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.Collections; 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 java.util.Vector; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.DefaultComboBoxModel; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBox; 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.UIManager; 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.model.GameSettings; import jrummikub.model.PlayerSettings; import jrummikub.model.PlayerSettings.Type; 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 List> playerTypeChoices = Collections.emptyList(); private List removeButtonsEnabled = Collections.emptyList(); private List playerNamesEditable = Collections.emptyList(); private Set playerColors; private SettingsMode settingsMode = SettingsMode.DEFAULT; private JTabbedPane tabbedPane; private JPanel playerSetupPanel; private JPanel playerSettingsViewport; private JPanel optionsPanel; private JButton addPlayerButton; private JLabel errorMessageLabel; private JButton startButton; private JButton offerButton; private List playerSettingsPanels = new ArrayList(); private JLabel variantLabel; private JPanel variantPanel; private JButton setVariantDefaultButton; private JButton setVariantChildrenButton; private JSpinner initialMeldThresholdSpinner; private JSpinner stoneSetNumberSpinner; private JSpinner highestValueSpinner; private JSpinner numberOfStonesDealtSpinner; private JSpinner jokerNumberSpinner; private JSpinner timeSpinner; private JCheckBox noLimitsBox; private JCheckBox seeHandSizeBox; private JPanel colorSelectionPanel; private Map colorButtons = new HashMap(); private JPanel colorLabelPanel; private JLabel initialMeldThresholdLabel; private JLabel stoneSetNumberLabel; private JLabel highestValueLabel; private JLabel numberOfStonesDealtLabel; private JLabel jokerNumberLabel; private JLabel timeLabel; private JLabel noLimitsLabel; private JLabel seeHandSizeLabel; private JButton loadButton; private JButton networkButton; private JButton backButton; private JPanel buttonPanel; private Event startGameEvent = new Event(); private Event loadGameEvent = new Event(); private Event networkGameEvent = new Event(); private Event offerGameEvent = new Event(); private Event backEvent = new Event(); private Event addPlayerEvent = new Event(); private Event1 removePlayerEvent = new Event1(); private Event2 changePlayerColorEvent = new Event2(); private Event2 changePlayerNameEvent = new Event2(); private Event2 changePlayerTypeEvent = new Event2(); private Event1 changeInitialMeldThresholdEvent = new Event1(); private Event1 changeJokerNumberEvent = new Event1(); private Event1 changeStoneSetNumberEvent = new Event1(); private Event1 changeNumberOfStonesDealtEvent = new Event1(); private Event1 changeHighestValueEvent = new Event1(); private Event1> changeStoneColorsEvent = new Event1>(); private Event1 changeTimeEvent = new Event1(); private Event1 changeNoLimitsEvent = new Event1(); private Event1 changeSeeHandSizeEvent = new Event1(); private Event setVariantDefaultEvent = new Event(); private Event setVariantChildrenEvent = new Event(); @Override public IEvent getStartGameEvent() { return startGameEvent; } @Override public IEvent getOfferGameEvent() { return offerGameEvent; } IEvent getLoadGameEvent() { return loadGameEvent; } IEvent getNetworkGameEvent() { return networkGameEvent; } @Override public IEvent getAddPlayerEvent() { return addPlayerEvent; } @Override public IEvent1 getRemovePlayerEvent() { return removePlayerEvent; } @Override public IEvent2 getChangePlayerColorEvent() { return changePlayerColorEvent; } @Override public IEvent2 getChangePlayerNameEvent() { return changePlayerNameEvent; } @Override public IEvent1 getChangeInitialMeldThresholdEvent() { return changeInitialMeldThresholdEvent; } @Override public IEvent1 getChangeStoneSetNumberEvent() { return changeStoneSetNumberEvent; } @Override public IEvent1 getChangeNumberOfStonesDealtEvent() { return changeNumberOfStonesDealtEvent; } @Override public IEvent1 getChangeHighestValueEvent() { return changeHighestValueEvent; } @Override public IEvent1 getChangeJokerNumberEvent() { return changeJokerNumberEvent; } @Override public IEvent2 getChangePlayerTypeEvent() { return changePlayerTypeEvent; } @Override public IEvent1 getChangeTimeEvent() { return changeTimeEvent; } @Override public IEvent1 getChangeNoLimitsEvent() { return changeNoLimitsEvent; } @Override public IEvent1 getChangeSeeHandSize() { return changeSeeHandSizeEvent; } @Override public IEvent1> getChangeStoneColorsEvent() { return changeStoneColorsEvent; } @Override public IEvent getSetVariantDefaultEvent() { return setVariantDefaultEvent; } @Override public IEvent getSetVariantChildrenEvent() { return setVariantChildrenEvent; } @Override public IEvent getBackEvent() { return backEvent; } @Override public void setPlayerTypeChoices(List> choices) { playerTypeChoices = choices; } @Override public void setPlayerColors(Set colors) { playerColors = colors; } @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); offerButton.setEnabled(enable); } @Override public void enableAddPlayerButton(boolean enable) { addPlayerButton.setVisible(enable); } @Override public void enableRemovePlayerButtons(List enable) { removeButtonsEnabled = enable; Iterator it = enable.iterator(); for (PlayerSettingsPanel psp : playerSettingsPanels) { if (!it.hasNext()) { psp.enableRemoveButton(false); } else { psp.enableRemoveButton(it.next()); } } } @Override public void setPlayerNamesEditable(List editable) { playerNamesEditable = editable; Iterator it = editable.iterator(); for (PlayerSettingsPanel psp : playerSettingsPanels) { if (!it.hasNext()) { psp.setPlayerNameEditable(true); } else { psp.setPlayerNameEditable(it.next()); } } } @Override public void setGameSettings(GameSettings gameSettings) { while (playerSettingsPanels.size() > gameSettings.getPlayerList() .size()) { removePlayerSettingsPanel(); } for (int i = 0; i < gameSettings.getPlayerList().size(); ++i) { List choices = Collections.emptyList(); if (i < playerTypeChoices.size()) { choices = playerTypeChoices.get(i); } updatePlayerSettingsPanel(i, gameSettings.getPlayerList().get(i), choices); } setInitialSettingsValue(gameSettings); initialMeldThresholdLabel.setText(gameSettings .getInitialMeldThreshold() + " Punkte"); stoneSetNumberLabel.setText(Integer.toString(gameSettings .getStoneSetNumber())); highestValueLabel.setText(Integer.toString(gameSettings .getHighestValue())); numberOfStonesDealtLabel.setText(Integer.toString(gameSettings .getNumberOfStonesDealt())); jokerNumberLabel .setText(Integer.toString(gameSettings.getJokerNumber())); timeLabel.setText(gameSettings.getTotalTime() + " Sekunden"); noLimitsLabel.setText(gameSettings.isNoLimits() ? "An" : "Aus"); //seeHandSizeLabel.setText(gameSettings.doSeeHandSize() ? "An" : "Aus"); colorLabelPanel.removeAll(); for (StoneColor color : StoneColor.values()) { boolean contained = gameSettings.getStoneColors().contains(color); colorButtons.get(color).getModel().setSelected(contained); if (contained) { colorLabelPanel.add(new JLabel(ImageUtil.createColorIcon( StonePainter.getColor(color), 16, 1))); } } playerSettingsViewport.revalidate(); } private void setInitialSettingsValue(GameSettings gameSettings) { initialMeldThresholdSpinner.setValue(gameSettings .getInitialMeldThreshold()); stoneSetNumberSpinner.setValue(gameSettings.getStoneSetNumber()); highestValueSpinner.setValue(gameSettings.getHighestValue()); numberOfStonesDealtSpinner.setValue(gameSettings .getNumberOfStonesDealt()); jokerNumberSpinner.setValue(gameSettings.getJokerNumber()); timeSpinner.setValue(gameSettings.getTotalTime()); noLimitsBox.setSelected(gameSettings.isNoLimits()); seeHandSizeBox.setSelected(gameSettings.doSeeHandSize()); } private void updatePlayerSettingsPanel(int i, PlayerSettings settings, List choices) { if (i < playerSettingsPanels.size()) { playerSettingsPanels.get(i).setChoices(choices); playerSettingsPanels.get(i).setSettings(settings); } else { addPlayerSettingsPanel(i, settings, choices); } } private void addPlayerSettingsPanel(int i, PlayerSettings settings, List choices) { PlayerSettingsPanel panel = new PlayerSettingsPanel(i, settings, choices, settingsMode != SettingsMode.NETWORK_OFFER && settingsMode != SettingsMode.NETWORK_JOIN); playerSettingsPanels.add(panel); playerSettingsViewport.add(panel, playerSettingsViewport.getComponentCount() - 1); enableRemovePlayerButtons(removeButtonsEnabled); setPlayerNamesEditable(playerNamesEditable); } 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); int row = 1; variantLabel = new JLabel("Variante:"); makeVariantPanel(); row = makeAllOptionLabels(row); GridBagConstraints c = new GridBagConstraints(); c.gridx = 1; c.gridy = row; c.fill = GridBagConstraints.BOTH; c.weightx = 1; c.weighty = 1; optionsPanel.add(makeFiller(), c); } private int makeAllOptionLabels(int row) { makeOptionLabel(row++, "Auslegeschranke:"); initialMeldThresholdLabel = new JLabel(); initialMeldThresholdSpinner = createOptionSpinner(1, 999, 1, changeInitialMeldThresholdEvent); makeOptionLabel(row++, "Anzahl Steins\u00e4tze:"); stoneSetNumberLabel = new JLabel(); stoneSetNumberSpinner = createOptionSpinner(1, 999, 1, changeStoneSetNumberEvent); makeOptionLabel(row++, "H\u00f6chster Steinwert:"); highestValueLabel = new JLabel(); highestValueSpinner = createOptionSpinner(3, 99, 1, changeHighestValueEvent); makeOptionLabel(row++, "Anzahl Startsteine:"); numberOfStonesDealtLabel = new JLabel(); numberOfStonesDealtSpinner = createOptionSpinner(1, 999, 1, changeNumberOfStonesDealtEvent); makeOptionLabel(row++, "Jokeranzahl:"); jokerNumberLabel = new JLabel(); jokerNumberSpinner = createOptionSpinner(0, 999, 1, changeJokerNumberEvent); makeOptionLabel(row++, "Zeit f\u00fcr Spielzug:"); timeLabel = new JLabel(); timeSpinner = createOptionSpinner(1, 999, 1, changeTimeEvent); makeOptionLabel(row++, "No Limits:"); noLimitsLabel = new JLabel(); noLimitsBox = createOptionCheckbox(changeNoLimitsEvent); seeHandSizeBox = createOptionCheckbox(changeSeeHandSizeEvent); makeOptionLabel(row++, "Steinanzahl anzeigen"); makeOptionLabel(row, "Steinfarben:"); createColorSelectionPanel(); colorLabelPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0)); return row; } private void removeOptionPanelComponentsAndLabels() { optionsPanel.remove(variantLabel); optionsPanel.remove(variantPanel); optionsPanel.remove(initialMeldThresholdSpinner); optionsPanel.remove(initialMeldThresholdLabel); optionsPanel.remove(stoneSetNumberSpinner); optionsPanel.remove(stoneSetNumberLabel); optionsPanel.remove(highestValueSpinner); optionsPanel.remove(highestValueLabel); optionsPanel.remove(numberOfStonesDealtSpinner); optionsPanel.remove(numberOfStonesDealtLabel); optionsPanel.remove(jokerNumberSpinner); optionsPanel.remove(jokerNumberLabel); optionsPanel.remove(timeSpinner); optionsPanel.remove(timeLabel); optionsPanel.remove(noLimitsBox); optionsPanel.remove(noLimitsLabel); optionsPanel.remove(seeHandSizeBox); optionsPanel.remove(colorSelectionPanel); optionsPanel.remove(colorLabelPanel); } private void addOptionPanelComponents() { removeOptionPanelComponentsAndLabels(); int row = 0; addOptionPanelComponent(variantLabel, true, row); addOptionPanelComponent(variantPanel, false, row++); addOptionPanelComponent(initialMeldThresholdSpinner, false, row++); addOptionPanelComponent(stoneSetNumberSpinner, false, row++); addOptionPanelComponent(highestValueSpinner, false, row++); addOptionPanelComponent(numberOfStonesDealtSpinner, false, row++); addOptionPanelComponent(jokerNumberSpinner, false, row++); addOptionPanelComponent(timeSpinner, false, row++); addOptionPanelComponent(noLimitsBox, false, row++); addOptionPanelComponent(seeHandSizeBox, false, row++); addOptionPanelComponent(colorSelectionPanel, false, row++); } private void addOptionPanelLabels() { removeOptionPanelComponentsAndLabels(); int row = 1; addOptionPanelComponent(initialMeldThresholdLabel, false, row++); addOptionPanelComponent(stoneSetNumberLabel, false, row++); addOptionPanelComponent(highestValueLabel, false, row++); addOptionPanelComponent(numberOfStonesDealtLabel, false, row++); addOptionPanelComponent(jokerNumberLabel, false, row++); addOptionPanelComponent(timeLabel, false, row++); addOptionPanelComponent(noLimitsLabel, false, row++); addOptionPanelComponent(seeHandSizeBox, false, row++); addOptionPanelComponent(colorLabelPanel, false, row++); } private void addOptionPanelComponent(JComponent component, boolean label, int row) { GridBagConstraints c = new GridBagConstraints(); c.anchor = label ? GridBagConstraints.EAST : GridBagConstraints.WEST; c.gridx = label ? 0 : 1; c.gridy = row; c.insets = new Insets(2, 2, 2, 2); optionsPanel.add(component, c); } private void createColorSelectionPanel() { colorSelectionPanel = new JPanel(); 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 colors = new HashSet(); for (StoneColor color : StoneColor.values()) { if (colorButtons.get(color).getModel().isSelected()) { colors.add(color); } } changeStoneColorsEvent.emit(colors); } private void makeVariantPanel() { variantPanel = new JPanel(new GridLayout(1, 2, 5, 0)); setVariantDefaultButton = new JButton("Standard"); variantPanel.add(setVariantDefaultButton); setVariantDefaultButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setVariantDefaultEvent.emit(); } }); setVariantChildrenButton = new JButton("Kinder"); variantPanel.add(setVariantChildrenButton); setVariantChildrenButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setVariantChildrenEvent.emit(); } }); } private JCheckBox createOptionCheckbox(final Event1 targetEvent) { final JCheckBox box = new JCheckBox(); box.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { targetEvent.emit(box.isSelected()); } }); return box; } private JSpinner createOptionSpinner(int min, int max, int step, final Event1 targetEvent) { 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()); } }); return spinner; } private JLabel 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); return label; } SettingsPanel() { setLayout(new GridBagLayout()); tabbedPane = new JTabbedPane(); createPlayerSetupPanel(); tabbedPane.addTab("Spieler", playerSetupPanel); createOptionsPanel(); JScrollPane scrollPane = new JScrollPane(optionsPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); tabbedPane.addTab("Optionen", scrollPane); 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); buttonPanel = new JPanel(); buttonPanel.setLayout(new GridBagLayout()); add(buttonPanel, c); startButton = createButton("Spiel starten", startGameEvent); loadButton = createButton("Spiel laden...", loadGameEvent); networkButton = createButton("Netzwerkspiel...", networkGameEvent); offerButton = createButton("Spiel anbieten", offerGameEvent); backButton = createButton("Zur\u00fcck", backEvent); addDefaultButtons(); setBorder(new CompoundBorder(new LineBorder(Color.BLACK), new EmptyBorder(10, 10, 10, 10))); } void resetTabbedPane() { tabbedPane.setSelectedIndex(0); } private void addDefaultButtons() { GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; c.gridwidth = 1; c.weightx = 1; c.weighty = 1; buttonPanel.add(startButton, c); c.weightx = 0; buttonPanel.add(Box.createHorizontalStrut(10), c); c.weightx = 1; buttonPanel.add(loadButton, c); c.weightx = 0; buttonPanel.add(Box.createHorizontalStrut(10), c); c.weightx = 1; c.gridwidth = GridBagConstraints.REMAINDER; buttonPanel.add(networkButton, c); } private void addNetworkSetupButtons() { GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; c.gridwidth = 1; c.weightx = 1; c.weighty = 1; buttonPanel.add(offerButton, c); c.weightx = 0; buttonPanel.add(Box.createHorizontalStrut(10), c); c.weightx = 1; c.gridwidth = GridBagConstraints.REMAINDER; buttonPanel.add(backButton, c); } private void addNetworkOfferButtons() { GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; c.gridwidth = 1; c.weightx = 1; c.weighty = 1; buttonPanel.add(startButton, c); c.weightx = 0; buttonPanel.add(Box.createHorizontalStrut(10), c); c.weightx = 1; c.gridwidth = GridBagConstraints.REMAINDER; buttonPanel.add(backButton, c); } private void addNetworkJoinButtons() { GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; c.gridwidth = GridBagConstraints.REMAINDER; c.weightx = 1; c.weighty = 1; buttonPanel.add(backButton, c); } private JButton createButton(String title, final Event event) { JButton button = new JButton(title); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { event.emit(); } }); return button; } @Override public void setSettingsMode(SettingsMode mode) { settingsMode = mode; while (!playerSettingsPanels.isEmpty()) { removePlayerSettingsPanel(); } buttonPanel.removeAll(); switch (mode) { case DEFAULT: addDefaultButtons(); enableOptions(true); break; case NETWORK_SETUP: addNetworkSetupButtons(); enableOptions(true); break; case NETWORK_OFFER: addNetworkOfferButtons(); enableOptions(false); break; case NETWORK_JOIN: addNetworkJoinButtons(); enableOptions(false); break; } } private void enableOptions(boolean enable) { if (enable) { addOptionPanelComponents(); } else { addOptionPanelLabels(); } } private class PlayerSettingsPanel extends JPanel { private int playerNumber; private JButton colorButton; private JTextField nameField; private JButton removeButton; private JComboBox playerType; private List playerTypeChoices; private boolean colorChangable = true; private JLabel nameLabel; private JLabel typeLabel; public void setSettings(PlayerSettings settings) { if (nameField != null && !nameField.getText().equals(settings.getName())) { nameField.setText(settings.getName()); } if (nameLabel != null) { nameLabel.setText(settings.getName()); } if (playerType != null) { int index = playerTypeChoices.indexOf(settings.getType()); if (index != playerType.getSelectedIndex() && index >= 0 && index < playerType.getModel().getSize()) { playerType.setSelectedIndex(index); } } if (typeLabel != null) { typeLabel.setText(getTypeLabel(settings.getType())); } colorButton.setIcon(ImageUtil.createColorIcon(settings.getColor(), 16, 2)); colorChangable = !((settingsMode == SettingsMode.NETWORK_JOIN | settingsMode == SettingsMode.NETWORK_OFFER) & settings .getType() != Type.HUMAN); } public void setPlayerNameEditable(boolean editable) { if (nameField != null) { nameField.setEditable(editable); } } public void enableRemoveButton(boolean enable) { if (removeButton != null) { 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, List choices, boolean editable) { setLayout(new GridBagLayout()); this.playerNumber = playerNumber; if (editable) { createControls(settings); } else { createLabels(); } setChoices(choices); setSettings(settings); } private String getTypeLabel(Type type) { switch (type) { case COMPUTER: return "Computer"; case HUMAN: return "Mensch"; case NETWORK: case VACANT: return "Netzwerk"; } return null; } public void setChoices(List playerTypeChoices) { this.playerTypeChoices = playerTypeChoices; Vector choices = new Vector(); for (Type t : playerTypeChoices) { choices.add(getTypeLabel(t)); } if (playerType != null) { playerType.setModel(new DefaultComboBoxModel(choices)); } } 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); playerType = new JComboBox(); playerType.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { changeType(); } }); playerType.setPreferredSize(new Dimension(120, playerType .getPreferredSize().height)); playerType.setMinimumSize(new Dimension(120, playerType .getMinimumSize().height)); 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(); } }); add(removeButton, c); } private void createLabels() { GridBagConstraints c = new GridBagConstraints(); GridBagConstraints c2 = new GridBagConstraints(); colorButton = new JButton(); nameLabel = new JLabel(); nameLabel.setBorder(new EmptyBorder(3, 7, 3, 7)); nameLabel.putClientProperty("html.disable", Boolean.TRUE); colorButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (colorChangable) { new ColorMenu(); } } }); c.gridy = 0; add(colorButton, c); c2.gridy = 0; c2.weightx = 1; c2.fill = GridBagConstraints.HORIZONTAL; add(nameLabel, c2); typeLabel = new JLabel(" "); typeLabel.setBorder(new EmptyBorder(3, 7, 3, 7)); typeLabel.setPreferredSize(new Dimension(120, typeLabel .getPreferredSize().height)); typeLabel.setMinimumSize(new Dimension(120, typeLabel .getMinimumSize().height)); add(typeLabel, 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, playerTypeChoices.get(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) { if (playerColors.contains(c)) { add(new ColorButton(c, menu)); } else { add(new JLabel(ImageUtil.createColorIcon( UIManager.getColor("PopupMenu.background"), 16, 0))); } } 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); } }); } } } } }