/*
* $Id$
*
* Copyright (c) 2004 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.build.module;
import java.awt.Component;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.HashMap;
import javax.swing.Box;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import VASSAL.build.AbstractConfigurable;
import VASSAL.build.BadDataReport;
import VASSAL.build.Buildable;
import VASSAL.build.Builder;
import VASSAL.build.Configurable;
import VASSAL.build.GameModule;
import VASSAL.build.GpIdSupport;
import VASSAL.build.module.documentation.HelpFile;
import VASSAL.build.module.properties.PropertySource;
import VASSAL.command.AddPiece;
import VASSAL.configure.Configurer;
import VASSAL.configure.StringConfigurer;
import VASSAL.configure.ValidationReport;
import VASSAL.configure.ValidityChecker;
import VASSAL.counters.BasicPiece;
import VASSAL.counters.Decorator;
import VASSAL.counters.GamePiece;
import VASSAL.counters.PieceDefiner;
import VASSAL.counters.PieceEditor;
import VASSAL.counters.Properties;
import VASSAL.i18n.ComponentI18nData;
import VASSAL.i18n.Resources;
import VASSAL.tools.ErrorDialog;
import VASSAL.tools.FormattedString;
import VASSAL.tools.UniqueIdManager;
public class PrototypeDefinition extends AbstractConfigurable
implements UniqueIdManager.Identifyable,
ValidityChecker {
private String name = "Prototype"; //$NON-NLS-1$
private java.util.Map<String,GamePiece> pieces =
new HashMap<String,GamePiece>();
private String pieceDefinition;
private static UniqueIdManager idMgr = new UniqueIdManager("prototype-"); //$NON-NLS-1$
private PropertyChangeSupport propSupport = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener l) {
propSupport.addPropertyChangeListener(l);
}
public Class<?>[] getAllowableConfigureComponents() {
return new Class<?>[0];
}
public Configurable[] getConfigureComponents() {
return new Configurable[0];
}
public String getConfigureName() {
return name;
}
public void setConfigureName(String s) {
String oldName = name;
this.name = s;
propSupport.firePropertyChange(NAME_PROPERTY, oldName, name);
}
public Configurer getConfigurer() {
return new Config(this);
}
public HelpFile getHelpFile() {
return HelpFile.getReferenceManualPage("GameModule.htm", "Definition"); //$NON-NLS-1$ //$NON-NLS-2$
}
public void remove(Buildable child) {
idMgr.remove(this);
}
public void removeFrom(Buildable parent) {
}
public void add(Buildable child) {
}
public String getId() {
return null;
}
public void setId(String id) {
}
public void validate(Buildable target, ValidationReport report) {
idMgr.validate(this, report);
}
public void addTo(Buildable parent) {
idMgr.add(this);
}
public GamePiece getPiece() {
return getPiece(pieceDefinition);
}
/**
* For the case when the piece definition is a Message Format, expand the definition using the given properties
*
* @param props
* @return
*/
public GamePiece getPiece(PropertySource props) {
String def = props == null ? pieceDefinition : new FormattedString(pieceDefinition).getText(props);
return getPiece(def);
}
protected GamePiece getPiece(String def) {
GamePiece piece = pieces.get(def);
if (piece == null && def != null) {
try {
final AddPiece comm = (AddPiece) GameModule.getGameModule().decode(def);
if (comm == null) {
ErrorDialog.dataError(new BadDataReport("Couldn't build piece ",def,null)); //$NON-NLS-1$
}
else {
piece = comm.getTarget();
piece.setState(comm.getState());
}
}
catch (RuntimeException e) {
ErrorDialog.dataError(new BadDataReport("Couldn't build piece",def,e));
}
}
return piece;
}
public void setPiece(GamePiece p) {
pieceDefinition = p == null ? null : GameModule.getGameModule().encode(new AddPiece(p));
pieces.clear();
}
public void build(Element e) {
if (e != null) {
setConfigureName(e.getAttribute(NAME_PROPERTY));
pieceDefinition = Builder.getText(e);
}
}
public Element getBuildElement(Document doc) {
Element el = doc.createElement(getClass().getName());
el.setAttribute(NAME_PROPERTY, name);
el.appendChild(doc.createTextNode(pieceDefinition));
return el;
}
public static String getConfigureTypeName() {
return Resources.getString("Editor.Prototype.component_type"); //$NON-NLS-1$
}
public static class Config extends Configurer {
private Box box;
private PieceDefiner pieceDefiner;
private StringConfigurer name;
private PrototypeDefinition def;
public Config(PrototypeDefinition def) {
super(null, null, def);
box = Box.createVerticalBox();
name = new StringConfigurer(null, Resources.getString(Resources.NAME_LABEL), def.name);
box.add(name.getControls());
pieceDefiner = new Definer(GameModule.getGameModule().getGpIdSupport());
pieceDefiner.setPiece(def.getPiece());
box.add(pieceDefiner);
this.def = def;
}
public Object getValue() {
if (def != null) {
def.setPiece(pieceDefiner.getPiece());
def.setConfigureName(name.getValueString());
}
return def;
}
public Component getControls() {
return box;
}
public String getValueString() {
return null;
}
public void setValue(String s) {
}
public static class Definer extends PieceDefiner {
private static final long serialVersionUID = 1L;
public Definer(GpIdSupport s) {
super(s);
}
public void setPiece(GamePiece piece) {
if (piece != null) {
GamePiece inner = Decorator.getInnermost(piece);
if (!(inner instanceof Plain)) {
Plain plain = new Plain();
Object outer = inner.getProperty(Properties.OUTER);
if (outer instanceof Decorator) {
((Decorator) outer).setInner(plain);
}
piece = Decorator.getOutermost(plain);
}
}
else {
piece = new Plain();
}
super.setPiece(piece);
}
protected void removeTrait(int index) {
if (index > 0) {
super.removeTrait(index);
}
}
private static class Plain extends BasicPiece {
public Plain() {
super(ID + ";;;;"); //$NON-NLS-1$
}
public String getDescription() {
return ""; //$NON-NLS-1$
}
public PieceEditor getEditor() {
return null;
}
}
}
}
/*
* Implement Translatable - Since PrototypeDefinition implements its
* own configurer, methods below here will only ever be called by the
* translation subsystem.
*/
public void setAttribute(String attr, Object value) {
}
public String[] getAttributeDescriptions() {
return new String[0];
}
public Class<?>[] getAttributeTypes() {
return new Class<?>[0];
}
public String[] getAttributeNames() {
return new String[0];
}
/*
* Redirect getAttributeValueString() to return the attribute
* values for the enclosed pieces
*/
public String getAttributeValueString(String attr) {
return getI18nData().getLocalUntranslatedValue(attr);
}
public ComponentI18nData getI18nData() {
/*
* Prototype definition may change due to editing, so no caching
*/
return new ComponentI18nData(this, getPiece());
}
}