/*
* $Id$
*
* Copyright (c) 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.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Window;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import VASSAL.build.module.Map;
import VASSAL.build.module.documentation.HelpFile;
import VASSAL.build.module.map.MassKeyCommand;
import VASSAL.command.Command;
import VASSAL.command.NullCommand;
import VASSAL.configure.BooleanConfigurer;
import VASSAL.configure.IntConfigurer;
import VASSAL.configure.NamedHotKeyConfigurer;
import VASSAL.configure.PropertyExpression;
import VASSAL.configure.PropertyExpressionConfigurer;
import VASSAL.configure.StringConfigurer;
import VASSAL.i18n.PieceI18nData;
import VASSAL.i18n.Resources;
import VASSAL.i18n.TranslatablePiece;
import VASSAL.tools.NamedKeyStroke;
import VASSAL.tools.RecursionLimiter;
import VASSAL.tools.SequenceEncoder;
/**
* Adds a menu item that applies a {@link GlobalCommand} to other pieces
*/
public class CounterGlobalKeyCommand extends Decorator
implements TranslatablePiece,
RecursionLimiter.Loopable {
public static final String ID = "globalkey;";
protected KeyCommand[] command;
protected String commandName;
protected NamedKeyStroke key;
protected NamedKeyStroke globalKey;
protected GlobalCommand globalCommand = new GlobalCommand(this);
protected PropertyExpression propertiesFilter = new PropertyExpression();
protected boolean restrictRange;
protected boolean fixedRange = true;
protected int range;
protected String rangeProperty = "";
private KeyCommand myCommand;
protected String description;
public CounterGlobalKeyCommand() {
this(ID, null);
}
public CounterGlobalKeyCommand(String type, GamePiece inner) {
mySetType(type);
setInner(inner);
}
public void mySetType(String type) {
type = type.substring(ID.length());
SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(type, ';');
commandName = st.nextToken("Global Command");
key = st.nextNamedKeyStroke('G');
globalKey = st.nextNamedKeyStroke('K');
propertiesFilter.setExpression(st.nextToken(""));
restrictRange = st.nextBoolean(false);
range = st.nextInt(1);
globalCommand.setReportSingle(st.nextBoolean(true));
globalCommand.setKeyStroke(globalKey);
fixedRange = st.nextBoolean(true);
rangeProperty = st.nextToken("");
description = st.nextToken("");
globalCommand.setSelectFromDeck(st.nextInt(-1));
command = null;
}
public String myGetType() {
SequenceEncoder se = new SequenceEncoder(';');
se.append(commandName)
.append(key)
.append(globalKey)
.append(propertiesFilter.getExpression())
.append(restrictRange)
.append(range)
.append(globalCommand.isReportSingle())
.append(fixedRange)
.append(rangeProperty)
.append(description)
.append(globalCommand.getSelectFromDeck());
return ID + se.getValue();
}
protected KeyCommand[] myGetKeyCommands() {
if (command == null) {
myCommand = new KeyCommand(commandName, key, Decorator.getOutermost(this), this);
if (commandName.length() > 0 && key != null && ! key.isNull()) {
command = new KeyCommand[]{ myCommand };
}
else {
command = new KeyCommand[0];
}
}
if (command.length > 0) {
command[0].setEnabled(getMap() != null);
}
return command;
}
public String myGetState() {
return "";
}
public Command myKeyEvent(KeyStroke stroke) {
myGetKeyCommands();
return myCommand.matches(stroke) ? apply() : null;
}
public void mySetState(String newState) {
}
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();
}
public PieceEditor getEditor() {
return new Ed(this);
}
public String getDescription() {
String d = "Global Key Command";
if (description.length() > 0) {
d += " - " + description;
}
return d;
}
public HelpFile getHelpFile() {
return HelpFile.getReferenceManualPage("GlobalKeyCommand.htm");
}
public Command apply() {
PieceFilter filter = propertiesFilter.getFilter(Decorator.getOutermost(this));
Command c = new NullCommand();
if (restrictRange) {
int r = range;
if (!fixedRange) {
String rangeValue = (String) Decorator.getOutermost(this).getProperty(rangeProperty);
try {
r = Integer.parseInt(rangeValue);
}
catch (NumberFormatException e) {
reportDataError(this, Resources.getString("Error.non_number_error"), "range["+rangeProperty+"]="+rangeValue, e);
}
}
filter = new BooleanAndPieceFilter(filter,new RangeFilter(getMap(), getPosition(), r));
}
for (Map m : Map.getMapList()) {
c = c.append(globalCommand.apply(m, filter));
}
return c;
}
public PieceI18nData getI18nData() {
return getI18nData(commandName, getCommandDescription(description, "Command name"));
}
public static class Ed implements PieceEditor {
protected StringConfigurer nameInput;
protected NamedHotKeyConfigurer keyInput;
protected NamedHotKeyConfigurer globalKey;
protected PropertyExpressionConfigurer propertyMatch;
protected MassKeyCommand.DeckPolicyConfig deckPolicy;
protected BooleanConfigurer suppress;
protected BooleanConfigurer restrictRange;
protected BooleanConfigurer fixedRange;
protected IntConfigurer range;
protected StringConfigurer rangeProperty;
protected StringConfigurer descInput;
protected JPanel controls;
public Ed(CounterGlobalKeyCommand p) {
PropertyChangeListener pl = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
boolean isRange = Boolean.TRUE.equals(restrictRange.getValue());
boolean isFixed = Boolean.TRUE.equals(fixedRange.getValue());
range.getControls().setVisible(isRange && isFixed);
fixedRange.getControls().setVisible(isRange);
rangeProperty.getControls().setVisible(isRange && !isFixed);
Window w = SwingUtilities.getWindowAncestor(range.getControls());
if (w != null) {
w.pack();
}
}
};
controls = new JPanel();
controls.setLayout(new BoxLayout(controls, BoxLayout.Y_AXIS));
descInput = new StringConfigurer(null, "Description: ", p.description);
controls.add(descInput.getControls());
nameInput = new StringConfigurer(null, "Command name: ", p.commandName);
controls.add(nameInput.getControls());
keyInput = new NamedHotKeyConfigurer(null, "Keyboard Command: ", p.key);
controls.add(keyInput.getControls());
globalKey = new NamedHotKeyConfigurer(null, "Global Key Command: ", p.globalKey);
controls.add(globalKey.getControls());
propertyMatch = new PropertyExpressionConfigurer(null, "Matching Properties: ", p.propertiesFilter);
controls.add(propertyMatch.getControls());
deckPolicy = new MassKeyCommand.DeckPolicyConfig();
deckPolicy.setValue(p.globalCommand.getSelectFromDeck());
controls.add(deckPolicy.getControls());
restrictRange = new BooleanConfigurer(null, "Restrict Range?", p.restrictRange);
controls.add(restrictRange.getControls());
restrictRange.addPropertyChangeListener(pl);
fixedRange = new BooleanConfigurer(null, "Fixed Range?", p.fixedRange);
controls.add(fixedRange.getControls());
fixedRange.addPropertyChangeListener(pl);
range = new IntConfigurer(null, "Range: ", p.range);
controls.add(range.getControls());
rangeProperty = new StringConfigurer(null, "Range Property: ", p.rangeProperty);
controls.add(rangeProperty.getControls());
suppress = new BooleanConfigurer(null, "Suppress individual reports?", p.globalCommand.isReportSingle());
controls.add(suppress.getControls());
pl.propertyChange(null);
}
public Component getControls() {
return controls;
}
public String getType() {
SequenceEncoder se = new SequenceEncoder(';');
se.append(nameInput.getValueString())
.append(keyInput.getValueString())
.append(globalKey.getValueString())
.append(propertyMatch.getValueString())
.append(restrictRange.getValueString())
.append(range.getValueString())
.append(suppress.booleanValue().booleanValue())
.append(fixedRange.booleanValue().booleanValue())
.append(rangeProperty.getValueString())
.append(descInput.getValueString())
.append(deckPolicy.getIntValue());
return ID + se.getValue();
}
public String getState() {
return "";
}
}
// Implement Loopable
public String getComponentName() {
// Use inner name to prevent recursive looping when reporting errors.
return piece.getName();
}
public String getComponentTypeName() {
return getDescription();
}
}