This repository has been archived on 2025-03-02. You can view files and clone it, but cannot push or open issues or pull requests.
JRummikub/src/jrummikub/view/impl/SettingsPanel.java
Ida Massow 8c2e4a7d59 Man kann den Timer einstellen
git-svn-id: svn://sunsvr01.isp.uni-luebeck.de/swproj13/trunk@391 72836036-5685-4462-b002-a69064685172
2011-06-09 00:11:26 +02:00

625 lines
18 KiB
Java

package jrummikub.view.impl;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.SpinnerNumberModel;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import jrummikub.control.turn.TurnControlFactory;
import jrummikub.control.turn.TurnControlFactory.Type;
import jrummikub.model.GameSettings;
import jrummikub.model.PlayerSettings;
import jrummikub.model.StoneColor;
import jrummikub.util.Event;
import jrummikub.util.Event1;
import jrummikub.util.Event2;
import jrummikub.util.IEvent;
import jrummikub.util.IEvent1;
import jrummikub.util.IEvent2;
import jrummikub.view.ISettingsPanel;
@SuppressWarnings("serial")
class SettingsPanel extends JPanel implements ISettingsPanel {
private JPanel playerSetupPanel;
private JPanel playerSettingsViewport;
private JPanel optionsPanel;
private JButton addPlayerButton;
private JLabel errorMessageLabel;
private JButton startButton;
private boolean removeButtonsEnabled = true;
private List<PlayerSettingsPanel> playerSettingsPanels = new ArrayList<PlayerSettingsPanel>();
private JSpinner initialMeldThresholdSpinner;
private JSpinner stoneSetNumberSpinner;
private JSpinner highestValueSpinner;
private JSpinner numberOfStonesDealtSpinner;
private JSpinner jokerNumberSpinner;
private JSpinner timeSpinner;
private JPanel colorSelectionPanel;
private Map<StoneColor, JToggleButton> colorButtons = new HashMap<StoneColor, JToggleButton>();
private Event startGameEvent = new Event();
private Event addPlayerEvent = new Event();
private Event1<Integer> removePlayerEvent = new Event1<Integer>();
private Event2<Integer, Color> changePlayerColorEvent = new Event2<Integer, Color>();
private Event2<Integer, String> changePlayerNameEvent = new Event2<Integer, String>();
private Event2<Integer, TurnControlFactory.Type> changePlayerTypeEvent = new Event2<Integer, TurnControlFactory.Type>();
private Event1<Integer> changeInitialMeldThresholdEvent = new Event1<Integer>();
private Event1<Integer> changeJokerNumberEvent = new Event1<Integer>();
private Event1<Integer> changeStoneSetNumberEvent = new Event1<Integer>();
private Event1<Integer> changeNumberOfStonesDealtEvent = new Event1<Integer>();
private Event1<Integer> changeHighestValueEvent = new Event1<Integer>();
private Event1<Set<StoneColor>> changeStoneColorsEvent = new Event1<Set<StoneColor>>();
private Event1<Integer> changeTimeEvent = new Event1<Integer>();
@Override
public IEvent getStartGameEvent() {
return startGameEvent;
}
@Override
public IEvent getAddPlayerEvent() {
return addPlayerEvent;
}
@Override
public IEvent1<Integer> getRemovePlayerEvent() {
return removePlayerEvent;
}
@Override
public IEvent2<Integer, Color> getChangePlayerColorEvent() {
return changePlayerColorEvent;
}
@Override
public IEvent2<Integer, String> getChangePlayerNameEvent() {
return changePlayerNameEvent;
}
@Override
public IEvent1<Integer> getChangeInitialMeldThresholdEvent() {
return changeInitialMeldThresholdEvent;
}
@Override
public IEvent1<Integer> getChangeStoneSetNumberEvent() {
return changeStoneSetNumberEvent;
}
@Override
public IEvent1<Integer> getChangeNumberOfStonesDealtEvent() {
return changeNumberOfStonesDealtEvent;
}
@Override
public IEvent1<Integer> getChangeHighestValueEvent() {
return changeHighestValueEvent;
}
@Override
public IEvent1<Integer> getChangeJokerNumberEvent() {
return changeJokerNumberEvent;
}
@Override
public IEvent2<Integer, Type> getChangePlayerTypeEvent() {
return changePlayerTypeEvent;
}
@Override
public Event1<Integer> getChangeTimeEvent() {
return changeTimeEvent;
}
@Override
public IEvent1<Set<StoneColor>> getChangeStoneColorsEvent() {
return changeStoneColorsEvent;
}
@Override
public void setError(SettingsError error) {
switch (error) {
case NO_ERROR:
errorMessageLabel.setText(" ");
break;
case DUPLICATE_PLAYER_NAME_ERROR:
errorMessageLabel
.setText("Jeder Spielername darf nur einmal verwendet werden.");
errorMessageLabel.setForeground(Color.RED);
break;
case NO_PLAYER_NAME_ERROR:
errorMessageLabel.setText("Jeder Spieler muss einen Namen haben.");
errorMessageLabel.setForeground(Color.RED);
break;
case NOT_ENOUGH_STONES_ERROR:
errorMessageLabel
.setText("Es gibt nicht genug Steine f\u00fcr die gew\u00e4hlte Spieleranzahl.");
errorMessageLabel.setForeground(Color.RED);
break;
case NOT_ENOUGH_COLORS_ERROR:
errorMessageLabel
.setText("Es m\u00fcssen mindestens drei Farben ausgew\u00e4hlt werden.");
errorMessageLabel.setForeground(Color.RED);
break;
case COMPUTER_PLAYERS_ONLY_WARNING:
errorMessageLabel.setText("Es gibt keinen menschlichen Spieler.");
errorMessageLabel.setForeground(Color.ORANGE.darker());
break;
case TOO_HIGH_THRESHOLD_WARNING:
errorMessageLabel
.setText("Die gew\u00e4hlte Schranke ist m\u00f6glicherweise zu hoch");
errorMessageLabel.setForeground(Color.ORANGE.darker());
break;
}
}
@Override
public void enableStartGameButton(boolean enable) {
startButton.setEnabled(enable);
}
@Override
public void enableAddPlayerButton(boolean enable) {
addPlayerButton.setVisible(enable);
}
@Override
public void enableRemovePlayerButtons(boolean enable) {
removeButtonsEnabled = enable;
for (PlayerSettingsPanel psp : playerSettingsPanels) {
psp.enableRemoveButton(enable);
}
}
@Override
public void setGameSettings(GameSettings gameSettings) {
while (playerSettingsPanels.size() > gameSettings.getPlayerList().size()) {
removePlayerSettingsPanel();
}
for (int i = 0; i < gameSettings.getPlayerList().size(); ++i) {
updatePlayerSettingsPanel(i, gameSettings.getPlayerList().get(i));
}
initialMeldThresholdSpinner
.setValue(gameSettings.getInitialMeldThreshold());
stoneSetNumberSpinner.setValue(gameSettings.getStoneSetNumber());
highestValueSpinner.setValue(gameSettings.getHighestValue());
numberOfStonesDealtSpinner.setValue(gameSettings.getNumberOfStonesDealt());
jokerNumberSpinner.setValue(gameSettings.getJokerNumber());
timeSpinner.setValue(gameSettings.getTime());
for (StoneColor color : StoneColor.values()) {
colorButtons.get(color).getModel()
.setSelected(gameSettings.getStoneColors().contains(color));
}
playerSettingsViewport.revalidate();
}
private void updatePlayerSettingsPanel(int i, PlayerSettings settings) {
if (i < playerSettingsPanels.size()) {
playerSettingsPanels.get(i).setSettings(settings);
} else {
addPlayerSettingsPanel(i, settings);
}
}
private void addPlayerSettingsPanel(int i, PlayerSettings settings) {
PlayerSettingsPanel panel = new PlayerSettingsPanel(i, settings);
playerSettingsPanels.add(panel);
playerSettingsViewport.add(panel,
playerSettingsViewport.getComponentCount() - 1);
}
private void removePlayerSettingsPanel() {
PlayerSettingsPanel p = playerSettingsPanels.remove(playerSettingsPanels
.size() - 1);
playerSettingsViewport.remove(p);
}
private void createPlayerSetupPanel() {
playerSetupPanel = new JPanel();
playerSetupPanel.setLayout(new BorderLayout());
playerSettingsViewport = new JPanel();
playerSettingsViewport.setLayout(new BoxLayout(playerSettingsViewport,
BoxLayout.Y_AXIS));
JScrollPane scrollPane = new JScrollPane(playerSettingsViewport,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
playerSetupPanel.add(scrollPane);
JPanel addPlayerPanel = new JPanel();
addPlayerPanel.setLayout(new FlowLayout(FlowLayout.TRAILING, 0, 2));
playerSettingsViewport.add(addPlayerPanel);
addPlayerButton = new JButton("+");
addPlayerButton.setFont(addPlayerButton.getFont().deriveFont(Font.BOLD));
addPlayerButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
addPlayerEvent.emit();
}
});
addPlayerPanel.add(addPlayerButton);
}
private JComponent makeFiller() {
return new Box.Filler(new Dimension(0, 0), new Dimension(0, 0),
new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
}
private void createOptionsPanel() {
optionsPanel = new JPanel();
GridBagLayout layout = new GridBagLayout();
optionsPanel.setLayout(layout);
makeOptionLabel(0, "Auslegeschranke:");
initialMeldThresholdSpinner = makeOptionSpinner(0, 1, 999, 1,
changeInitialMeldThresholdEvent);
makeOptionLabel(1, "Anzahl Steins\u00e4tze:");
stoneSetNumberSpinner = makeOptionSpinner(1, 1, 999, 1,
changeStoneSetNumberEvent);
makeOptionLabel(2, "H\u00f6chster Steinwert:");
highestValueSpinner = makeOptionSpinner(2, 3, 99, 1,
changeHighestValueEvent);
makeOptionLabel(3, "Anzahl Startsteine:");
numberOfStonesDealtSpinner = makeOptionSpinner(3, 1, 999, 1,
changeNumberOfStonesDealtEvent);
makeOptionLabel(4, "Jokeranzahl:");
jokerNumberSpinner = makeOptionSpinner(4, 1, 999, 1, changeJokerNumberEvent);
makeOptionLabel(5, "Zeit für Spielzug:");
timeSpinner = makeOptionSpinner(5, 1, 999, 1, changeTimeEvent);
makeOptionLabel(6, "Steinfarben:");
createColorSelectionPanel(6);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 7;
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.weighty = 1;
optionsPanel.add(makeFiller(), c);
}
private void createColorSelectionPanel(int row) {
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.WEST;
c.gridx = 1;
c.gridy = row;
colorSelectionPanel = new JPanel();
optionsPanel.add(colorSelectionPanel, c);
for (StoneColor color : StoneColor.values()) {
createColorButton(color);
}
}
private void createColorButton(final StoneColor color) {
JToggleButton button = new JToggleButton(ImageUtil.createColorIcon(
StonePainter.getColor(color), 12, 1));
button.setMargin(new Insets(3, 3, 3, 3));
button.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
emitColorChangeEvent();
}
});
colorSelectionPanel.add(button);
colorButtons.put(color, button);
}
private void emitColorChangeEvent() {
Set<StoneColor> colors = new HashSet<StoneColor>();
for (StoneColor color : StoneColor.values()) {
if (colorButtons.get(color).getModel().isSelected()) {
colors.add(color);
}
}
changeStoneColorsEvent.emit(colors);
}
private JSpinner makeOptionSpinner(int row, int min, int max, int step,
final Event1<Integer> targetEvent) {
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.WEST;
c.gridx = 1;
c.gridy = row;
c.insets = new Insets(2, 2, 2, 2);
final JSpinner spinner = new JSpinner();
spinner.setModel(new SpinnerNumberModel(min, min, max, step));
spinner
.setPreferredSize(new Dimension(60, spinner.getMinimumSize().height));
spinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
targetEvent.emit((Integer) spinner.getValue());
}
});
optionsPanel.add(spinner, c);
return spinner;
}
private void makeOptionLabel(int row, String name) {
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.EAST;
c.gridx = 0;
c.gridy = row;
c.insets = new Insets(4, 4, 4, 4);
JLabel label = new JLabel(name);
optionsPanel.add(label, c);
}
SettingsPanel() {
setLayout(new GridBagLayout());
final JTabbedPane tabbedPane = new JTabbedPane();
createPlayerSetupPanel();
tabbedPane.addTab("Spieler", playerSetupPanel);
createOptionsPanel();
tabbedPane.addTab("Optionen", optionsPanel);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.gridwidth = GridBagConstraints.REMAINDER;
c.weightx = 1;
c.weighty = 1;
add(tabbedPane, c);
errorMessageLabel = new JLabel(" ");
c.weighty = 0;
add(errorMessageLabel, c);
startButton = new JButton("Spiel starten");
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
startGameEvent.emit();
}
});
add(startButton, c);
setBorder(new CompoundBorder(new LineBorder(Color.BLACK), new EmptyBorder(
10, 10, 10, 10)));
}
private class PlayerSettingsPanel extends JPanel {
private int playerNumber;
private JButton colorButton;
private JTextField nameField;
private JButton removeButton;
private JComboBox playerType;
public void setSettings(PlayerSettings settings) {
if (!nameField.getText().equals(settings.getName())) {
nameField.setText(settings.getName());
}
// playerType.setSelectedIndex(0);
int index = Arrays.binarySearch(TurnControlFactory.Type.values(),
settings.getTurnControlType());
if (index != playerType.getSelectedIndex()) {
playerType.setSelectedIndex(index);
}
colorButton
.setIcon(ImageUtil.createColorIcon(settings.getColor(), 16, 2));
}
public void enableRemoveButton(boolean enable) {
removeButton.setEnabled(enable);
}
class NameChangeListener implements DocumentListener {
@Override
public void insertUpdate(DocumentEvent e) {
changeName();
}
@Override
public void removeUpdate(DocumentEvent e) {
changeName();
}
@Override
public void changedUpdate(DocumentEvent e) {
changeName();
}
}
public PlayerSettingsPanel(int playerNumber, PlayerSettings settings) {
setLayout(new GridBagLayout());
this.playerNumber = playerNumber;
createControls(settings);
setSettings(settings);
}
private void createControls(PlayerSettings settings) {
GridBagConstraints c = new GridBagConstraints();
GridBagConstraints c2 = new GridBagConstraints();
colorButton = new JButton();
nameField = new JTextField(settings.getName());
colorButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new ColorMenu();
}
});
c.gridy = 0;
add(colorButton, c);
nameField.getDocument().addDocumentListener(new NameChangeListener());
c2.gridy = 0;
c2.weightx = 1;
c2.fill = GridBagConstraints.HORIZONTAL;
add(nameField, c2);
String[] choices = { "Mensch", "Computer" };
playerType = new JComboBox(choices);
playerType.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
changeType();
}
});
add(playerType, c);
removeButton = new JButton("\u00d7");
removeButton.setFont(removeButton.getFont().deriveFont(Font.BOLD));
removeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
remove();
}
});
removeButton.setEnabled(removeButtonsEnabled);
add(removeButton, c);
}
@Override
public Dimension getPreferredSize() {
Dimension preferredSize = super.getPreferredSize();
for (Component component : this.getComponents()) {
preferredSize
.setSize(preferredSize.width, Math.max(preferredSize.height,
component.getPreferredSize().height));
}
return preferredSize;
}
@Override
public Dimension getMaximumSize() {
Dimension preferredSize = super.getPreferredSize();
for (Component component : this.getComponents()) {
preferredSize
.setSize(Integer.MAX_VALUE, Math.max(preferredSize.height,
component.getPreferredSize().height));
}
return preferredSize;
}
private void changeName() {
changePlayerNameEvent.emit(playerNumber, nameField.getText());
}
private void changeColor(Color c) {
changePlayerColorEvent.emit(playerNumber, c);
}
private void changeType() {
changePlayerTypeEvent.emit(playerNumber,
TurnControlFactory.Type.values()[playerType.getSelectedIndex()]);
}
private void remove() {
removePlayerEvent.emit(playerNumber);
}
private class ColorMenu extends JPanel {
ColorMenu() {
setLayout(new GridLayout(4, 4, 1, 1));
JPopupMenu menu = new JPopupMenu();
for (Color c : PLAYER_COLORS) {
add(new ColorButton(c, menu));
}
menu.setLayout(new BorderLayout());
menu.add(this);
menu.show(colorButton, 0, colorButton.getHeight());
}
private class ColorButton extends JLabel {
ColorButton(final Color c, final JPopupMenu menu) {
final Icon normalIcon = ImageUtil.createColorIcon(c, 16, 1);
final Icon hoverIcon = ImageUtil.createColorIcon(c, 16, 2);
setIcon(normalIcon);
addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
setIcon(hoverIcon);
}
@Override
public void mouseExited(MouseEvent e) {
setIcon(normalIcon);
}
@Override
public void mouseClicked(MouseEvent e) {
menu.setVisible(false);
changeColor(c);
}
});
}
}
}
}
}