/*
* $Id$
*
* Copyright (c) 2000-2003 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.counters;
import java.awt.Component;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import VASSAL.build.GameModule;
import VASSAL.build.module.Map;
import VASSAL.build.module.documentation.HelpFile;
import VASSAL.build.module.map.DrawPile;
import VASSAL.command.Command;
import VASSAL.configure.NamedHotKeyConfigurer;
import VASSAL.configure.StringConfigurer;
import VASSAL.i18n.PieceI18nData;
import VASSAL.i18n.Resources;
import VASSAL.i18n.TranslatablePiece;
import VASSAL.tools.NamedKeyStroke;
import VASSAL.tools.ScrollPane;
import VASSAL.tools.SequenceEncoder;
import VASSAL.tools.UniqueIdManager;
/**
* GamePiece trait that returns a piece to a {@link DrawPile}
*/
public class ReturnToDeck extends Decorator implements TranslatablePiece {
public static final String ID = "return;";
protected String deckId;
protected String returnCommand;
protected String selectDeckPrompt="Select destination";
protected NamedKeyStroke returnKey;
protected DrawPile deck;
protected KeyCommand[] commands;
protected KeyCommand myCommand;
public ReturnToDeck() {
this(ID + "Return to Deck;R;", null);
}
public ReturnToDeck(String type, GamePiece inner) {
mySetType(type);
setInner(inner);
}
protected KeyCommand[] myGetKeyCommands() {
if (commands == null) {
myCommand = new KeyCommand(returnCommand, returnKey, Decorator.getOutermost(this), this);
if (returnCommand.length() > 0 && returnKey != null && !returnKey.isNull()) {
commands =
new KeyCommand[]{myCommand};
}
else {
commands = new KeyCommand[0];
}
}
return commands;
}
public String myGetState() {
return "";
}
public void mySetType(String s) {
s = s.substring(ID.length());
SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(s, ';');
returnCommand = st.nextToken();
returnKey = st.nextNamedKeyStroke(null);
deckId = st.nextToken("");
selectDeckPrompt = st.nextToken(selectDeckPrompt);
}
public String myGetType() {
SequenceEncoder se = new SequenceEncoder(';');
return ID + se.append(returnCommand).append(returnKey).append(deckId).append(selectDeckPrompt).getValue();
}
public Command myKeyEvent(KeyStroke stroke) {
myGetKeyCommands();
Command comm = null;
if (myCommand.matches(stroke)) {
DrawPile pile = deck;
if (pile == null || deckId.length() == 0)
pile = findDeck();
if (pile == null)
return null;
final Map preMap = getMap();
final Point prePos = getPosition();
setOldProperties();
comm = pile.addToContents(Decorator.getOutermost(this));
// Apply Auto-move key if the piece has moved
Map m = pile.getMap();
if (m != null && m.getMoveKey() != null && (m != preMap || !getPosition().equals(prePos))) {
comm.append(Decorator.getOutermost(this).keyEvent(m.getMoveKey()));
}
pile.getMap().repaint();
}
return comm;
}
public Rectangle boundingBox() {
return piece.boundingBox();
}
public void draw(Graphics g, int x, int y, Component obs, double zoom) {
piece.draw(g, x, y, obs, zoom);
}
public String getName() {
return piece.getName();
}
public Shape getShape() {
return piece.getShape();
}
private DrawPile findDeck() {
DrawPile pile = null;
if (deckId.length() > 0)
pile = DrawPile.findDrawPile(deckId);
if (pile == null)
return promptForDrawPile();
// cache
deck = pile;
return pile;
}
private DrawPile promptForDrawPile() {
final JDialog d = new JDialog(GameModule.getGameModule().getFrame(), true);
d.setTitle(Decorator.getInnermost(this).getName()); //$NON-NLS-1$
d.setLayout(new BoxLayout(d.getContentPane(), BoxLayout.Y_AXIS));
class AvailableDeck {
private DrawPile pile;
public AvailableDeck(DrawPile pile) {
this.pile = pile;
}
public String toString() {
return pile.getConfigureName();
}
}
final List<DrawPile> piles =
GameModule.getGameModule().getAllDescendantComponentsOf(DrawPile.class);
if (piles.size() == 0) {
reportDataError(this, "No decks in module.");
return null;
}
final AvailableDeck[] decks = new AvailableDeck[piles.size()];
int i = 0;
for (DrawPile p : piles)
decks[i++] = new AvailableDeck(p);
final JList list = new JList(decks);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JLabel prompt = new JLabel(selectDeckPrompt);
prompt.setAlignmentX(0.5f);
d.add(prompt); //$NON-NLS-1$
d.add(new ScrollPane(list));
Box box = Box.createHorizontalBox();
box.setAlignmentX(0.5F);
JButton b = new JButton(Resources.getString(Resources.OK));
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
AvailableDeck selection = (AvailableDeck) list.getSelectedValue();
if (selection != null)
deck = selection.pile;
d.dispose();
}
});
box.add(b);
b = new JButton(Resources.getString(Resources.CANCEL));
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
d.dispose();
}
});
box.add(b);
d.add(box);
d.pack();
d.setLocationRelativeTo(d.getOwner());
d.setVisible(true);
// don't cache -- ask again next time
DrawPile pile = deck;
deck = null;
return pile;
}
public void mySetState(String newState) {
}
public PieceEditor getEditor() {
return new Ed(this);
}
public String getDescription() {
String d = "Return to Deck";
if (deck != null) {
findDeck();
if (deck != null) {
d += " - " + deck.getConfigureName();
}
}
return d;
}
public HelpFile getHelpFile() {
return HelpFile.getReferenceManualPage("ReturnToDeck.htm");
}
public PieceI18nData getI18nData() {
return getI18nData(returnCommand, "Return to Deck command");
}
private static class Ed implements PieceEditor {
private StringConfigurer menuName;
private NamedHotKeyConfigurer menuKey;
private JPanel controls;
private String deckId;
private final JTextField tf = new JTextField(12);
private StringConfigurer promptText;
private JCheckBox prompt;
public Ed(ReturnToDeck p) {
controls = new JPanel();
controls.setLayout(new BoxLayout(controls, BoxLayout.Y_AXIS));
menuName = new StringConfigurer(null, "Menu Text: ", p.returnCommand);
controls.add(menuName.getControls());
menuKey = new NamedHotKeyConfigurer(null,"Keyboard Command: ",p.returnKey);
deckId = p.deckId;
controls.add(menuKey.getControls());
JButton select = new JButton("Select Deck");
tf.setEditable(false);
updateDeckName();
select.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
VASSAL.configure.ChooseComponentDialog d = new VASSAL.configure.ChooseComponentDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, controls), DrawPile.class);
d.setTitle("Select Deck");
d.setVisible(true);
if (d.getTarget() != null) {
deckId = UniqueIdManager.getIdentifier((UniqueIdManager.Identifyable)d.getTarget());
updateDeckName();
}
}
});
final Box box = Box.createHorizontalBox();
box.add(select);
box.add(tf);
controls.add(box);
promptText = new StringConfigurer(null,"Prompt for destination deck: ",p.selectDeckPrompt);
prompt = new JCheckBox("Choose destination deck at game time?");
controls.add(prompt);
controls.add(promptText.getControls());
promptText.getControls().setVisible(p.deckId == null || p.deckId.length() == 0);
box.setVisible(p.deckId != null && p.deckId.length() > 0);
prompt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
box.setVisible(!prompt.isSelected());
promptText.getControls().setVisible(prompt.isSelected());
}
});
prompt.setSelected(p.deckId == null || p.deckId.length() == 0);
}
private void updateDeckName() {
DrawPile p = DrawPile.findDrawPile(deckId);
tf.setText(p != null ? p.getConfigureName() : "<none>");
}
public Component getControls() {
return controls;
}
public String getState() {
return "";
}
public String getType() {
SequenceEncoder se = new SequenceEncoder(';');
return ID + se.append(menuName.getValueString()).append(menuKey.getValueString()).append(prompt.isSelected() ? "" : deckId).append(promptText.getValueString()).getValue();
}
}
}