/*
* $Id$
*
* Copyright (c) 2000-2007 by Rodney Kinney
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License (LGPL) as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, copies are available
* at http://www.opensource.org.
*/
package VASSAL.build.module;
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import org.jdesktop.swingworker.SwingWorker;
import org.netbeans.api.wizard.WizardDisplayer;
import org.netbeans.spi.wizard.Wizard;
import org.netbeans.spi.wizard.WizardBranchController;
import org.netbeans.spi.wizard.WizardController;
import org.netbeans.spi.wizard.WizardException;
import org.netbeans.spi.wizard.WizardPage;
import org.netbeans.spi.wizard.WizardPage.WizardResultProducer;
import org.netbeans.spi.wizard.WizardPanelProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import VASSAL.build.GameModule;
import VASSAL.build.module.documentation.Tutorial;
import VASSAL.chat.ui.ChatServerControls;
import VASSAL.command.Command;
import VASSAL.command.CommandFilter;
import VASSAL.command.NullCommand;
import VASSAL.configure.BooleanConfigurer;
import VASSAL.configure.FileConfigurer;
import VASSAL.configure.PasswordConfigurer;
import VASSAL.configure.ShowHelpAction;
import VASSAL.configure.StringConfigurer;
import VASSAL.i18n.Resources;
import VASSAL.launch.BasicModule;
import VASSAL.preferences.Prefs;
import VASSAL.tools.ErrorDialog;
import VASSAL.tools.SplashScreen;
import VASSAL.tools.UsernameAndPasswordDialog;
import VASSAL.tools.image.ImageUtils;
/**
* Provides support for two different wizards. The WelcomeWizard is the initial screen shown to the user when loading a
* module in play mode. The GameSetupWizard is shown whenever the user starts a new game on- or off-line.
*
* @author rkinney
*/
public class WizardSupport {
private static final Logger logger =
LoggerFactory.getLogger(WizardSupport.class);
public static final String POST_INITIAL_STEPS_WIZARD = "postInitialStepsWizard"; //$NON-NLS-1$
public static final String POST_LOAD_GAME_WIZARD = "postLoadGameWizard"; //$NON-NLS-1$
public static final String POST_PLAY_OFFLINE_WIZARD = "postPlayOfflineWizard"; //$NON-NLS-1$
public static final String WELCOME_WIZARD_KEY = "welcomeWizard"; //$NON-NLS-1$
public static final String SETUP_KEY = "setup"; //$NON-NLS-1$
public static final String ACTION_KEY = "action"; //$NON-NLS-1$
public static final String LOAD_TUTORIAL_ACTION = "tutorial"; //$NON-NLS-1$
public static final String PLAY_ONLINE_ACTION = "online"; //$NON-NLS-1$
public static final String PLAY_OFFLINE_ACTION = "offline"; //$NON-NLS-1$
public static final String LOAD_GAME_ACTION = "loadGame"; //$NON-NLS-1$
public static final String WELCOME_WIZARD_ENABLED = "showWelcomeWizard"; //$NON-NLS-1$
protected Dimension logoSize = new Dimension(200, 200);
protected List<PredefinedSetup> setups = new ArrayList<PredefinedSetup>();
protected Tutorial tutorial;
public WizardSupport() {
}
/**
* Add a {@link PredefinedSetup} to the wizard page for starting a new game offline
*
* @param setup
*/
public void addPredefinedSetup(PredefinedSetup setup) {
setups.add(setup);
}
public void removePredefinedSetup(PredefinedSetup setup) {
setups.remove(setup);
}
/**
* Specify a {@link Tutorial} that the user may load from the {@link InitialWelcomeSteps}
*
* @param tutorial
*/
public void setTutorial(Tutorial tutorial) {
this.tutorial = tutorial;
}
/**
* Show the "Welcome" wizard, shown when loading a module in play mode
*
*/
public void showWelcomeWizard() {
final GameModule g = GameModule.getGameModule();
final Boolean showWizard = (Boolean) Prefs.getGlobalPrefs().getValue(WELCOME_WIZARD_KEY);
if (! Boolean.TRUE.equals(showWizard)) {
g.getFrame().setVisible(true);
// prompt for username and password if wizard is off
// but no username is set
// FIXME: this belongs outside of the wizard, not here
final String name = (String) g.getPrefs().getValue(GameModule.REAL_NAME);
if (name == null || name.equals("newbie")) {
new UsernameAndPasswordDialog(g.getFrame()).setVisible(true);
}
return;
}
final WizardBranchController c = createWelcomeWizard();
final Wizard welcomeWizard = c.createWizard();
final HashMap<String, Wizard> props = new HashMap<String, Wizard>();
props.put(WELCOME_WIZARD_KEY, welcomeWizard);
Action help = null;
try {
help = new ShowHelpAction(new URL("http://www.vassalengine.org/wiki/doku.php?id=getting_started:getting_started"), null);
}
catch (MalformedURLException e) {
ErrorDialog.bug(e);
}
final Object result =
WizardDisplayer.showWizard(welcomeWizard, null, help, props);
if (result instanceof Map) {
final Map m = (Map) result;
final Object action = m.get(ACTION_KEY);
if (PLAY_ONLINE_ACTION.equals(action)) {
final ChatServerControls controls =
((BasicModule) g).getServerControls();
g.getFrame().setVisible(true);
controls.toggleVisible();
new SwingWorker<Void,Void>() {
@Override
protected Void doInBackground() {
controls.getClient().setConnected(true);
return null;
}
}.execute();
}
else {
g.getGameState().setup(true);
g.getFrame().setVisible(true);
}
}
else {
g.getFrame().setVisible(true);
}
}
protected BranchingWizard createWelcomeWizard() {
InitialWelcomeSteps info = createInitialWelcomeSteps();
info.setTutorial(tutorial);
return new BranchingWizard(info, POST_INITIAL_STEPS_WIZARD);
}
public WizardPanelProvider createPlayOfflinePanels() {
ArrayList<PredefinedSetup> l = new ArrayList<PredefinedSetup>();
for (PredefinedSetup ps : setups) {
if (!ps.isMenu())
l.add(ps);
}
if (l.isEmpty()) {
return GameSetupPanels.newInstance();
}
else {
return new PlayOfflinePanels(
Resources.getString("WizardSupport.WizardSupport.PlayOffline"), Resources.getString("WizardSupport.WizardSupport.SelectSetup"), l); //$NON-NLS-1$ //$NON-NLS-2$
}
}
/**
* Show a wizard that prompts the user to specify information for unfinished {@link GameSetupStep}s
*/
public void showGameSetupWizard() {
GameSetupPanels panels = GameSetupPanels.newInstance();
if (panels != null) {
WizardDisplayer.showWizard(panels.newWizard(logoSize), new Rectangle(0, 0, logoSize.width + 400, logoSize.height));
}
}
public InitialWelcomeSteps createInitialWelcomeSteps() {
Object realName = GameModule.getGameModule().getPrefs().getValue(GameModule.REAL_NAME);
if (realName == null || realName.equals(Resources.getString("Prefs.newbie"))) {
return new InitialWelcomeSteps(new String[]{InitialWelcomeSteps.NAME_STEP, ACTION_KEY},
new String[]{Resources.getString("WizardSupport.WizardSupport.EnterName"), Resources.getString("WizardSupport.WizardSupport.SelectPlayMode")}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
else {
return new InitialWelcomeSteps(new String[]{ACTION_KEY}, new String[]{Resources.getString("WizardSupport.SelectPlayMode")}); //$NON-NLS-1$
}
}
/**
* Wizard pages for the welcome wizard (initial module load). Prompts for username/password if not yet specified, and
* prompts to load a saved game or start a new one
*
* @author rkinney
*
*/
public class InitialWelcomeSteps extends WizardPanelProvider {
public static final String NAME_STEP = "name"; //$NON-NLS-1$
protected JComponent nameControls;
protected JComponent actionControls;
protected Tutorial tutorial;
public InitialWelcomeSteps(String[] steps, String[] stepDescriptions) {
super(Resources.getString("WizardSupport.Welcome"), steps, stepDescriptions); //$NON-NLS-1$
}
protected JComponent createPanel(WizardController controller, String id, Map settings) {
JComponent c = null;
if (NAME_STEP.equals(id)) {
c = getNameControls(controller, settings);
}
else if (ACTION_KEY.equals(id)) {
c = getActionControls(controller, settings);
}
else {
throw new IllegalArgumentException("Illegal step: " + id); //$NON-NLS-1$
}
SplashScreen.disposeAll();
return c;
}
@SuppressWarnings("unchecked")
private JComponent getActionControls(WizardController controller, final Map settings) {
if (actionControls == null) {
Box box = Box.createVerticalBox();
ButtonGroup group = new ButtonGroup();
JRadioButton tutorialButton = null;
if (tutorial != null && tutorial.isFirstRun()) {
tutorialButton = createTutorialButton(controller, settings);
addButton(tutorialButton, group, box);
box.add(Box.createVerticalStrut(20));
}
final JRadioButton b = createPlayOfflineButton(controller, settings);
b.doClick();
addButton(b, group, box);
settings.put(ACTION_KEY, PLAY_OFFLINE_ACTION);
addButton(createPlayOnlineButton(controller, settings), group, box);
addButton(createLoadSavedGameButton(controller, settings), group, box);
if (tutorialButton != null) {
// Select tutorial button by default, but not until wizard is built. Bug #2286742
final JRadioButton clickOnMe = tutorialButton;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
clickOnMe.doClick();
}
});
tutorialButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.DESELECTED) {
tutorial.markAsViewed();
}
}
});
}
else if (tutorial != null) {
addButton(createTutorialButton(controller, settings), group, box);
}
actionControls = box;
box.add(Box.createVerticalGlue());
final BooleanConfigurer wizardConf = (BooleanConfigurer)
Prefs.getGlobalPrefs().getOption(WELCOME_WIZARD_KEY);
final JCheckBox show = new JCheckBox(wizardConf.getName());
show.setSelected(wizardConf.booleanValue());
show.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
wizardConf.setValue(Boolean.valueOf(show.isSelected()));
}
});
box.add(show);
}
return actionControls;
}
private JRadioButton createTutorialButton(final WizardController controller, final Map settings) {
JRadioButton b = new JRadioButton(Resources.getString("WizardSupport.LoadTutorial")); //$NON-NLS-1$
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
controller.setProblem(Resources.getString("WizardSupport.LoadingTutorial")); //$NON-NLS-1$
try {
new TutorialLoader(controller, settings, new BufferedInputStream(tutorial.getTutorialContents()), POST_INITIAL_STEPS_WIZARD, tutorial).start();
}
catch (IOException e1) {
logger.error("", e1);
controller.setProblem(Resources.getString("WizardSupport.ErrorLoadingTutorial")); //$NON-NLS-1$
}
}
});
return b;
}
private JRadioButton createLoadSavedGameButton(final WizardController controller, final Map settings) {
JRadioButton b = new JRadioButton(Resources.getString("WizardSupport.LoadSavedGame")); //$NON-NLS-1$
b.addActionListener(new ActionListener() {
@SuppressWarnings("unchecked")
public void actionPerformed(ActionEvent e) {
settings.put(WizardSupport.ACTION_KEY, LOAD_GAME_ACTION);
Wizard wiz = new BranchingWizard(new LoadSavedGamePanels(), POST_LOAD_GAME_WIZARD).createWizard();
settings.put(POST_INITIAL_STEPS_WIZARD, wiz);
controller.setForwardNavigationMode(WizardController.MODE_CAN_CONTINUE);
controller.setProblem(null);
}
});
return b;
}
private JRadioButton createPlayOnlineButton(final WizardController controller, final Map settings) {
JRadioButton b = new JRadioButton(Resources.getString("WizardSupport.PlayOnline")); //$NON-NLS-1$
b.addActionListener(new ActionListener() {
@SuppressWarnings("unchecked")
public void actionPerformed(ActionEvent e) {
settings.put(WizardSupport.ACTION_KEY, PLAY_ONLINE_ACTION);
controller.setForwardNavigationMode(WizardController.MODE_CAN_FINISH);
controller.setProblem(null);
}
});
return b;
}
private JRadioButton createPlayOfflineButton(final WizardController controller, final Map settings) {
JRadioButton b = new JRadioButton(Resources.getString("WizardSupport.PlayOffline")); //$NON-NLS-1$
b.addActionListener(new ActionListener() {
@SuppressWarnings("unchecked")
public void actionPerformed(ActionEvent e) {
GameModule.getGameModule().getGameState().setup(false);
settings.put(WizardSupport.ACTION_KEY, PLAY_OFFLINE_ACTION);
final WizardPanelProvider panels = createPlayOfflinePanels();
if (panels == null) {
controller.setForwardNavigationMode(WizardController.MODE_CAN_FINISH);
}
else {
Wizard wiz = new BranchingWizard(panels, POST_PLAY_OFFLINE_WIZARD).createWizard();
settings.put(POST_INITIAL_STEPS_WIZARD, wiz);
controller.setForwardNavigationMode(WizardController.MODE_CAN_CONTINUE);
}
}
});
return b;
}
private void addButton(JRadioButton button, ButtonGroup group, Box box) {
box.add(button);
group.add(button);
}
protected JComponent getNameControls(final WizardController controller, final Map settings) {
if (nameControls == null) {
Box box = Box.createVerticalBox();
box.add(Box.createVerticalGlue());
controller.setProblem(Resources.getString("WizardSupport.EnterNameAndPassword")); //$NON-NLS-1$
final StringConfigurer nameConfig = new StringConfigurer(null, Resources.getString("WizardSupport.RealName")); //$NON-NLS-1$
final StringConfigurer pwd = new PasswordConfigurer(null, Resources.getString("WizardSupport.Password")); //$NON-NLS-1$
final StringConfigurer pwd2 = new PasswordConfigurer(null, Resources.getString("WizardSupport.ConfirmPassword")); //$NON-NLS-1$
PropertyChangeListener pl = new PropertyChangeListener() {
@SuppressWarnings("unchecked")
public void propertyChange(PropertyChangeEvent evt) {
settings.put(GameModule.REAL_NAME, nameConfig.getValue());
settings.put(GameModule.SECRET_NAME, pwd.getValue());
if (nameConfig.getValue() == null || "".equals(nameConfig.getValue())) { //$NON-NLS-1$
controller.setProblem(Resources.getString("WizardSupport.EnterYourName")); //$NON-NLS-1$
}
else if (pwd.getValue() == null || "".equals(pwd.getValue())) { //$NON-NLS-1$
controller.setProblem(Resources.getString("WizardSupport.EnterYourPassword")); //$NON-NLS-1$
}
else if (!pwd.getValue().equals(pwd2.getValue())) {
controller.setProblem(Resources.getString("WizardSupport.PasswordsDontMatch")); //$NON-NLS-1$
}
else {
final Prefs p = GameModule.getGameModule().getPrefs();
p.getOption(GameModule.REAL_NAME)
.setValue(nameConfig.getValueString());
p.getOption(GameModule.SECRET_NAME)
.setValue(pwd.getValueString());
try {
p.save();
controller.setProblem(null);
}
// FIXME: review error message
catch (IOException e) {
String msg = e.getMessage();
if (msg == null) {
msg = Resources.getString("Prefs.unable_to_save");
}
controller.setProblem(msg);
}
}
}
};
nameConfig.addPropertyChangeListener(pl);
pwd.addPropertyChangeListener(pl);
pwd2.addPropertyChangeListener(pl);
box.add(nameConfig.getControls());
box.add(pwd.getControls());
box.add(pwd2.getControls());
JLabel l = new JLabel(Resources.getString("WizardSupport.NameAndPasswordDetails"));
l.setAlignmentX(Box.CENTER_ALIGNMENT);
box.add(l);
box.add(Box.createVerticalGlue());
nameControls = box;
}
return nameControls;
}
public void setTutorial(Tutorial tutorial) {
this.tutorial = tutorial;
}
}
/**
* Wizard pages for starting a new game offline
*
* @author rkinney
*
*/
public static class PlayOfflinePanels extends WizardPanelProvider {
private List setups;
private String description;
protected PlayOfflinePanels(String title, String singleDescription, List setups) {
super(title, SETUP_KEY, singleDescription);
this.setups = setups;
this.description = singleDescription;
}
protected JComponent createPanel(final WizardController controller, String id, final Map settings) {
final JComboBox setupSelection = new JComboBox(setups.toArray());
((DefaultComboBoxModel) setupSelection.getModel()).insertElementAt(description, 0);
setupSelection.setSelectedIndex(0);
setupSelection.addActionListener(new ActionListener() {
@SuppressWarnings("unchecked")
public void actionPerformed(ActionEvent e) {
if (setupSelection.getSelectedItem() instanceof PredefinedSetup) {
PredefinedSetup setup = (PredefinedSetup) setupSelection.getSelectedItem();
if (setup.isUseFile() && setup.getFileName() != null) {
loadSetup(setup, controller, settings);
}
else {
final GameSetupPanels panels = GameSetupPanels.newInstance();
settings.put(POST_PLAY_OFFLINE_WIZARD, panels);
controller.setProblem(null);
controller.setForwardNavigationMode(panels == null ? WizardController.MODE_CAN_FINISH : WizardController.MODE_CAN_CONTINUE);
}
}
else {
controller.setProblem(description);
}
}
});
setupSelection.setMaximumSize(new Dimension(setupSelection.getMaximumSize().width, setupSelection.getPreferredSize().height));
setupSelection.setRenderer(new DefaultListCellRenderer() {
private static final long serialVersionUID = 1L;
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JLabel c = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof PredefinedSetup) {
PredefinedSetup pds = (PredefinedSetup) value;
c.setText((pds).getConfigureName());
if (pds.isMenu()) {
c.setSize(0, 0);
}
}
else {
c.setText(value == null ? "" : value.toString());
}
return c;
}
});
Box box = Box.createVerticalBox();
box.add(Box.createVerticalGlue());
box.add(setupSelection);
box.add(Box.createVerticalGlue());
controller.setProblem(description);
return box;
}
protected void loadSetup(PredefinedSetup setup, final WizardController controller, final Map settings) {
try {
new SavedGameLoader(controller, settings, new BufferedInputStream(setup.getSavedGameContents()), POST_PLAY_OFFLINE_WIZARD).start();
}
// FIXME: review error message
catch (IOException e1) {
controller.setProblem(Resources.getString("WizardSupport.UnableToLoad"));
}
}
}
/**
* Branches the wizard by forwarding to the Wizard stored in the wizard settings under a specified key
*/
public static class BranchingWizard extends WizardBranchController {
private String wizardKey;
public BranchingWizard(WizardPanelProvider base, String key) {
super(base);
this.wizardKey = key;
}
protected WizardPanelProvider getPanelProviderForStep(String step, Map settings) {
return (WizardPanelProvider) settings.get(wizardKey);
}
protected Wizard getWizardForStep(String step, Map settings) {
Wizard w = null;
Object next = settings.get(wizardKey);
if (next instanceof Wizard) {
w = (Wizard) next;
}
else {
w = super.getWizardForStep(step, settings);
}
return w;
}
}
/**
* Loads a saved game in the background. Add a branch to the wizard if the loaded game has unfinished
* {@link GameSetupStep}s. Otherwise, enable the finish button.
*
* @author rkinney
*
*/
public static class SavedGameLoader extends Thread {
private WizardController controller;
private Map settings;
// FIXME: this is a bad design---when can we safely close this stream?!
private InputStream in;
private String wizardKey;
public SavedGameLoader(WizardController controller, Map settings, InputStream in, String wizardKey) {
super();
this.controller = controller;
this.settings = settings;
this.in = in;
this.wizardKey = wizardKey;
}
@SuppressWarnings("unchecked")
public void run() {
try {
controller.setProblem(Resources.getString("WizardSupport.LoadingGame")); //$NON-NLS-1$
Command setupCommand = loadSavedGame();
setupCommand.execute();
controller.setProblem(null);
final GameSetupPanels panels = GameSetupPanels.newInstance();
settings.put(wizardKey, panels);
controller.setForwardNavigationMode(panels == null ? WizardController.MODE_CAN_FINISH : WizardController.MODE_CAN_CONTINUE);
}
// FIXME: review error message
catch (IOException e) {
controller.setProblem(Resources.getString("WizardSupport.UnableToLoad")); //$NON-NLS-1$
}
}
protected Command loadSavedGame() throws IOException {
Command setupCommand =
GameModule.getGameModule().getGameState().decodeSavedGame(in);
if (setupCommand == null) {
throw new IOException(Resources.getString("WizardSupport.InvalidSavefile")); //$NON-NLS-1$
}
// Strip out the setup(true) command. This will be applied when the "Finish" button is pressed
setupCommand = new CommandFilter() {
protected boolean accept(Command c) {
return !(c instanceof GameState.SetupCommand) ||
!((GameState.SetupCommand) c).isGameStarting();
}
}.apply(setupCommand);
return setupCommand;
}
}
public static class TutorialLoader extends SavedGameLoader {
private Tutorial tutorial;
public TutorialLoader(WizardController controller, Map settings, InputStream in, String wizardKey, Tutorial tutorial) {
super(controller, settings, in, wizardKey);
this.tutorial = tutorial;
}
protected Command loadSavedGame() throws IOException {
String msg = tutorial.getWelcomeMessage();
Command c = msg == null ? new NullCommand() : new Chatter.DisplayText(GameModule.getGameModule().getChatter(), msg);
c = c.append(super.loadSavedGame());
return c;
}
}
/**
* Wizard pages for loading a saved game
*
* @author rkinney
*
*/
public static class LoadSavedGamePanels extends WizardPanelProvider {
private FileConfigurer fileConfig;
public LoadSavedGamePanels() {
super(Resources.getString("WizardSupport.LoadGame"), LOAD_GAME_ACTION, Resources.getString("WizardSupport.LoadSavedGame")); //$NON-NLS-1$ //$NON-NLS-2$
}
protected JComponent createPanel(final WizardController controller, String id, final Map settings) {
if (fileConfig == null) {
fileConfig = new FileConfigurer(null,
Resources.getString("WizardSupport.SavedGame"), GameModule.getGameModule().getGameState().getSavedGameDirectoryPreference()); //$NON-NLS-1$
fileConfig.addPropertyChangeListener(new PropertyChangeListener() {
private Set<File> processing = new HashSet<File>();
public void propertyChange(PropertyChangeEvent evt) {
final File f = (File) evt.getNewValue();
if (f == null || !f.exists()) {
controller.setProblem(Resources.getString("WizardSupport.NoSuchFile")); //$NON-NLS-1$
}
else if (f.isDirectory()) {
controller.setProblem(""); //$NON-NLS-1$
}
else if (!processing.contains(f)) { // Sometimes the FileConfigurer fires more than one event for the same
// file
processing.add(f);
try {
new SavedGameLoader(controller, settings, new BufferedInputStream(new FileInputStream(f)), POST_LOAD_GAME_WIZARD) {
public void run() {
super.run();
processing.remove(f);
}
}.start();
}
// FIXME: review error message
catch (IOException e) {
controller.setProblem(Resources.getString("WizardSupport.UnableToLoad")); //$NON-NLS-1$
}
}
}
});
controller.setProblem(Resources.getString("WizardSupport.SelectSavedGame")); //$NON-NLS-1$
}
return (JComponent) fileConfig.getControls();
}
}
/**
* Wizard page for an unfinished {@link GameSetupStep}
*
* @author rkinney
*
*/
public static class SetupStepPage extends WizardPage {
private static final long serialVersionUID = 1L;
public SetupStepPage(GameSetupStep step) {
super(step.getStepTitle());
setLayout(new BorderLayout());
add(step.getControls());
putWizardData(step, step);
}
}
public void setBackgroundImage(Image image) {
if (image != null) {
final ImageIcon icon = new ImageIcon(image);
logoSize = new Dimension(icon.getIconWidth(), icon.getIconHeight());
final BufferedImage img =
ImageUtils.createCompatibleTranslucentImage(logoSize.width,
logoSize.height);
Graphics2D g = img.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, icon.getIconWidth(), icon.getIconHeight());
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5F));
icon.paintIcon(null, g, 0, 0);
g.dispose();
UIManager.put("wizard.sidebar.image", img); //$NON-NLS-1$
}
}
/**
* Wizard pages for starting a new game. One page will be added for each unfinished {@link GameSetupStep}
*
* @see GameState#getUnfinishedSetupSteps()
* @author rkinney
*/
public static class GameSetupPanels extends WizardPanelProvider implements WizardResultProducer {
private WizardPage[] pages;
private List<GameSetupStep> setupSteps;
private GameSetupPanels(String[] steps, String[] descriptions, WizardPage[] pages, List<GameSetupStep> setupSteps) {
super(steps, descriptions);
this.pages = pages;
this.setupSteps = setupSteps;
}
public static GameSetupPanels newInstance() {
GameSetupPanels panels = null;
final ArrayList<SetupStepPage> pages = new ArrayList<SetupStepPage>();
final ArrayList<GameSetupStep> setupSteps = new ArrayList<GameSetupStep>();
for (Iterator<GameSetupStep> i = GameModule.getGameModule().getGameState().getUnfinishedSetupSteps(); i.hasNext();) {
final GameSetupStep step = i.next();
setupSteps.add(step);
final SetupStepPage page = new SetupStepPage(step);
pages.add(page);
}
if (!pages.isEmpty()) {
WizardPage[] wizardPages = pages.toArray(new WizardPage[pages.size()]);
String[] steps = new String[setupSteps.size()];
String[] desc = new String[setupSteps.size()];
for (int i = 0, n = setupSteps.size(); i < n; i++) {
steps[i] = String.valueOf(i);
desc[i] = setupSteps.get(i).getStepTitle();
}
panels = new GameSetupPanels(steps, desc, wizardPages, setupSteps);
}
return panels;
}
protected JComponent createPanel(WizardController controller, String id, Map settings) {
int index = indexOfStep(id);
controller.setForwardNavigationMode(index == pages.length - 1 ? WizardController.MODE_CAN_FINISH : WizardController.MODE_CAN_CONTINUE);
return pages[index];
}
public boolean cancel(Map settings) {
GameModule.getGameModule().getGameState().setup(false);
return true;
}
public Object finish(Map wizardData) throws WizardException {
for (GameSetupStep step : setupSteps) {
step.finish();
}
return wizardData;
}
public Wizard newWizard(Dimension logoSize) {
return createWizard();
}
}
}