/*******************************************************************************
* Copyright (c) 2001, 2010 Mathew A. Nelson and Robocode contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://robocode.sourceforge.net/license/epl-v10.html
*
* Contributors:
* Mathew A. Nelson
* - Initial API and implementation
* Matthew Reeder
* - Added keyboard mnemonics to buttons and tabs
* Flemming N. Larsen
* - Code cleanup
* - Replaced FileSpecificationVector with plain Vector
* - Changed the F5 key press for refreshing the list of available robots
* into 'modifier key' + R to comply with other OSes like e.g. Mac OS
* Robert D. Maupin
* - Replaced old collection types like Vector and Hashtable with
* synchronized List and HashMap
*******************************************************************************/
package net.sf.robocode.ui.dialog;
import net.sf.robocode.battle.BattleProperties;
import net.sf.robocode.battle.IBattleManager;
import net.sf.robocode.repository.IRepositoryItem;
import net.sf.robocode.settings.ISettingsManager;
import net.sf.robocode.ui.IWindowManager;
import static net.sf.robocode.ui.util.ShortcutUtil.MENU_SHORTCUT_KEY_MASK;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.util.List;
/**
* @author Mathew A. Nelson (original)
* @author Matthew Reeder (contributor)
* @author Flemming N. Larsen (contributor)
* @author Robert D. Maupin (contributor)
*/
@SuppressWarnings("serial")
public class NewBattleDialog extends JDialog implements WizardListener {
private final static int MAX_ROBOTS = 256; // 64;
private final static int MIN_ROBOTS = 1;
private final EventHandler eventHandler = new EventHandler();
private JPanel newBattleDialogContentPane;
private WizardTabbedPane tabbedPane;
private NewBattleBattleFieldTab battleFieldTab;
private BattleProperties battleProperties;
private boolean isOpeningBattle;
private NewBattleRulesTab rulesTab;
private WizardController wizardController;
private RobotSelectionPanel robotSelectionPanel;
private final IBattleManager battleManager;
private final ISettingsManager settingsManager;
public NewBattleDialog(IWindowManager windowManager, IBattleManager battleManager, ISettingsManager settingsManager) {
super(windowManager.getRobocodeFrame(), true);
this.battleManager = battleManager;
this.settingsManager = settingsManager;
}
public void setup(BattleProperties battleProperties, boolean openBattle) {
this.battleProperties = battleProperties;
this.isOpeningBattle = openBattle;
robotSelectionPanel = null;
initialize();
}
public void cancelButtonActionPerformed() {
dispose();
}
public void finishButtonActionPerformed() {
if (robotSelectionPanel.getSelectedRobotsCount() > 24) {
if (JOptionPane.showConfirmDialog(this,
"Warning: The battle you are about to start (" + robotSelectionPanel.getSelectedRobotsCount()
+ " robots) " + " is very large and will consume a lot of CPU and memory. Do you wish to proceed?",
"Large Battle Warning",
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE)
== JOptionPane.NO_OPTION) {
return;
}
}
if (robotSelectionPanel.getSelectedRobotsCount() == 1) {
if (JOptionPane.showConfirmDialog(this,
"You have only selected one robot. For normal battles you should select at least 2.\nDo you wish to proceed anyway?",
"Just one robot?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE)
== JOptionPane.NO_OPTION) {
return;
}
}
battleProperties.setSelectedRobots(getRobotSelectionPanel().getSelectedRobotsAsString());
battleProperties.setBattlefieldWidth(getBattleFieldTab().getBattleFieldWidth());
battleProperties.setBattlefieldHeight(getBattleFieldTab().getBattleFieldHeight());
battleProperties.setNumRounds(getRobotSelectionPanel().getNumRounds());
battleProperties.setGunCoolingRate(getRulesTab().getGunCoolingRate());
battleProperties.setInactivityTime(getRulesTab().getInactivityTime());
battleProperties.setHideEnemyNames(getRulesTab().getHideEnemyNames());
// Dispose this dialog before starting the battle due to pause/resume battle state
dispose();
// Start new battle after the dialog has been disposed and hence has called resumeBattle()
battleManager.startNewBattle(battleProperties, false, false);
}
/**
* Return the battleFieldTab
*
* @return JPanel
*/
private NewBattleBattleFieldTab getBattleFieldTab() {
if (battleFieldTab == null) {
battleFieldTab = new NewBattleBattleFieldTab();
}
return battleFieldTab;
}
/**
* Return the newBattleDialogContentPane
*
* @return JPanel
*/
private JPanel getNewBattleDialogContentPane() {
if (newBattleDialogContentPane == null) {
newBattleDialogContentPane = new JPanel();
newBattleDialogContentPane.setLayout(new BorderLayout());
newBattleDialogContentPane.add(getWizardController(), BorderLayout.SOUTH);
newBattleDialogContentPane.add(getTabbedPane(), BorderLayout.CENTER);
newBattleDialogContentPane.registerKeyboardAction(eventHandler, "Refresh",
KeyStroke.getKeyStroke(KeyEvent.VK_R, MENU_SHORTCUT_KEY_MASK),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
}
return newBattleDialogContentPane;
}
/**
* Return the rulesTab property value.
*
* @return robocode.dialog.NewBattleRulesTab
*/
private NewBattleRulesTab getRulesTab() {
if (rulesTab == null) {
rulesTab = new net.sf.robocode.ui.dialog.NewBattleRulesTab();
}
return rulesTab;
}
public List<IRepositoryItem> getSelectedRobots() {
return getRobotSelectionPanel().getSelectedRobots();
}
/**
* Initialize the class.
*/
private void initialize() {
setTitle("New Battle");
setPreferredSize(new Dimension(850, 650));
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setContentPane(getNewBattleDialogContentPane());
addCancelByEscapeKey();
processBattleProperties();
}
private void addCancelByEscapeKey() {
String CANCEL_ACTION_KEY = "CANCEL_ACTION_KEY";
int noModifiers = 0;
KeyStroke escapeKey = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, noModifiers, false);
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
inputMap.put(escapeKey, CANCEL_ACTION_KEY);
AbstractAction cancelAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
cancelButtonActionPerformed();
}
};
getRootPane().getActionMap().put(CANCEL_ACTION_KEY, cancelAction);
}
/**
* Return the wizardController
*
* @return JButton
*/
private WizardController getWizardController() {
if (wizardController == null) {
wizardController = getTabbedPane().getWizardController();
wizardController.setFinishButtonTextAndMnemonic("Start Battle", 'S', 0);
wizardController.setFocusOnEnabled(true);
}
return wizardController;
}
/**
* Return the Page property value.
*
* @return JPanel
*/
private RobotSelectionPanel getRobotSelectionPanel() {
if (robotSelectionPanel == null) {
String selectedRobots = "";
if (battleProperties != null) {
selectedRobots = battleProperties.getSelectedRobots();
}
robotSelectionPanel = net.sf.robocode.core.Container.createComponent(RobotSelectionPanel.class);
final boolean ignoreTeamRobots = false; // TODO do we really want to have this !properties.getOptionsTeamShowTeamRobots();
robotSelectionPanel.setup(MIN_ROBOTS, MAX_ROBOTS, true, "Select robots for the battle", false, false, false,
false, false, ignoreTeamRobots, selectedRobots);
}
return robotSelectionPanel;
}
/**
* Return the tabbedPane.
*
* @return JTabbedPane
*/
private WizardTabbedPane getTabbedPane() {
if (tabbedPane == null) {
tabbedPane = new WizardTabbedPane(this);
tabbedPane.insertTab("Robots", null, getRobotSelectionPanel(), null, 0);
tabbedPane.setMnemonicAt(0, KeyEvent.VK_R);
tabbedPane.setDisplayedMnemonicIndexAt(0, 0);
tabbedPane.insertTab("BattleField", null, getBattleFieldTab(), null, 1);
tabbedPane.setMnemonicAt(1, KeyEvent.VK_F);
tabbedPane.setDisplayedMnemonicIndexAt(1, 6);
tabbedPane.insertTab("Rules", null, getRulesTab(), null, 2);
tabbedPane.setMnemonicAt(2, KeyEvent.VK_U);
tabbedPane.setDisplayedMnemonicIndexAt(2, 1);
}
return tabbedPane;
}
private void processBattleProperties() {
if (battleProperties == null) {
return;
}
getBattleFieldTab().setBattleFieldWidth(battleProperties.getBattlefieldWidth());
getBattleFieldTab().setBattleFieldHeight(battleProperties.getBattlefieldHeight());
getRulesTab().setGunCoolingRate(battleProperties.getGunCoolingRate());
getRulesTab().setInactivityTime(battleProperties.getInactivityTime());
getRulesTab().setHideEnemyNames(battleProperties.getHideEnemyNames());
// When opening a battle, we use the 'number of rounds' from the battle properties.
// When starting a new battle, we use the 'number of rounds' from the settings manager instead.
int numRounds = isOpeningBattle ? battleProperties.getNumRounds() : settingsManager.getNumberOfRounds();
getRobotSelectionPanel().setNumRounds(numRounds);
}
private class EventHandler extends WindowAdapter implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Refresh")) {
getRobotSelectionPanel().refreshRobotList(true);
}
}
}
}