/******************************************************************************* * 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 * Flemming N. Larsen * - Replaced FileSpecificationVector with plain Vector * - Ported to Java 5 * - Code cleanup * - Updated to use methods from the Logger, which replaces logger methods * that have been (re)moved from the robocode.util.Utils class * - Bugfixed buildRobotList(), which checked if selectedRobots was set * instead of preSelectedRobots. Robots were not selected when loading a * battle * - Replaced synchronizedList on list for selectedRobots with a * CopyOnWriteArrayList in order to prevent ConcurrentModificationException * when accessing this list via Iterators using public methods to this * class * 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.core.Container; import net.sf.robocode.repository.IRepositoryItem; import net.sf.robocode.repository.IRepositoryManager; import net.sf.robocode.settings.ISettingsManager; import net.sf.robocode.ui.IWindowManager; import javax.swing.*; import javax.swing.border.TitledBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.*; import java.awt.event.*; import java.util.List; import java.util.ArrayList; /** * @author Mathew A. Nelson (original) * @author Matthew Reeder (contributor) * @author Flemming N. Larsen (contributor) * @author Robert D. Maupin (contributor) */ @SuppressWarnings("serial") public class RobotSelectionPanel extends WizardPanel { private AvailableRobotsPanel availableRobotsPanel; private JPanel selectedRobotsPanel; private JScrollPane selectedRobotsScrollPane; private JList selectedRobotsList; private JPanel buttonsPanel; private JPanel addButtonsPanel; private JPanel removeButtonsPanel; private JButton addButton; private JButton addAllButton; private JButton removeButton; private JButton removeAllButton; private final EventHandler eventHandler = new EventHandler(); private RobotDescriptionPanel descriptionPanel; private String instructions; private JLabel instructionsLabel; private JPanel mainPanel; private int maxRobots = 1; private int minRobots = 1; private JPanel numRoundsPanel; private JTextField numRoundsTextField; private boolean onlyShowSource; private boolean onlyShowWithPackage; private boolean onlyShowRobots; private boolean onlyShowDevelopment; private boolean onlyShowInJar; private boolean ignoreTeamRobots; private String preSelectedRobots; private final List<AvailableRobotsPanel.ItemWrapper> selectedRobots = new ArrayList<AvailableRobotsPanel.ItemWrapper>(); private boolean showNumRoundsPanel; private final ISettingsManager properties; private final IRepositoryManager repositoryManager; private boolean nummerOfRoundSetByGame; public RobotSelectionPanel(ISettingsManager properties, IRepositoryManager repositoryManager) { super(); this.properties = properties; this.repositoryManager = repositoryManager; } public void setup(int minRobots, int maxRobots, boolean showNumRoundsPanel, String instructions, boolean onlyShowSource, boolean onlyShowWithPackage, boolean onlyShowRobots, boolean onlyShowDevelopment, boolean onlyShowInJar, boolean ignoreTeamRobots, String preSelectedRobots) { this.showNumRoundsPanel = showNumRoundsPanel; this.minRobots = minRobots; this.maxRobots = maxRobots; this.instructions = instructions; this.onlyShowSource = onlyShowSource; this.onlyShowWithPackage = onlyShowWithPackage; this.onlyShowRobots = onlyShowRobots; this.onlyShowDevelopment = onlyShowDevelopment; this.onlyShowInJar = onlyShowInJar; this.ignoreTeamRobots = ignoreTeamRobots; this.preSelectedRobots = preSelectedRobots; initialize(); } private class EventHandler implements ActionListener, ListSelectionListener { public void actionPerformed(ActionEvent e) { if (e.getSource() == getAddAllButton()) { addAllButtonActionPerformed(); } else if (e.getSource() == getAddButton()) { addButtonActionPerformed(); } else if (e.getSource() == getRemoveAllButton()) { removeAllButtonActionPerformed(); } else if (e.getSource() == getRemoveButton()) { removeButtonActionPerformed(); } } public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } if (e.getSource() == getSelectedRobotsList()) { selectedRobotsListSelectionChanged(); } } } private void addAllButtonActionPerformed() { JList selectedList = getSelectedRobotsList(); SelectedRobotsModel selectedModel = (SelectedRobotsModel) selectedList.getModel(); for (AvailableRobotsPanel.ItemWrapper selected : availableRobotsPanel.getAvailableRobots()) { selectedRobots.add(selected); } selectedList.clearSelection(); selectedModel.changed(); fireStateChanged(); if (selectedModel.getSize() >= minRobots && selectedModel.getSize() <= maxRobots) { showInstructions(); } else if (selectedModel.getSize() > maxRobots) { showWrongNumInstructions(); } availableRobotsPanel.getAvailableRobotsList().requestFocus(); } private void addButtonActionPerformed() { SelectedRobotsModel selectedModel = (SelectedRobotsModel) getSelectedRobotsList().getModel(); List<AvailableRobotsPanel.ItemWrapper> moves = availableRobotsPanel.getSelectedRobots(); for (AvailableRobotsPanel.ItemWrapper move : moves) { selectedRobots.add(new AvailableRobotsPanel.ItemWrapper(move.getItem())); } selectedModel.changed(); fireStateChanged(); if (selectedModel.getSize() >= minRobots && selectedModel.getSize() <= maxRobots) { showInstructions(); } else if (selectedModel.getSize() > maxRobots) { showWrongNumInstructions(); } availableRobotsPanel.getAvailableRobotsList().requestFocus(); } private JButton getAddAllButton() { if (addAllButton == null) { addAllButton = new JButton(); addAllButton.setText("Add All ->"); addAllButton.setMnemonic('l'); addAllButton.setDisplayedMnemonicIndex(5); addAllButton.addActionListener(eventHandler); } return addAllButton; } private JButton getAddButton() { if (addButton == null) { addButton = new JButton(); addButton.setText("Add ->"); addButton.setMnemonic('A'); addButton.addActionListener(eventHandler); } return addButton; } private JPanel getAddButtonsPanel() { if (addButtonsPanel == null) { addButtonsPanel = new JPanel(); addButtonsPanel.setLayout(new GridLayout(2, 1)); addButtonsPanel.add(getAddButton()); addButtonsPanel.add(getAddAllButton()); } return addButtonsPanel; } private JPanel getButtonsPanel() { if (buttonsPanel == null) { buttonsPanel = new JPanel(); buttonsPanel.setLayout(new BorderLayout(5, 5)); buttonsPanel.setBorder(BorderFactory.createEmptyBorder(21, 5, 5, 5)); buttonsPanel.add(getAddButtonsPanel(), BorderLayout.NORTH); if (showNumRoundsPanel) { buttonsPanel.add(getNumRoundsPanel(), BorderLayout.CENTER); } buttonsPanel.add(getRemoveButtonsPanel(), BorderLayout.SOUTH); } return buttonsPanel; } private JButton getRemoveAllButton() { if (removeAllButton == null) { removeAllButton = new JButton(); removeAllButton.setText("<- Remove All"); removeAllButton.setMnemonic('v'); removeAllButton.setDisplayedMnemonicIndex(7); removeAllButton.addActionListener(eventHandler); } return removeAllButton; } private JButton getRemoveButton() { if (removeButton == null) { removeButton = new JButton(); removeButton.setText("<- Remove"); removeButton.setMnemonic('m'); removeButton.setDisplayedMnemonicIndex(5); removeButton.addActionListener(eventHandler); } return removeButton; } private JPanel getRemoveButtonsPanel() { if (removeButtonsPanel == null) { removeButtonsPanel = new JPanel(); removeButtonsPanel.setLayout(new GridLayout(2, 1)); removeButtonsPanel.add(getRemoveButton()); removeButtonsPanel.add(getRemoveAllButton()); } return removeButtonsPanel; } public String getSelectedRobotsAsString() { StringBuffer sb = new StringBuffer(); for (int i = 0; i < selectedRobots.size(); i++) { if (i != 0) { sb.append(','); } sb.append(selectedRobots.get(i).getItem().getUniqueFullClassNameWithVersion()); } return sb.toString(); } public List<IRepositoryItem> getSelectedRobots() { List<IRepositoryItem> res = new ArrayList<IRepositoryItem>(); for (AvailableRobotsPanel.ItemWrapper item : selectedRobots) { res.add(item.getItem()); } return res; } private JList getSelectedRobotsList() { if (selectedRobotsList == null) { selectedRobotsList = new JList(); selectedRobotsList.setModel(new SelectedRobotsModel()); selectedRobotsList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); MouseListener mouseListener = new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { removeButtonActionPerformed(); } if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { contextMenuActionPerformed(); } } }; selectedRobotsList.addMouseListener(mouseListener); selectedRobotsList.addListSelectionListener(eventHandler); } return selectedRobotsList; } private JPanel getSelectedRobotsPanel() { if (selectedRobotsPanel == null) { selectedRobotsPanel = new JPanel(); selectedRobotsPanel.setLayout(new BorderLayout()); selectedRobotsPanel.setPreferredSize(new Dimension(120, 100)); selectedRobotsPanel.setBorder( BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Selected Robots")); selectedRobotsPanel.add(getSelectedRobotsScrollPane(), BorderLayout.CENTER); } return selectedRobotsPanel; } private JScrollPane getSelectedRobotsScrollPane() { if (selectedRobotsScrollPane == null) { selectedRobotsScrollPane = new JScrollPane(); selectedRobotsScrollPane.setViewportView(getSelectedRobotsList()); } return selectedRobotsScrollPane; } private void initialize() { setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); setLayout(new BorderLayout()); add(getInstructionsLabel(), BorderLayout.NORTH); add(getMainPanel(), BorderLayout.CENTER); add(getDescriptionPanel(), BorderLayout.SOUTH); setVisible(true); showInstructions(); refreshRobotList(false); } private void removeAllButtonActionPerformed() { JList selectedList = getSelectedRobotsList(); SelectedRobotsModel selectedModel = (SelectedRobotsModel) selectedList.getModel(); selectedRobots.clear(); selectedList.clearSelection(); selectedModel.changed(); fireStateChanged(); showInstructions(); } private void contextMenuActionPerformed() {} private void removeButtonActionPerformed() { JList selectedList = getSelectedRobotsList(); SelectedRobotsModel selectedModel = (SelectedRobotsModel) selectedList.getModel(); int sel[] = selectedList.getSelectedIndices(); for (int i = 0; i < sel.length; i++) { selectedRobots.remove(sel[i] - i); } selectedList.clearSelection(); selectedModel.changed(); fireStateChanged(); if (selectedModel.getSize() < minRobots || selectedModel.getSize() > maxRobots) { showWrongNumInstructions(); } else { showInstructions(); } } class SelectedRobotsModel extends AbstractListModel { public void changed() { fireContentsChanged(this, 0, getSize()); } public int getSize() { return selectedRobots.size(); } public Object getElementAt(int which) { return selectedRobots.get(which); } } public AvailableRobotsPanel getAvailableRobotsPanel() { if (availableRobotsPanel == null) { availableRobotsPanel = new AvailableRobotsPanel(getAddButton(), "Available Robots", getSelectedRobotsList(), this); } return availableRobotsPanel; } private RobotDescriptionPanel getDescriptionPanel() { if (descriptionPanel == null) { descriptionPanel = new RobotDescriptionPanel(); descriptionPanel.setBorder(BorderFactory.createEmptyBorder(1, 10, 1, 10)); } return descriptionPanel; } private JLabel getInstructionsLabel() { if (instructionsLabel == null) { instructionsLabel = new JLabel(); if (instructions != null) { instructionsLabel.setText(instructions); } } return instructionsLabel; } private JPanel getMainPanel() { if (mainPanel == null) { mainPanel = new JPanel(); mainPanel.setPreferredSize(new Dimension(550, 300)); GridBagLayout layout = new GridBagLayout(); mainPanel.setLayout(layout); GridBagConstraints constraints = new GridBagConstraints(); constraints.fill = GridBagConstraints.BOTH; constraints.weightx = 2; constraints.weighty = 1; constraints.anchor = GridBagConstraints.NORTHWEST; constraints.gridwidth = 2; layout.setConstraints(getAvailableRobotsPanel(), constraints); mainPanel.add(getAvailableRobotsPanel()); constraints.gridwidth = 1; constraints.weightx = 0; constraints.weighty = 0; constraints.anchor = GridBagConstraints.CENTER; layout.setConstraints(getButtonsPanel(), constraints); mainPanel.add(getButtonsPanel()); constraints.gridwidth = GridBagConstraints.REMAINDER; constraints.weightx = 1; constraints.weighty = 1; constraints.anchor = GridBagConstraints.NORTHWEST; layout.setConstraints(getSelectedRobotsPanel(), constraints); mainPanel.add(getSelectedRobotsPanel()); } return mainPanel; } public int getNumRounds() { try { return Integer.parseInt(getNumRoundsTextField().getText()); } catch (NumberFormatException e) { int numRounds = properties.getNumberOfRounds(); getNumRoundsTextField().setText("" + numRounds); return numRounds; } } private JPanel getNumRoundsPanel() { if (numRoundsPanel == null) { numRoundsPanel = new JPanel(); numRoundsPanel.setLayout(new BoxLayout(numRoundsPanel, BoxLayout.Y_AXIS)); numRoundsPanel.setBorder(BorderFactory.createEmptyBorder()); numRoundsPanel.add(new JPanel()); JPanel j = new JPanel(); j.setLayout(new BoxLayout(j, BoxLayout.Y_AXIS)); TitledBorder border = BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Number of Rounds"); j.setBorder(border); j.add(getNumRoundsTextField()); j.setPreferredSize(new Dimension(border.getMinimumSize(j).width, j.getPreferredSize().height)); j.setMinimumSize(j.getPreferredSize()); j.setMaximumSize(j.getPreferredSize()); numRoundsPanel.add(j); numRoundsPanel.add(new JPanel()); } return numRoundsPanel; } private JTextField getNumRoundsTextField() { final ISettingsManager props = properties; if (numRoundsTextField == null) { numRoundsTextField = new JTextField(); numRoundsTextField.setAutoscrolls(false); // Center in panel numRoundsTextField.setAlignmentX((float) .5); // Center text in text field numRoundsTextField.setHorizontalAlignment(SwingConstants.CENTER); // Add document listener numRoundsTextField.getDocument().addDocumentListener(new DocumentListener() { public void changedUpdate(DocumentEvent e) {} public void insertUpdate(DocumentEvent e) { handleChange(); } public void removeUpdate(DocumentEvent e) { handleChange(); } private void handleChange() { // Ignore the change if the 'number of rounds' was set by the game, not the user if (nummerOfRoundSetByGame) { return; } // Here we assume that the user made the change try { int numRounds = Integer.parseInt(numRoundsTextField.getText()); props.setNumberOfRounds(numRounds); // Update the user settings } catch (NumberFormatException ignored) {} } }); } return numRoundsTextField; } public int getSelectedRobotsCount() { return selectedRobots.size(); } @Override public boolean isReady() { return (getSelectedRobotsCount() >= minRobots && getSelectedRobotsCount() <= maxRobots); } public void refreshRobotList(final boolean withClear) { final Runnable runnable = new Runnable() { public void run() { final IWindowManager windowManager = Container.getComponent(IWindowManager.class); try { windowManager.setBusyPointer(true); repositoryManager.refresh(withClear); List<IRepositoryItem> robotList = repositoryManager.filterRepositoryItems(onlyShowSource, onlyShowWithPackage, onlyShowRobots, onlyShowDevelopment, false, ignoreTeamRobots, onlyShowInJar); getAvailableRobotsPanel().setRobotList(robotList); if (preSelectedRobots != null && preSelectedRobots.length() > 0) { setSelectedRobots(preSelectedRobots); preSelectedRobots = null; } } finally { windowManager.setBusyPointer(false); } } }; SwingUtilities.invokeLater(runnable); } private void selectedRobotsListSelectionChanged() { int sel[] = getSelectedRobotsList().getSelectedIndices(); if (sel.length == 1) { availableRobotsPanel.clearSelection(); IRepositoryItem robotSpecification = ((AvailableRobotsPanel.ItemWrapper) getSelectedRobotsList().getModel().getElementAt(sel[0])).getItem(); showDescription(robotSpecification); } else { showDescription(null); } } public void setNumRounds(int numRounds) { // Set flag that 'number of rounds' was set by the game, not user nummerOfRoundSetByGame = true; getNumRoundsTextField().setText("" + numRounds); // Clear flag for 'number of rounds' nummerOfRoundSetByGame = false; } private void setSelectedRobots(String selectedRobotsString) { if (selectedRobotsString != null) { for (IRepositoryItem item: repositoryManager.getSelectedSpecifications(selectedRobotsString)) { this.selectedRobots.add(new AvailableRobotsPanel.ItemWrapper(item)); } } ((SelectedRobotsModel) getSelectedRobotsList().getModel()).changed(); fireStateChanged(); } public void showDescription(IRepositoryItem robotSpecification) { getDescriptionPanel().showDescription(robotSpecification); } public void showInstructions() { if (instructions != null) { instructionsLabel.setText(instructions); instructionsLabel.setVisible(true); } else { instructionsLabel.setVisible(false); } } public void showWrongNumInstructions() { if (minRobots == maxRobots) { if (minRobots == 1) { instructionsLabel.setText("Please select exactly 1 robot."); } else { instructionsLabel.setText("Please select exactly " + minRobots + " robots."); } } else { instructionsLabel.setText("Please select between " + minRobots + " and " + maxRobots + " robots."); } instructionsLabel.setVisible(true); } }