VASSAL.build.module.GlobalOptions.java Source code

Java tutorial

Introduction

Here is the source code for VASSAL.build.module.GlobalOptions.java

Source

/*
 * $Id$
 *
 * Copyright (c) 2000-2012 by Rodney Kinney, Brent Easton
 *
 * 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.Container;
import java.awt.dnd.DragSource;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import org.apache.commons.lang.SystemUtils;

import VASSAL.build.AbstractConfigurable;
import VASSAL.build.AutoConfigurable;
import VASSAL.build.Buildable;
import VASSAL.build.Builder;
import VASSAL.build.GameModule;
import VASSAL.build.IllegalBuildException;
import VASSAL.build.module.documentation.HelpFile;
import VASSAL.build.module.map.PieceMover;
import VASSAL.configure.BooleanConfigurer;
import VASSAL.configure.Configurer;
import VASSAL.configure.ConfigurerFactory;
import VASSAL.configure.FormattedStringConfigurer;
import VASSAL.configure.IntConfigurer;
import VASSAL.configure.SingleChildInstance;
import VASSAL.configure.StringEnum;
import VASSAL.i18n.Resources;
import VASSAL.preferences.BasicPreference;
import VASSAL.preferences.BooleanPreference;
import VASSAL.preferences.DoublePreference;
import VASSAL.preferences.EnumPreference;
import VASSAL.preferences.IntegerPreference;
import VASSAL.preferences.Prefs;
import VASSAL.preferences.StringPreference;
import VASSAL.preferences.TextPreference;
import VASSAL.tools.ErrorDialog;
import VASSAL.tools.FormattedString;

public class GlobalOptions extends AbstractConfigurable {
    public static final String NON_OWNER_UNMASKABLE = "nonOwnerUnmaskable"; //$NON-NLS-1$
    public static final String PROMPT_STRING = "promptString"; //$NON-NLS-1$
    public static final String CENTER_ON_MOVE = "centerOnMove"; //$NON-NLS-1$
    public static final String MARK_MOVED = "markMoved"; //$NON-NLS-1$
    public static final String AUTO_REPORT = "autoReport"; //$NON-NLS-1$
    public static final String ALWAYS = "Always"; //$NON-NLS-1$
    public static final String NEVER = "Never"; //$NON-NLS-1$
    public static final String PROMPT = "Use Preferences Setting"; //$NON-NLS-1$
    public static final String SINGLE_WINDOW = "singleWindow"; //$NON-NLS-1$
    public static final String MAXIMUM_HEAP = "maximumHeap"; //$NON-NLS-1$
    public static final String INITIAL_HEAP = "initialHeap"; //$NON-NLS-1$
    public static final String BUG_10295 = "bug10295";

    public static final String PLAYER_NAME = "PlayerName"; //$NON-NLS-1$
    public static final String PLAYER_NAME_ALT = "playerName"; //$NON-NLS-1$
    public static final String PLAYER_SIDE = "PlayerSide"; //$NON-NLS-1$
    public static final String PLAYER_SIDE_ALT = "playerSide"; //$NON-NLS-1$
    public static final String PLAYER_ID = "PlayerId"; //$NON-NLS-1$
    public static final String PLAYER_ID_ALT = "playerId"; //$NON-NLS-1$
    public static final String PLAYER_ID_FORMAT = "playerIdFormat"; //$NON-NLS-1$

    private String promptString = "Opponents can unmask my pieces"; //$NON-NLS-1$
    private String nonOwnerUnmaskable = NEVER;
    private String centerOnMoves = ALWAYS;
    private String autoReport = ALWAYS;
    private String markMoved = NEVER;

    private Map<String, Object> properties = new HashMap<String, Object>();
    private static Map<String, Configurer> optionConfigurers = new LinkedHashMap<String, Configurer>();
    private static Properties optionInitialValues = new Properties();

    private FormattedString playerIdFormat = new FormattedString("$" + PLAYER_NAME + "$"); //$NON-NLS-1$ //$NON-NLS-2$

    private static GlobalOptions instance = new GlobalOptions();
    private boolean useSingleWindow;

    public void addTo(Buildable parent) {
        instance = this;

        final GameModule gm = GameModule.getGameModule();
        final Prefs prefs = gm.getPrefs();

        // should this moudule use a combined main window?
        final BooleanConfigurer combConf = new BooleanConfigurer(SINGLE_WINDOW,
                Resources.getString("GlobalOptions.use_combined"), //$NON-NLS-1$
                Boolean.TRUE);
        prefs.addOption(combConf);
        useSingleWindow = !Boolean.FALSE.equals(combConf.getValue());

        // the initial heap size for this module
        final IntConfigurer initHeapConf = new IntConfigurer(INITIAL_HEAP,
                Resources.getString("GlobalOptions.initial_heap"), //$NON-NLS-1$
                Integer.valueOf(256));
        prefs.addOption(initHeapConf);

        // the maximum heap size for this module
        final IntConfigurer maxHeapConf = new IntConfigurer(MAXIMUM_HEAP,
                Resources.getString("GlobalOptions.maximum_heap"), //$NON-NLS-1$
                Integer.valueOf(512));
        prefs.addOption(maxHeapConf);

        // Bug 10295: Sometimes, for unknown reasons, the native drag handler
        // fails to draw images properly on Windows. This lets the user select
        // the drag handler to use.
        if (SystemUtils.IS_OS_WINDOWS) {
            final BooleanConfigurer bug10295Conf = new BooleanConfigurer(BUG_10295,
                    Resources.getString("GlobalOptions.bug10295"), Boolean.FALSE);

            if (Boolean.TRUE.equals(bug10295Conf.getValue()) && !(PieceMover.AbstractDragHandler
                    .getTheDragHandler() instanceof PieceMover.DragHandlerNoImage)) {
                PieceMover.AbstractDragHandler.setTheDragHandler(new PieceMover.DragHandlerNoImage());
            }

            bug10295Conf.addPropertyChangeListener(new PropertyChangeListener() {
                public void propertyChange(PropertyChangeEvent e) {
                    PieceMover.AbstractDragHandler.setTheDragHandler(
                            (Boolean.TRUE.equals(e.getNewValue()) || !DragSource.isDragImageSupported())
                                    ? new PieceMover.DragHandlerNoImage()
                                    : new PieceMover.DragHandler());
                }
            });

            prefs.addOption(bug10295Conf);
        }

        validator = new SingleChildInstance(gm, getClass());
    }

    public static GlobalOptions getInstance() {
        return instance;
    }

    public boolean isUseSingleWindow() {
        return useSingleWindow;
    }

    @Deprecated
    public boolean isAveragedScaling() {
        return true;
    }

    public static String getConfigureTypeName() {
        return Resources.getString("Editor.GlobalOption.component_type"); //$NON-NLS-1$
    }

    public static class Prompt extends StringEnum {
        public String[] getValidValues(AutoConfigurable target) {
            return new String[] { ALWAYS, NEVER, PROMPT };
        }
    }

    public static class PlayerIdFormatConfig implements ConfigurerFactory {
        public Configurer getConfigurer(AutoConfigurable c, String key, String name) {
            return new FormattedStringConfigurer(key, name, new String[] { PLAYER_NAME, PLAYER_SIDE });
        }
    }

    public Class<?>[] getAllowableConfigureComponents() {
        return new Class<?>[] { StringPreference.class, TextPreference.class, EnumPreference.class,
                IntegerPreference.class, DoublePreference.class, BooleanPreference.class };
    }

    public String[] getAttributeDescriptions() {
        return new String[] { Resources.getString("Editor.GlobalOption.nonowner_unmask"), //$NON-NLS-1$
                null, Resources.getString("Editor.GlobalOption.center_moves"), //$NON-NLS-1$
                Resources.getString("Editor.GlobalOption.autoreport_moves"), //$NON-NLS-1$
                Resources.getString("Editor.GlobalOption.playerid_format") //$NON-NLS-1$
        };
    }

    public String[] getAttributeNames() {
        final ArrayList<String> attributes = new ArrayList<String>(
                Arrays.asList(NON_OWNER_UNMASKABLE, PROMPT_STRING, CENTER_ON_MOVE, AUTO_REPORT, PLAYER_ID_FORMAT));

        for (String key : properties.keySet()) {
            attributes.add(key);
        }

        return attributes.toArray(new String[attributes.size()]);
    }

    public Class<?>[] getAttributeTypes() {
        return new Class<?>[] { Prompt.class, null, Prompt.class, Prompt.class, PlayerIdFormatConfig.class };
    }

    /**
     * Components may use GlobalOptions to store generic global attributes.
     * This method registers the given key as an attribute of the GlobalOptions
     * with the given type.
     */
    public void addOption(Configurer option) {
        optionConfigurers.put(option.getKey(), option);
        Object initValue = optionInitialValues.get(option.getKey());

        if (initValue instanceof String) {
            option.setValue((String) initValue);
        }

        if (config != null) {
            ((Container) config.getControls()).add(option.getControls());
        }
    }

    public void build(Element e) {
        if (e == null)
            return;

        final NamedNodeMap nnm = e.getAttributes();
        for (int i = 0; i < nnm.getLength(); ++i) {
            final Attr att = (Attr) nnm.item(i);
            setAttribute(att.getName(), att.getValue());
        }

        for (Node n = e.getFirstChild(); n != null; n = n.getNextSibling()) {
            if (n.getNodeType() == Node.ELEMENT_NODE) {
                final Element element = (Element) n;
                if ("option".equals(element.getTagName())) { //$NON-NLS-1$
                    final String optionName = element.getAttribute("name"); //$NON-NLS-1$
                    final String value = Builder.getText(element);
                    optionInitialValues.put(optionName, value);
                    // Update the Configurer value if it is already registered
                    final Configurer config = optionConfigurers.get(optionName);
                    if (config != null) {
                        config.setValue(value);
                    }
                } else {
                    try {
                        final Buildable b = Builder.create(element);
                        b.addTo(this);
                        add(b);
                    } catch (IllegalBuildException ex) {
                        ErrorDialog.bug(ex);
                    }
                }
            }
        }
    }

    public Element getBuildElement(Document doc) {
        final Element e = super.getBuildElement(doc);
        for (Configurer c : optionConfigurers.values()) {
            final Element option = doc.createElement("option"); //$NON-NLS-1$
            option.setAttribute("name", c.getKey()); //$NON-NLS-1$
            option.appendChild(doc.createTextNode(c.getValueString()));
            e.appendChild(option);
        }
        return e;
    }

    public Configurer getConfigurer() {
        if (config == null) {
            final Configurer defaultConfig = super.getConfigurer();
            for (Configurer c : optionConfigurers.values()) {
                ((Container) defaultConfig.getControls()).add(c.getControls());
            }
        }
        return config;
    }

    public String getAttributeValueString(String key) {
        if (NON_OWNER_UNMASKABLE.equals(key)) {
            return nonOwnerUnmaskable;
        } else if (PROMPT_STRING.equals(key)) {
            return promptString;
        } else if (CENTER_ON_MOVE.equals(key)) {
            return centerOnMoves;
        } else if (AUTO_REPORT.equals(key)) {
            return autoReport;
        } else if (MARK_MOVED.equals(key)) {
            return markMoved;
        } else if (PLAYER_ID_FORMAT.equals(key)) {
            return playerIdFormat.getFormat();
        } else if (!optionConfigurers.containsKey(key)) {
            Object val = properties.get(key);
            return val != null ? val.toString() : null;
        } else {
            return null;
        }
    }

    public HelpFile getHelpFile() {
        return HelpFile.getReferenceManualPage("GlobalOptions.htm"); //$NON-NLS-1$
    }

    public void removeFrom(Buildable parent) {
    }

    public void setAttribute(String key, Object value) {
        if (NON_OWNER_UNMASKABLE.equals(key)) {
            nonOwnerUnmaskable = (String) value;
            if (ALWAYS.equals(nonOwnerUnmaskable)) {
                ObscurableOptions.getInstance().allowAll();
            } else if (NEVER.equals(nonOwnerUnmaskable)) {
                ObscurableOptions.getInstance().allowNone();
            } else if (PROMPT.equals(nonOwnerUnmaskable)) {
                ObscurableOptions.getInstance().allowSome(promptString);
                GameModule.getGameModule().getGameState().addGameComponent(ObscurableOptions.getInstance());
                GameModule.getGameModule().addCommandEncoder(ObscurableOptions.getInstance());
            }
        } else if (PROMPT_STRING.equals(key)) {
            promptString = (String) value;
            ObscurableOptions.getInstance().setPrompt(promptString);
        } else if (CENTER_ON_MOVE.equals(key)) {
            centerOnMoves = (String) value;
            if (PROMPT.equals(centerOnMoves)) {
                BooleanConfigurer config = new BooleanConfigurer(CENTER_ON_MOVE,
                        Resources.getString("GlobalOptions.center_on_move")); //$NON-NLS-1$
                GameModule.getGameModule().getPrefs().addOption(config);
            }
        } else if (AUTO_REPORT.equals(key)) {
            autoReport = (String) value;
            if (PROMPT.equals(autoReport)) {
                BooleanConfigurer config = new BooleanConfigurer(AUTO_REPORT,
                        Resources.getString("GlobalOptions.auto_report")); //$NON-NLS-1$
                GameModule.getGameModule().getPrefs().addOption(config);
            }
        } else if (MARK_MOVED.equals(key)) {
            markMoved = (String) value;
            if (PROMPT.equals(markMoved)) {
                BooleanConfigurer config = new BooleanConfigurer(MARK_MOVED,
                        Resources.getString("GlobalOptions.mark_moved")); //$NON-NLS-1$
                GameModule.getGameModule().getPrefs().addOption(config);
            }
        } else if (PLAYER_ID_FORMAT.equals(key)) {
            playerIdFormat.setFormat((String) value);
        } else if (optionConfigurers.containsKey(key)) {
            optionConfigurers.get(key).setValue(value);
        } else {
            properties.put(key, value);
        }
    }

    public boolean autoReportEnabled() {
        return isEnabled(autoReport, AUTO_REPORT);
    }

    public boolean centerOnOpponentsMove() {
        return isEnabled(centerOnMoves, CENTER_ON_MOVE);
    }

    public boolean isMarkMoveEnabled() {
        return isEnabled(markMoved, MARK_MOVED);
    }

    public String getPlayerId() {
        playerIdFormat.setProperty(PLAYER_NAME,
                (String) GameModule.getGameModule().getPrefs().getValue(GameModule.REAL_NAME));
        playerIdFormat.setProperty(PLAYER_SIDE, PlayerRoster.getMyLocalizedSide());
        return playerIdFormat.getText();
    }

    private boolean isEnabled(String attValue, String prefsPrompt) {
        if (ALWAYS.equals(attValue)) {
            return true;
        } else if (NEVER.equals(attValue)) {
            return false;
        } else {
            return Boolean.TRUE.equals(GameModule.getGameModule().getPrefs().getValue(prefsPrompt));
        }
    }

    /**
     * Implement PropertyNameSource - Expose our preference names
     */
    public List<String> getPropertyNames() {
        final ArrayList<String> l = new ArrayList<String>();
        for (Buildable b : getBuildables()) {
            if (b instanceof BasicPreference) {
                l.add(((BasicPreference) b).getVariableName());
            }
        }
        return l;
    }

}