/*
* $Id: Embellishment0.java 8282 2012-08-21 00:05:59Z swampwallaby $
*
* Copyright (c) 2000-2012 by Brent Easton, 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.GridLayout;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.geom.Area;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.event.ListSelectionListener;
import VASSAL.build.GameModule;
import VASSAL.build.module.documentation.HelpFile;
import VASSAL.command.ChangeTracker;
import VASSAL.command.Command;
import VASSAL.configure.BooleanConfigurer;
import VASSAL.configure.HotKeyConfigurer;
import VASSAL.configure.IntConfigurer;
import VASSAL.configure.KeyModifiersConfigurer;
import VASSAL.configure.StringConfigurer;
import VASSAL.i18n.PieceI18nData;
import VASSAL.i18n.Resources;
import VASSAL.i18n.TranslatablePiece;
import VASSAL.tools.FormattedString;
import VASSAL.tools.SequenceEncoder;
import VASSAL.tools.image.ImageUtils;
import VASSAL.tools.imageop.ImageOp;
import VASSAL.tools.imageop.ScaledImagePainter;
/**
*
* Embellishment has been extensively re-written for Vassal 3.2 changing
* both the behavior and the visual look of the configurer. A version
* number has been added to distinguish between the two versions.
* Note, there is also a much older Embellishment trait with a type of emb
*
* When editing a module, the old versions will be automatically converted to
* the new version. One feature (multiple keystrokes for a command) cannot
* be converted.
*
* This class contains the complete code of the original version 0
* emb2 Embellishment to support editing of unconverted version 0 Embellishments
* and run-time support for modules containing unconverted traits.
*
* This is essentially the latest 3.1 version of Embellishment
*/
public class Embellishment0 extends Decorator implements TranslatablePiece {
public static final String OLD_ID = "emb;";
public static final String ID = "emb2;"; // New type encoding
public static final String IMAGE = "_Image";
public static final String NAME = "_Name";
public static final String LEVEL = "_Level";
public static final String ACTIVE = "_Active";
protected String activateKey = "";
protected String upKey, downKey;
protected int activateModifiers, upModifiers, downModifiers;
protected String upCommand, downCommand, activateCommand;
protected String resetCommand;
protected FormattedString resetLevel = new FormattedString("1");
protected boolean loopLevels;
protected KeyStroke resetKey;
protected boolean followProperty;
protected String propertyName = "";
protected int firstLevelValue;
// random layers
// protected KeyCommand rndCommand;
protected KeyStroke rndKey;
private String rndText = "";
// end random layers
// Index of the image to draw. Negative if inactive. 0 is not a valid value.
protected int value = -1;
protected String activationStatus = "";
protected int nValues;
protected int xOff, yOff;
protected String imageName[];
protected String commonName[];
protected Rectangle size[];
protected ScaledImagePainter imagePainter[];
protected boolean drawUnderneathWhenSelected = false;
protected String name = "";
protected KeyCommand[] commands;
protected KeyCommand up = null;
protected KeyCommand down = null;
// Shape cache
protected Rectangle lastBounds = null;
protected Area lastShape = null;
public Embellishment0() {
this(ID + "Activate", null);
}
public Embellishment0(String type, GamePiece d) {
mySetType(type);
setInner(d);
}
public boolean isActive() {
return value > 0;
}
public void setActive(boolean val) {
value = val ? Math.abs(value) : -Math.abs(value);
}
public int getValue() {
return Math.abs(value) - 1;
}
/**
* Set the current level - First level = 0 Does not change the active status
*
* @param val
*/
public void setValue(int val) {
if (val >= nValues) {
throw new IllegalArgumentException();
}
value = value > 0 ? val + 1 : -val - 1;
}
public void mySetType(String s) {
if (!s.startsWith(ID)) {
originalSetType(s);
}
else {
s = s.substring(ID.length());
SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(s, ';');
activateCommand = st.nextToken("Activate");
activateModifiers = st.nextInt(InputEvent.CTRL_MASK);
activateKey = st.nextToken("A");
upCommand = st.nextToken("Increase");
upModifiers = st.nextInt(InputEvent.CTRL_MASK);
upKey = st.nextToken("]");
downCommand = st.nextToken("Decrease");
downModifiers = st.nextInt(InputEvent.CTRL_MASK);
downKey = st.nextToken("[");
resetCommand = st.nextToken("Reset");
resetKey = st.nextKeyStroke('R');
resetLevel = new FormattedString(st.nextToken("1"));
drawUnderneathWhenSelected = st.nextBoolean(false);
xOff = st.nextInt(0);
yOff = st.nextInt(0);
imageName = st.nextStringArray(0);
commonName = st.nextStringArray(imageName.length);
loopLevels = st.nextBoolean(true);
name = st.nextToken("");
// random layers
rndKey = st.nextKeyStroke(null);
rndText = st.nextToken("");
// end random layers
// Follow property value
followProperty = st.nextBoolean(false);
propertyName = st.nextToken("");
firstLevelValue = st.nextInt(1);
value = activateKey.length() > 0 ? -1 : 1;
nValues = imageName.length;
size = new Rectangle[imageName.length];
imagePainter = new ScaledImagePainter[imageName.length];
for (int i = 0; i < imageName.length; ++i) {
imagePainter[i] = new ScaledImagePainter();
imagePainter[i].setImageName(imageName[i]);
}
}
commands = null;
}
/**
* This original way of representing the type causes problems because it's not
* extensible
*
* @param s
*/
private void originalSetType(String s) {
SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(s, ';');
st.nextToken();
final SequenceEncoder.Decoder st2 =
new SequenceEncoder.Decoder(st.nextToken(), ';');
activateKey = st2.nextToken().toUpperCase();
activateModifiers = InputEvent.CTRL_MASK;
if (st2.hasMoreTokens()) {
resetCommand = st2.nextToken();
resetKey = st2.nextKeyStroke(null);
resetLevel.setFormat(st2.nextToken("0"));
}
else {
resetKey = null;
resetCommand = "";
resetLevel.setFormat("0");
}
activateCommand = st.nextToken();
drawUnderneathWhenSelected = activateCommand.startsWith("_");
if (drawUnderneathWhenSelected) {
activateCommand = activateCommand.substring(1);
}
value = activateKey.length() > 0 ? -1 : 1;
upKey = st.nextToken().toUpperCase();
upCommand = st.nextToken();
upModifiers = InputEvent.CTRL_MASK;
downKey = st.nextToken().toUpperCase();
downCommand = st.nextToken();
downModifiers = InputEvent.CTRL_MASK;
xOff = st.nextInt(0);
yOff = st.nextInt(0);
final ArrayList<String> l = new ArrayList<String>();
while (st.hasMoreTokens()) {
l.add(st.nextToken());
}
nValues = l.size();
imageName = new String[l.size()];
commonName = new String[l.size()];
size = new Rectangle[imageName.length];
imagePainter = new ScaledImagePainter[imageName.length];
for (int i = 0; i < imageName.length; ++i) {
final String sub = l.get(i);
final SequenceEncoder.Decoder subSt =
new SequenceEncoder.Decoder(sub, ',');
imageName[i] = subSt.nextToken();
imagePainter[i] = new ScaledImagePainter();
imagePainter[i].setImageName(imageName[i]);
if (subSt.hasMoreTokens()) {
commonName[i] = subSt.nextToken();
}
}
loopLevels = true;
}
public String getLocalizedName() {
return getName(true);
}
public String getName() {
return getName(false);
}
public String getName(boolean localized) {
checkPropertyLevel(); // Name Change?
String name = null;
final String cname = 0 < value && value - 1 < commonName.length ?
getCommonName(localized, value - 1) : null;
if (cname != null && cname.length() > 0) {
final SequenceEncoder.Decoder st =
new SequenceEncoder.Decoder(cname, '+');
final String first = st.nextToken();
if (st.hasMoreTokens()) {
final String second = st.nextToken();
if (first.length() == 0) {
name = (localized ? piece.getLocalizedName() : piece.getName()) + second;
}
else {
name = first + (localized ? piece.getLocalizedName() : piece.getName());
}
}
else {
name = first;
}
}
else {
name = (localized ? piece.getLocalizedName() : piece.getName());
}
return name;
}
public void mySetState(String s) {
final SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(s, ';');
value = st.nextInt(1);
activationStatus = st.nextToken(value < 0 ? "" : activateKey);
}
public String myGetType() {
final SequenceEncoder se = new SequenceEncoder(';');
se.append(activateCommand)
.append(activateModifiers)
.append(activateKey)
.append(upCommand)
.append(upModifiers)
.append(upKey)
.append(downCommand)
.append(downModifiers)
.append(downKey)
.append(resetCommand)
.append(resetKey)
.append(resetLevel.getFormat())
.append(drawUnderneathWhenSelected)
.append(xOff)
.append(yOff)
.append(imageName)
.append(commonName)
.append(loopLevels)
.append(name)
.append(rndKey) // random layers
.append(rndText) // random layers
.append(followProperty)
.append(propertyName)
.append(firstLevelValue);
return ID + se.getValue();
}
@Deprecated
public String oldGetType() {
final SequenceEncoder se = new SequenceEncoder(';');
final SequenceEncoder se2 = new SequenceEncoder(activateKey, ';');
se2.append(resetCommand)
.append(resetKey)
.append(String.valueOf(resetLevel));
se.append(se2.getValue())
.append(drawUnderneathWhenSelected ?
"_" + activateCommand : activateCommand)
.append(upKey)
.append(upCommand)
.append(downKey)
.append(downCommand)
.append(xOff)
.append(yOff);
for (int i = 0; i < nValues; ++i) {
if (commonName[i] != null) {
SequenceEncoder sub = new SequenceEncoder(imageName[i], ',');
se.append(sub.append(commonName[i]).getValue());
}
else {
se.append(imageName[i]);
}
}
return ID + se.getValue();
}
public String myGetState() {
final SequenceEncoder se = new SequenceEncoder(';');
return se.append(String.valueOf(value)).append(activationStatus).getValue();
}
public void draw(Graphics g, int x, int y, Component obs, double zoom) {
piece.draw(g, x, y, obs, zoom);
checkPropertyLevel();
if (!isActive()) {
return;
}
final int i = value - 1;
if (i < imagePainter.length && imagePainter[i] != null) {
final Rectangle r = getCurrentImageBounds();
imagePainter[i].draw(g, x + (int)(zoom*r.x), y + (int)(zoom*r.y), zoom, obs);
}
if (drawUnderneathWhenSelected &&
Boolean.TRUE.equals(getProperty(Properties.SELECTED))) {
piece.draw(g, x, y, obs, zoom);
}
}
/*
* Calculate the new level to display based on a property?
*/
protected void checkPropertyLevel() {
if (!followProperty || propertyName.length() == 0) return;
final Object propertyValue = Decorator.getOutermost(this).getProperty(propertyName);
final String val = propertyValue == null ? String.valueOf(firstLevelValue) : String.valueOf(propertyValue);
try {
int v = Integer.parseInt(val) - firstLevelValue + 1;
if (v <= 0) v = 1;
if (v > nValues) v = nValues;
value = isActive() ? v : -v;
}
catch (NumberFormatException e) {
reportDataError(this, Resources.getString("Error.non_number_error"), "followProperty["+propertyName+"]="+val, e);
}
return;
}
public KeyCommand[] myGetKeyCommands() {
if (commands == null) {
final ArrayList<KeyCommand> l = new ArrayList<KeyCommand>();
final GamePiece outer = Decorator.getOutermost(this);
if (activateCommand.length() > 0 && activateKey.length() > 0) {
final KeyCommand k = new KeyCommand(activateCommand,
KeyStroke.getKeyStroke(activateKey.charAt(0), activateModifiers),
outer, this);
k.setEnabled(nValues > 0);
l.add(k);
}
if (upCommand.length() > 0 &&
upKey.length() > 0 &&
nValues > 1 &&
!followProperty) {
up = new KeyCommand(upCommand,
KeyStroke.getKeyStroke(upKey.charAt(0), upModifiers), outer, this);
l.add(up);
}
if (downCommand.length() > 0 &&
downKey.length() > 0 &&
nValues > 1 &&
!followProperty) {
down = new KeyCommand(downCommand,
KeyStroke.getKeyStroke(downKey.charAt(0), downModifiers), outer, this);
l.add(down);
}
if (resetKey != null && resetCommand.length() > 0 && !followProperty) {
l.add(new KeyCommand(resetCommand, resetKey, outer, this));
}
// random layers
if (rndKey != null && rndText.length() > 0 && !followProperty) {
l.add(new KeyCommand(rndText, rndKey, outer, this));
}
// end random layers
commands = l.toArray(new KeyCommand[l.size()]);
}
if (up != null) {
up.setEnabled(loopLevels || Math.abs(value) < imageName.length);
}
if (down != null) {
down.setEnabled(loopLevels || Math.abs(value) > 1);
}
return commands;
}
public Command myKeyEvent(KeyStroke stroke) {
char strokeChar = getMatchingActivationChar(stroke);
ChangeTracker tracker = null;
if (strokeChar != 0 && nValues > 0) { // Do not Activate if no levels defined
tracker = new ChangeTracker(this);
int index = activationStatus.indexOf(strokeChar);
if (index < 0) {
activationStatus += strokeChar;
}
else {
String before = activationStatus.substring(0, index);
String after = activationStatus.substring(index + 1);
activationStatus = before + after;
}
if (activationStatus.length() == activateKey.length()) {
value = Math.abs(value);
}
else {
value = -Math.abs(value);
}
}
if (!followProperty) {
for (int i = 0; i < upKey.length(); ++i) {
if (KeyStroke.getKeyStroke(upKey.charAt(i), upModifiers).equals(stroke)) {
if (tracker == null) {
tracker = new ChangeTracker(this);
}
int val = Math.abs(value);
if (++val > nValues) {
val = loopLevels ? 1 : nValues;
}
value = value > 0 ? val : -val;
break;
}
}
for (int i = 0; i < downKey.length(); ++i) {
if (KeyStroke.getKeyStroke(downKey.charAt(i), downModifiers).equals(stroke)) {
if (tracker == null) {
tracker = new ChangeTracker(this);
}
int val = Math.abs(value);
if (--val < 1) {
val = loopLevels ? nValues : 1;
}
value = value > 0 ? val : -val;
break;
}
}
if (resetKey != null && resetKey.equals(stroke)) {
if (tracker == null) {
tracker = new ChangeTracker(this);
}
final GamePiece outer = Decorator.getOutermost(this);
final String levelText = resetLevel.getText(outer);
try {
final int level = Integer.parseInt(levelText);
setValue(Math.abs(level) - 1);
setActive(level > 0);
}
catch (NumberFormatException e) {
reportDataError(this, Resources.getString("Error.non_number_error"), resetLevel.debugInfo(levelText, "resetLevel"), e);
}
}
// random layers
if (rndKey != null && rndKey.equals(stroke)) {
if (tracker == null) {
tracker = new ChangeTracker(this);
}
int val = 0;
val = GameModule.getGameModule().getRNG().nextInt(nValues) + 1;
value = value > 0 ? val : -val;
}
}
// end random layers
return tracker != null ? tracker.getChangeCommand() : null;
}
private char getMatchingActivationChar(KeyStroke stroke) {
for (int i = 0; i < activateKey.length(); ++i) {
if (stroke != null && stroke.equals(KeyStroke.getKeyStroke(activateKey.charAt(i), activateModifiers))) {
return activateKey.charAt(i);
}
}
return (char) 0;
}
/** @deprecated Use {@link ImageOp.getImage} instead. */
@Deprecated
protected Image getCurrentImage() throws java.io.IOException {
// nonpositive value means that layer is inactive
// null or empty imageName[value-1] means that this layer has no image
if (value <= 0 ||
imageName[value-1] == null ||
imageName[value-1].length() == 0 ||
imagePainter[value-1] == null ||
imagePainter[value-1].getSource() == null) return null;
return imagePainter[value-1].getSource().getImage();
}
public Rectangle boundingBox() {
final Rectangle r = piece.boundingBox();
if (value > 0) r.add(getCurrentImageBounds());
return r;
}
public Rectangle getCurrentImageBounds() {
if (value > 0) {
final int i = value - 1;
if (i >= size.length) {
// Occurs when adding a layer with a name, but no image
return new Rectangle();
}
if (size[i] == null) {
if (imagePainter[i] != null) {
size[i] = ImageUtils.getBounds(imagePainter[i].getImageSize());
size[i].translate(xOff, yOff);
}
else {
size[i] = new Rectangle();
}
}
return size[i];
}
else {
return new Rectangle();
}
}
/**
* Return the Shape of the counter by adding the shape of this layer to the shape of all inner traits.
* Minimize generation of new Area objects.
*/
public Shape getShape() {
final Shape innerShape = piece.getShape();
if (value > 0 && !drawUnderneathWhenSelected) {
final Rectangle r = getCurrentImageBounds();
// If the label is completely enclosed in the current counter shape, then we can just return
// the current shape
if (innerShape.contains(r.x, r.y, r.width, r.height)) {
return innerShape;
}
else {
final Area a = new Area(innerShape);
// Cache the Area object generated. Only recreate if the layer position or size has changed
if (!r.equals(lastBounds)) {
lastShape = new Area(r);
lastBounds = new Rectangle(r);
}
a.add(lastShape);
return a;
}
}
else {
return innerShape;
}
}
public String getDescription() {
String displayName = name;
if (name == null || name.length() == 0) {
if (imageName.length > 0 &&
imageName[0] != null &&
imageName[0].length() > 0) {
displayName = imageName[0];
}
}
if (displayName == null || displayName.length() == 0) {
return "Layer";
}
else {
return "Layer - " + displayName;
}
}
public Object getProperty(Object key) {
if (key.equals(name + IMAGE)) {
checkPropertyLevel();
if (value > 0) {
return imageName[Math.abs(value) - 1];
}
else
return "";
}
else if (key.equals(name + NAME)) {
checkPropertyLevel();
if (value > 0) {
return strip(commonName[Math.abs(value) - 1]);
}
else
return "";
}
else if (key.equals(name + LEVEL)) {
checkPropertyLevel();
return String.valueOf(value);
}
else if (key.equals(name + ACTIVE)) {
return String.valueOf(isActive());
}
else if (key.equals(Properties.VISIBLE_STATE)) {
String s = String.valueOf(super.getProperty(key));
if (drawUnderneathWhenSelected) {
s += getProperty(Properties.SELECTED);
}
return s;
}
return super.getProperty(key);
}
public Object getLocalizedProperty(Object key) {
if (key.equals(name + IMAGE) ||
key.equals(name + LEVEL) ||
key.equals(name + ACTIVE) ||
key.equals(Properties.VISIBLE_STATE)) {
return getProperty(key);
}
else if (key.equals(name + NAME)) {
checkPropertyLevel();
if (value > 0) {
return strip(getLocalizedCommonName(Math.abs(value) - 1));
}
else
return "";
}
return super.getLocalizedProperty(key);
}
protected String strip (String s) {
if (s == null) {
return null;
}
if (s.startsWith("+")) {
return s.substring(1);
}
if (s.endsWith("+")) {
return s.substring(0, s.length() - 1);
}
return s;
}
/** Get the name of this level (alone) */
protected String getCommonName(boolean localized, int i) {
return localized ? getLocalizedCommonName(i) : commonName[i];
}
/** Get the localized name of this level (alone) */
protected String getLocalizedCommonName(int i) {
final String name = commonName[i];
if (name == null) return null;
final String translation = getTranslation(strip(name));
if (name.startsWith("+")) {
return "+" + translation;
}
if (name.endsWith("+")) {
return translation + "+";
}
return translation;
}
public HelpFile getHelpFile() {
return HelpFile.getReferenceManualPage("Layer.htm");
}
public PieceEditor getEditor() {
return new Ed(this);
}
/**
* If the argument GamePiece contains a Layer whose "activate" command matches
* the given keystroke, and whose active status matches the boolean argument,
* return that Layer
*/
public static Embellishment getLayerWithMatchingActivateCommand(GamePiece piece, KeyStroke stroke, boolean active) {
for (Embellishment layer = (Embellishment) Decorator.getDecorator(piece, Embellishment.class); layer != null; layer = (Embellishment) Decorator
.getDecorator(layer.piece, Embellishment.class)) {
for (int i = 0; i < layer.activateKey.length(); ++i) {
if (stroke.equals(KeyStroke.getKeyStroke(layer.activateKey.charAt(i), layer.activateModifiers))) {
if (active && layer.isActive()) {
return layer;
}
else if (!active && !layer.isActive()) {
return layer;
}
break;
}
}
}
return null;
}
private static class Ed implements PieceEditor {
private MultiImagePicker images;
private JTextField activateKeyInput = new JTextField("A");
private JTextField upKeyInput = new JTextField("]");
private JTextField downKeyInput = new JTextField("[");
private JTextField activateCommand = new JTextField("Activate");
private KeyModifiersConfigurer activateModifiers = new KeyModifiersConfigurer(null, " key: ");
private JTextField upCommand = new JTextField("Increase");
private KeyModifiersConfigurer upModifiers = new KeyModifiersConfigurer(null, " key: ");
private JTextField downCommand = new JTextField("Decrease");
private KeyModifiersConfigurer downModifiers = new KeyModifiersConfigurer(null, " key: ");
// random layers
private JTextField rndCommand = new JTextField(8);
// random layers
private JTextField xOffInput = new JTextField(2);
private JTextField yOffInput = new JTextField(2);
private JTextField levelNameInput = new JTextField(8);
private JRadioButton prefix = new JRadioButton("is prefix");
private JRadioButton suffix = new JRadioButton("is suffix");
private JCheckBox alwaysActive = new JCheckBox("Always active?");
private JCheckBox drawUnderneath = new JCheckBox("Underneath when highlighted?");
private JTextField resetLevel = new JTextField(2);
private JTextField resetCommand = new JTextField(8);
private JCheckBox loop = new JCheckBox("Loop through levels?");
private HotKeyConfigurer resetKey = new HotKeyConfigurer(null, " Keyboard: ");
private JTextField name = new JTextField(8);
private JPanel controls;
private List<String> names;
private List<Integer> isPrefix;
private static final Integer NEITHER = Integer.valueOf(0);
private static final Integer PREFIX = Integer.valueOf(1);
private static final Integer SUFFIX = Integer.valueOf(2);
// random layers
private HotKeyConfigurer rndKeyConfig;
private BooleanConfigurer followConfig;
private StringConfigurer propertyConfig;
private IntConfigurer firstLevelConfig;
private Box reset1Controls, reset2Controls;
private Box rnd1Controls, rnd2Controls;
public Ed(Embellishment0 e) {
Box box;
controls = new JPanel();
controls.setLayout(new BoxLayout(controls, BoxLayout.Y_AXIS));
final Box nameControls = Box.createHorizontalBox();
nameControls.add(new JLabel("Name: "));
nameControls.add(name);
controls.add(nameControls);
final JPanel p = new JPanel();
p.setLayout(new GridLayout(5, 3));
p.add(resetKey.getControls());
activateCommand.setMaximumSize(activateCommand.getPreferredSize());
p.add(activateCommand);
p.add(activateModifiers.getControls());
p.add(activateKeyInput);
upCommand.setMaximumSize(upCommand.getPreferredSize());
p.add(upCommand);
p.add(upModifiers.getControls());
p.add(upKeyInput);
downCommand.setMaximumSize(downCommand.getPreferredSize());
p.add(downCommand);
p.add(downModifiers.getControls());
p.add(downKeyInput);
reset1Controls = Box.createHorizontalBox();
reset1Controls.add(new JLabel("Reset to level: "));
reset1Controls.add(resetLevel);
p.add(reset1Controls);
reset2Controls = Box.createHorizontalBox();
reset2Controls.add(new JLabel(" Command: "));
reset2Controls.add(resetCommand);
p.add(reset2Controls);
p.add(resetKey.getControls());
// random layer
rnd1Controls = Box.createHorizontalBox();
rnd1Controls.add(new JLabel("Randomize: "));
p.add(rnd1Controls);
rnd2Controls = Box.createHorizontalBox();
rnd2Controls.add(new JLabel(" Command: "));
rndCommand = new JTextField(12);
rndCommand.setMaximumSize(rndCommand.getPreferredSize());
rndCommand.setText(e.rndText);
rnd2Controls.add(rndCommand);
p.add(rnd2Controls);
rndKeyConfig = new HotKeyConfigurer(null, " Keyboard: ", e.rndKey);
p.add(rndKeyConfig.getControls());
// end random layer
box = Box.createVerticalBox();
alwaysActive.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
if (alwaysActive.isSelected()) {
activateCommand.setText("");
activateKeyInput.setText("");
activateCommand.setEnabled(false);
activateKeyInput.setEnabled(false);
}
else {
activateCommand.setText("Activate");
activateKeyInput.setText("A");
activateCommand.setEnabled(true);
activateKeyInput.setEnabled(true);
}
}
});
final JPanel checkBoxes = new JPanel();
checkBoxes.setLayout(new GridLayout(3, 2));
checkBoxes.add(alwaysActive);
checkBoxes.add(drawUnderneath);
checkBoxes.add(loop);
box.add(checkBoxes);
box.add(p);
final Box offsetControls = Box.createHorizontalBox();
xOffInput.setMaximumSize(xOffInput.getPreferredSize());
xOffInput.setText("0");
yOffInput.setMaximumSize(xOffInput.getPreferredSize());
yOffInput.setText("0");
offsetControls.add(new JLabel("Offset: "));
offsetControls.add(xOffInput);
offsetControls.add(new JLabel(","));
offsetControls.add(yOffInput);
checkBoxes.add(offsetControls);
followConfig = new BooleanConfigurer(null, "Levels follow Property Value?");
checkBoxes.add(followConfig.getControls());
final Box levelBox = Box.createHorizontalBox();
propertyConfig = new StringConfigurer(null, "Property Name: ");
levelBox.add(propertyConfig.getControls());
firstLevelConfig = new IntConfigurer(null, " Level 1 = ", e.firstLevelValue);
levelBox.add(firstLevelConfig.getControls());
checkBoxes.add(levelBox);
followConfig.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
showHideFields();
}
});
controls.add(box);
images = new MultiImagePicker();
controls.add(images);
final JPanel p2 = new JPanel();
p2.setLayout(new GridLayout(2, 2));
box = Box.createHorizontalBox();
box.add(new JLabel("Level Name: "));
levelNameInput.setMaximumSize(levelNameInput.getPreferredSize());
levelNameInput.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent evt) {
changeLevelName();
}
});
box.add(levelNameInput);
p2.add(box);
box = Box.createHorizontalBox();
prefix.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (prefix.isSelected()) {
suffix.setSelected(false);
}
changeLevelName();
}
});
suffix.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (suffix.isSelected()) {
prefix.setSelected(false);
}
changeLevelName();
}
});
box.add(prefix);
box.add(suffix);
p2.add(box);
JButton b = new JButton("Add Level");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
names.add(null);
isPrefix.add(null);
images.addEntry();
}
});
p2.add(b);
b = new JButton("Remove Level");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
final int index = images.getList().getSelectedIndex();
if (index >= 0) {
names.remove(index);
isPrefix.remove(index);
images.removeEntryAt(index);
}
}
});
p2.add(b);
controls.add(p2);
images.getList().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
updateLevelName();
}
});
reset(e);
}
/*
* Change visibility of fields depending on the Follow Property setting
*/
protected void showHideFields() {
boolean show = !followConfig.booleanValue().booleanValue();
loop.setEnabled(show);
propertyConfig.getControls().setVisible(!show);
firstLevelConfig.getControls().setVisible(!show);
reset1Controls.setVisible(show);
reset2Controls.setVisible(show);
resetKey.getControls().setVisible(show);
rnd1Controls.setVisible(show);
rnd2Controls.setVisible(show);
rndKeyConfig.getControls().setVisible(show);
upCommand.setVisible(show);
upModifiers.getControls().setVisible(show);
upKeyInput.setVisible(show);
downCommand.setVisible(show);
downModifiers.getControls().setVisible(show);
downKeyInput.setVisible(show);
}
private void updateLevelName() {
int index = images.getList().getSelectedIndex();
if (index < 0) {
levelNameInput.setText(null);
}
else {
levelNameInput.setText(names.get(index));
prefix.setSelected(PREFIX.equals(isPrefix.get(index)));
suffix.setSelected(SUFFIX.equals(isPrefix.get(index)));
}
}
private void changeLevelName() {
int index = images.getList().getSelectedIndex();
if (index >= 0) {
String s = levelNameInput.getText();
names.set(index, s);
if (prefix.isSelected()) {
isPrefix.set(index, PREFIX);
}
else if (suffix.isSelected()) {
isPrefix.set(index, SUFFIX);
}
else {
isPrefix.set(index, NEITHER);
}
}
else if (index == 0) {
names.set(index, null);
isPrefix.set(index, NEITHER);
}
}
public String getState() {
return alwaysActive.isSelected() ? "1" : "-1";
}
public String getType() {
final SequenceEncoder se = new SequenceEncoder(';');
final ArrayList<String> imageNames = new ArrayList<String>();
final ArrayList<String> commonNames = new ArrayList<String>();
int i = 0;
for (String n : images.getImageNameList()) {
imageNames.add(n);
String commonName = names.get(i);
if (commonName != null && commonName.length() > 0) {
if (PREFIX.equals(isPrefix.get(i))) {
commonName =
new SequenceEncoder(commonName, '+').append("").getValue();
}
else if (SUFFIX.equals(isPrefix.get(i))) {
commonName =
new SequenceEncoder("", '+').append(commonName).getValue();
}
else {
commonName = new SequenceEncoder(commonName, '+').getValue();
}
}
commonNames.add(commonName);
i++;
}
try {
Integer.parseInt(xOffInput.getText());
}
catch (NumberFormatException xNAN) {
// TODO use IntConfigurer
xOffInput.setText("0");
}
try {
Integer.parseInt(yOffInput.getText());
}
catch (NumberFormatException yNAN) {
// TODO use IntConfigurer
yOffInput.setText("0");
}
se.append(activateCommand.getText())
.append(activateModifiers.getValueString())
.append(activateKeyInput.getText())
.append(upCommand.getText())
.append(upModifiers.getValueString())
.append(upKeyInput.getText())
.append(downCommand.getText())
.append(downModifiers.getValueString())
.append(downKeyInput.getText())
.append(resetCommand.getText())
.append((KeyStroke) resetKey.getValue())
.append(resetLevel.getText())
.append(drawUnderneath.isSelected())
.append(xOffInput.getText())
.append(yOffInput.getText())
.append(imageNames.toArray(new String[imageNames.size()]))
.append(commonNames.toArray(new String[commonNames.size()]))
.append(loop.isSelected())
.append(name.getText())
.append((KeyStroke) rndKeyConfig.getValue())
.append(rndCommand.getText() == null ? "" :
rndCommand.getText().trim())
.append(followConfig.getValueString())
.append(propertyConfig.getValueString())
.append(firstLevelConfig.getValueString());
return ID + se.getValue();
}
@Deprecated
public String oldgetType() {
final SequenceEncoder imageList = new SequenceEncoder(';');
int i = 0;
for (String imageName : images.getImageNameList()) {
String commonName = names.get(i);
if (names.get(i) != null && commonName != null && commonName.length() > 0) {
SequenceEncoder sub = new SequenceEncoder(imageName, ',');
if (PREFIX.equals(isPrefix.get(i))) {
commonName = new SequenceEncoder(commonName, '+').append("").getValue();
}
else if (SUFFIX.equals(isPrefix.get(i))) {
commonName = new SequenceEncoder("", '+').append(commonName).getValue();
}
else {
commonName = new SequenceEncoder(commonName, '+').getValue();
}
imageList.append(sub.append(commonName).getValue());
}
else {
imageList.append(imageName);
}
i++;
}
try {
Integer.parseInt(xOffInput.getText());
}
catch (NumberFormatException xNAN) {
// TODO use IntConfigurer
xOffInput.setText("0");
}
try {
Integer.parseInt(yOffInput.getText());
}
catch (NumberFormatException yNAN) {
yOffInput.setText("0");
}
String command = activateCommand.getText();
if (drawUnderneath.isSelected()) {
command = "_" + command;
}
final SequenceEncoder se2 =
new SequenceEncoder(activateKeyInput.getText(), ';');
se2.append(resetCommand.getText())
.append((KeyStroke) resetKey.getValue())
.append(resetLevel.getText());
final SequenceEncoder se = new SequenceEncoder(null, ';');
se.append(se2.getValue())
.append(command)
.append(upKeyInput.getText())
.append(upCommand.getText())
.append(downKeyInput.getText())
.append(downCommand.getText())
.append(xOffInput.getText())
.append(yOffInput.getText());
String type = ID + se.getValue() + ';'
+ (imageList.getValue() == null ? "" : imageList.getValue());
return type;
}
public Component getControls() {
return controls;
}
public void reset(Embellishment0 e) {
name.setText(e.name);
names = new ArrayList<String>();
isPrefix = new ArrayList<Integer>();
for (int i = 0; i < e.commonName.length; ++i) {
String s = e.commonName[i];
Integer is = NEITHER;
if (s != null && s.length() > 0) {
SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(s, '+');
String first = st.nextToken();
if (st.hasMoreTokens()) {
String second = st.nextToken();
if (first.length() == 0) {
s = second;
is = SUFFIX;
}
else {
s = first;
is = PREFIX;
}
}
else {
s = first;
}
}
names.add(s);
isPrefix.add(is);
}
alwaysActive.setSelected(e.activateKey.length() == 0);
drawUnderneath.setSelected(e.drawUnderneathWhenSelected);
loop.setSelected(e.loopLevels);
images.clear();
activateKeyInput.setText(e.activateKey);
activateCommand.setText(e.activateCommand);
activateModifiers.setValue(Integer.valueOf(e.activateModifiers));
upKeyInput.setText(e.upKey);
upCommand.setText(e.upCommand);
upModifiers.setValue(Integer.valueOf(e.upModifiers));
downKeyInput.setText(e.downKey);
downCommand.setText(e.downCommand);
downModifiers.setValue(Integer.valueOf(e.downModifiers));
resetKey.setValue(e.resetKey);
resetCommand.setText(e.resetCommand);
resetLevel.setText(e.resetLevel.getFormat());
xOffInput.setText(String.valueOf(e.xOff));
yOffInput.setText(String.valueOf(e.yOff));
images.setImageList(e.imageName);
followConfig.setValue(Boolean.valueOf(e.followProperty));
propertyConfig.setValue(e.propertyName);
// Add at least one level if none defined
if (images.getImageNameList().isEmpty()) {
names.add(null);
isPrefix.add(null);
images.addEntry();
}
updateLevelName();
showHideFields();
}
}
public PieceI18nData getI18nData() {
final PieceI18nData data = new PieceI18nData(this);
final String prefix = name.length() > 0 ? name+": " : "";
if (activateKey.length() > 0) {
data.add(activateCommand, prefix + "Activate command");
}
if (!followProperty) {
data.add(upCommand, prefix + "Increase command");
data.add(downCommand, prefix + "Decrease command");
data.add(resetCommand, prefix + "Reset command");
data.add(rndText, prefix + "Random command");
}
// Strip off prefix/suffix marker
for (int i = 0; i < commonName.length; i++) {
data.add(strip(commonName[i]), prefix + "Level " + (i+1) + " name");
}
return data;
}
}