com.t3.model.MacroButtonProperties.java Source code

Java tutorial

Introduction

Here is the source code for com.t3.model.MacroButtonProperties.java

Source

/*
 * Copyright (c) 2014 tabletoptool.com team.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     rptools.com team - initial implementation
 *     tabletoptool.com team - further development
 */
package com.t3.model;

import groovy.lang.Script;

import java.awt.Color;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.t3.client.AppPreferences;
import com.t3.client.T3MacroContext;
import com.t3.client.T3Util;
import com.t3.client.TabletopTool;
import com.t3.client.ui.MacroButtonHotKeyManager;
import com.t3.client.ui.macrobuttons.buttons.MacroButton;
import com.t3.client.ui.macrobuttons.buttons.MacroButtonPrefs;
import com.t3.macro.MacroEngine;
import com.t3.macro.MacroException;
import com.t3.model.chat.TextMessage;
import com.t3.util.StringUtil;
import com.t3.xstreamversioned.version.SerializationVersion;

/**
 * This (data)class is used by all Macro Buttons, including campaign, global and token macro buttons.
 * 
 * @see com.t3.client.ui.macrobuttons.buttons.MacroButton
 */
@SerializationVersion(0)
public class MacroButtonProperties implements Comparable<MacroButtonProperties> {

    private static final Logger log = Logger.getLogger(MacroButtonProperties.class);

    //   private transient static final List<String> HTMLColors = Arrays.asList("aqua", "black", "blue", "fuchsia", "gray", "green", "lime", "maroon", "navy", "olive", "purple", "red", "silver", "teal",
    //         "white", "yellow");
    private transient MacroButton button;
    private transient Token token;
    private String saveLocation;
    private int index;
    private String colorKey;
    private String hotKey;
    private String command;
    private String label;
    private String group;
    private String sortby;
    private String fontColorKey;
    private String fontSize;
    private String minWidth;
    private String maxWidth;
    private boolean allowPlayerEdits = true;
    private String toolTip;
    /**this will be automatically generated from the command string whenever it is changed */
    private transient Script compiledCommand;

    // constructor that creates a new instance, doesn't auto-save
    public MacroButtonProperties(int index, String colorKey, String hotKey, String command, String label,
            String group, String sortby, String fontColorKey, String fontSize, String minWidth, String maxWidth,
            String toolTip) {
        setIndex(index);
        setColorKey(colorKey);
        setHotKey(hotKey);
        setCommand(command);
        setLabel(label);
        setGroup(group);
        setSortby(sortby);
        setFontColorKey(fontColorKey);
        setFontSize(fontSize);
        setMinWidth(minWidth);
        setMaxWidth(maxWidth);
        setButton(null);
        setToken(null);
        setSaveLocation("");
        setAllowPlayerEdits(AppPreferences.getAllowPlayerMacroEditsDefault());
        setCompareGroup(true);
        setCompareSortPrefix(true);
        setCompareCommand(true);
        setToolTip(toolTip);
    }

    // constructor that creates a new instance, doesn't auto save
    public MacroButtonProperties(int index) {
        setIndex(index);
        setColorKey("");
        setHotKey(MacroButtonHotKeyManager.HOTKEYS[0]);
        setCommand("");
        setLabel("(new)");
        setGroup("");
        setSortby("");
        setFontColorKey("");
        setFontSize("");
        setMinWidth("");
        setMaxWidth("");
        setButton(null);
        setToken(null);
        setSaveLocation("");
        setAllowPlayerEdits(AppPreferences.getAllowPlayerMacroEditsDefault());
        setCompareGroup(true);
        setCompareSortPrefix(true);
        setCompareCommand(true);
        setToolTip(null);
    }

    // constructor for creating a new button in a specific button group, auto-saves
    public MacroButtonProperties(String panelClass, int index, String group) {
        this(index);
        setSaveLocation(panelClass);
        setGroup(group);
        setAllowPlayerEdits(AppPreferences.getAllowPlayerMacroEditsDefault());
        setCompareGroup(true);
        setCompareSortPrefix(true);
        setCompareCommand(true);
        setToolTip(null);
        save();
    }

    // constructor for creating a new token button in a specific button group, auto-saves
    public MacroButtonProperties(Token token, int index, String group) {
        this(index);
        setSaveLocation("Token");
        setToken(token);
        setGroup(group);
        setAllowPlayerEdits(AppPreferences.getAllowPlayerMacroEditsDefault());
        setCompareGroup(true);
        setCompareSortPrefix(true);
        setCompareCommand(true);
        setToolTip(null);
        save();
    }

    // constructor for creating a new copy of an existing button, auto-saves
    public MacroButtonProperties(String panelClass, int index, MacroButtonProperties properties) {
        this(index);
        setSaveLocation(panelClass);
        setColorKey(properties.getColorKey());
        // use the default hot key
        setCommand(properties.getCommand());
        setLabel(properties.getLabel());
        setGroup(properties.getGroup());
        setSortby(properties.getSortby());
        setFontColorKey(properties.getFontColorKey());
        setFontSize(properties.getFontSize());
        setMinWidth(properties.getMinWidth());
        setMaxWidth(properties.getMaxWidth());
        setAllowPlayerEdits(properties.getAllowPlayerEdits());
        setCompareGroup(properties.getCompareGroup());
        setCompareSortPrefix(properties.getCompareSortPrefix());
        setCompareCommand(properties.getCompareCommand());
        String tt = properties.getToolTip();
        setToolTip(tt);
        save();
    }

    // constructor for creating a new copy of an existing token button, auto-saves
    public MacroButtonProperties(Token token, int index, MacroButtonProperties properties) {
        this(index);
        setSaveLocation("Token");
        setToken(token);
        setColorKey(properties.getColorKey());
        // use the default hot key
        setCommand(properties.getCommand());
        setLabel(properties.getLabel());
        setGroup(properties.getGroup());
        setSortby(properties.getSortby());
        setFontColorKey(properties.getFontColorKey());
        setFontSize(properties.getFontSize());
        setMinWidth(properties.getMinWidth());
        setMaxWidth(properties.getMaxWidth());
        setAllowPlayerEdits(properties.getAllowPlayerEdits());
        setCompareGroup(properties.getCompareGroup());
        setCompareSortPrefix(properties.getCompareSortPrefix());
        setCompareCommand(properties.getCompareCommand());
        String tt = properties.getToolTip();
        setToolTip(tt);
        save();
    }

    // constructor for creating common macro buttons on selection panel
    public MacroButtonProperties(int index, MacroButtonProperties properties) {
        this(index);
        setToken((Token) null);
        setColorKey(properties.getColorKey());
        // use the default hot key
        setCommand(properties.getCommand());
        setLabel(properties.getLabel());
        setGroup(properties.getGroup());
        setSortby(properties.getSortby());
        setFontColorKey(properties.getFontColorKey());
        setFontSize(properties.getFontSize());
        setMinWidth(properties.getMinWidth());
        setMaxWidth(properties.getMaxWidth());
        setAllowPlayerEdits(properties.getAllowPlayerEdits());
        setCompareGroup(properties.getCompareGroup());
        setCompareSortPrefix(properties.getCompareSortPrefix());
        setCompareCommand(properties.getCompareCommand());
        setToolTip(properties.getToolTip());
        commonMacro = true;
    }

    public MacroButtonProperties(Token token, Map<String, String> props) {
        this(props.containsKey("index") ? Integer.parseInt(props.get("index")) : token.getMacroNextIndex());
        setToken(token);
        if (props.containsKey("saveLocation"))
            setSaveLocation(props.get("saveLocation"));
        if (props.containsKey("colorKey"))
            setColorKey(props.get("colorKey"));
        if (props.containsKey("hotKey"))
            setHotKey(props.get("hotKey"));
        if (props.containsKey("command"))
            setCommand(props.get("command"));
        if (props.containsKey("label"))
            setLabel(props.get("label"));
        if (props.containsKey("group"))
            setGroup(props.get("group"));
        if (props.containsKey("sortby"))
            setSortby(props.get("sortby"));
        if (props.containsKey("fontColorKey"))
            setFontColorKey(props.get("fontColorKey"));
        if (props.containsKey("fontSize"))
            setFontSize(props.get("fontSize"));
        if (props.containsKey("minWidth"))
            setMinWidth(props.get("minWidth"));
        if (props.containsKey("maxWidth"))
            setMaxWidth(props.get("maxWidth"));
        if (props.containsKey("allowPlayerEdits"))
            setAllowPlayerEdits(Boolean.valueOf(props.get("allowPlayerEdits")));
        if (props.containsKey("toolTip"))
            setToolTip(props.get("toolTip"));
        if (props.containsKey("commonMacro"))
            setCommonMacro(Boolean.valueOf(props.get("commonMacro")));
        if (props.containsKey("compareGroup"))
            setCompareGroup(Boolean.valueOf(props.get("compareGroup")));
        if (props.containsKey("compareSortPrefix"))
            setCompareSortPrefix(Boolean.valueOf(props.get("compareSortPrefix")));
        if (props.containsKey("compareCommand"))
            setCompareCommand(Boolean.valueOf(props.get("compareCommand")));
    }

    public void save() {
        if (saveLocation.equals("Token") && token != null) {
            getToken().saveMacroButtonProperty(this);
        } else if (saveLocation.equals("GlobalPanel")) {
            MacroButtonPrefs.savePreferences(this);
        } else if (saveLocation.equals("CampaignPanel")) {
            TabletopTool.getCampaign().saveMacroButtonProperty(this);
        }
    }

    public void executeMacro() {
        executeCommand(token);
    }

    /**
     * The top level method for executing macros with the given list of tokens as context. In essence, this method calls
     * the macro once for each token, and the token becomes the "impersonated" token for the duration of the macro
     * barring any use of the <b>token()</b> or <b>switchToken()</b> roll options inside the macro itself.
     * 
     * @param tokenList
     */
    public void executeMacro(Collection<Token> tokenList) {
        if (tokenList == null || tokenList.size() == 0) {
            executeCommand();
        } else if (commonMacro) {
            executeCommonMacro(tokenList);
        } else {
            for (Token token : tokenList)
                executeCommand(token);
        }
    }

    private void executeCommonMacro(Collection<Token> tokenList) {
        if (compareCommand) {
            for (Token token : tokenList) {
                executeCommand(token, null);
            }
        } else {
            // We need to find the "matching" button for each token and ensure to run that one.
            for (Token nextToken : tokenList) {
                for (MacroButtonProperties nextMacro : nextToken.getMacroList(true)) {
                    if (nextMacro.hashCodeForComparison() == hashCodeForComparison()) {
                        nextMacro.executeCommand(nextToken);
                    }
                }
            }
        }
    }

    private void executeCommand(Token token) {
        if (getCommand() != null)
            executeCommand(token, null);
    }

    private void executeCommand() {
        executeCommand(null, null);
    }

    public Object executeMacro(Token token) {
        return executeCommand(token, null);
    }

    private Object executeCommand(Token contextToken, Map<String, Object> arguments) {
        String loc;
        Object o = null;

        boolean trusted = false;
        if (saveLocation.equals("CampaignPanel") || !allowPlayerEdits) {
            trusted = true;
        }
        if (saveLocation.equals("GlobalPanel")) {
            loc = "global";
            trusted = TabletopTool.getPlayer().isGM();
        } else if (saveLocation.equals("CampaignPanel")) {
            loc = "campaign";
        } else if (contextToken != null) {
            loc = "Token:" + contextToken.getName();
        } else {
            loc = "chat";
        }

        T3MacroContext newMacroContext = new T3MacroContext(label, loc, trusted, index);
        try {
            if (compiledCommand == null)
                compileCommand();
            if (compiledCommand != null)
                o = MacroEngine.getInstance().run(compiledCommand, arguments, contextToken, newMacroContext);
        } catch (MacroException e) {
            log.error("Error while trying to execute a macro from button", e);
            TabletopTool.addMessage(TextMessage.me(e.getHTMLErrorMessage()));
        }

        TabletopTool.getFrame().getCommandPanel().getCommandTextArea().requestFocusInWindow();
        return o;
    }

    private void compileCommand() throws MacroException {
        if (command != null && !StringUtils.isEmpty(command))
            this.compiledCommand = MacroEngine.getInstance().compile(command);
    }

    public Token getToken() {
        return token;
    }

    public void setToken(Token token) {
        this.token = token;
    }

    public void setSaveLocation(String saveLocation) {
        if (saveLocation.equals("ImpersonatePanel") || saveLocation.equals("SelectionPanel")) {
            this.saveLocation = "Token";
        } else {
            this.saveLocation = saveLocation;
        }
    }

    public void setButton(MacroButton button) {
        this.button = button;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public String getColorKey() {
        if (colorKey == null || colorKey.equals("")) {
            return "default";
        }
        return colorKey;
    }

    public void setColorKey(String colorKey) {
        if (T3Util.getColor(colorKey) != null)
            this.colorKey = colorKey;
    }

    public String getHotKey() {
        return hotKey;
    }

    public void setHotKey(String hotKey) {
        this.hotKey = hotKey;
    }

    public String getCommand() {
        return command;
    }

    public void setCommand(String command) {
        try {
            this.command = command;
            compileCommand();
        } catch (MacroException e) {
            //TODO replace this with a better error dialog
            TabletopTool.showError("This script you tried to save is not valid.", e);
        }
    }

    public String getLabel() {
        return (label == null ? "" : label);
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public String getGroup() {
        return (group == null ? "" : group);
    }

    public String getGroupForDisplay() {
        return this.group;
    }

    public void setGroup(String group) {
        this.group = group;
    }

    public String getSortby() {
        return (sortby == null ? "" : sortby);
    }

    public void setSortby(String sortby) {
        this.sortby = sortby;
    }

    public static String[] getFontColors() {
        //      return (String[]) HTMLColors.toArray();
        String[] array = T3Util.getColorNames().toArray(new String[0]);
        return array;
    }

    /**
     * Returns the font color of this button as an HTML string. It might be one of the 16 colors defined by the W3C as a
     * standard HTML color (see <code>COLOR_MAP_HTML</code> for a list), but if it's not then the color is converted to
     * CSS format <b>#FF00FF</b> format and that string is returned.
     * 
     * @return
     */
    public String getFontColorAsHtml() {
        Color c = null;
        String font = getFontColorKey();
        if (T3Util.isHtmlColor(font)) {
            return font;
        }
        c = T3Util.getColor(font);
        if (c != null) {
            return "#" + Integer.toHexString(c.getRGB()).substring(2);
        }
        return "black";
    }

    public String getFontColorKey() {
        if (fontColorKey == null || StringUtil.isEmpty(fontColorKey)) {
            fontColorKey = "black";
            return fontColorKey;
        }
        Color c = T3Util.getColor(fontColorKey);
        if (c != null) {
            return fontColorKey;
        }
        return "black";
    }

    public void setFontColorKey(String fontColorKey) {
        if (T3Util.getColor(fontColorKey) != null)
            this.fontColorKey = fontColorKey;
    }

    public String getFontSize() {
        return (fontSize == null || fontSize.equals("") ? "1.00em" : fontSize);
    }

    public void setFontSize(String fontSize) {
        this.fontSize = (fontSize == null || fontSize.equals("") ? "1.00em" : fontSize);
    }

    public String getMinWidth() {
        return (minWidth == null ? "" : minWidth);
    }

    public void setMinWidth(String minWidth) {
        this.minWidth = minWidth;
    }

    public String getMaxWidth() {
        return (maxWidth == null ? "" : maxWidth);
    }

    public void setMaxWidth(String maxWidth) {
        this.maxWidth = maxWidth;
    }

    public Boolean getAllowPlayerEdits() {
        return allowPlayerEdits;
    }

    public void setAllowPlayerEdits(Boolean value) {
        allowPlayerEdits = value;
    }

    public String getSaveLocation() {
        return saveLocation;
    }

    public void setToolTip(String tt) {
        toolTip = (tt == null ? "" : tt);
    }

    public String getToolTip() {
        if (toolTip == null)
            toolTip = "";
        return toolTip;
    }

    public String getEvaluatedToolTip() {

        if (toolTip == null) {
            return "";
        }

        if (!toolTip.trim().startsWith("{") && !toolTip.trim().startsWith("[")) {
            return toolTip;
        }

        T3MacroContext context = new T3MacroContext("ToolTip", token != null ? token.getName() : "", false, index);
        if (log.isDebugEnabled()) {
            log.debug("Evaluating toolTip: "
                    + (token != null ? "for token " + token.getName() + "(" + token.getId() + ")" : "")
                    + "----------------------------------------------------------------------------------");
        }
        return TabletopTool.getParser().parseLine(token, toolTip, context);
    }

    public boolean isDuplicateMacro(String source, Token token) {
        int macroHashCode = hashCodeForComparison();
        List<MacroButtonProperties> existingMacroList = null;
        if (source.equalsIgnoreCase("CampaignPanel")) {
            existingMacroList = TabletopTool.getCampaign().getMacroButtonPropertiesArray();
        } else if (source.equalsIgnoreCase("GlobalPanel")) {
            existingMacroList = MacroButtonPrefs.getButtonProperties();
        } else if (token != null) {
            existingMacroList = token.getMacroList(false);
        } else {
            return false;
        }
        for (MacroButtonProperties existingMacro : existingMacroList) {
            if (existingMacro.hashCodeForComparison() == macroHashCode) {
                return true;
            }
        }
        return false;
    }

    public void reset() {
        colorKey = "default";
        hotKey = MacroButtonHotKeyManager.HOTKEYS[0];
        command = "";
        compiledCommand = null;
        label = String.valueOf(index);
        group = "";
        sortby = "";
        fontColorKey = "black";
        fontSize = "";
        minWidth = "";
        maxWidth = "";
        toolTip = "";
    }

    //TODO: may have to rewrite hashcode and equals to only take index into account
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        MacroButtonProperties that = (MacroButtonProperties) o;

        if (index != that.index) {
            return false;
        }
        if (colorKey != null ? !colorKey.equals(that.colorKey) : that.colorKey != null) {
            return false;
        }
        if (command != null ? !command.equals(that.command) : that.command != null) {
            return false;
        }
        if (hotKey != null ? !hotKey.equals(that.hotKey) : that.hotKey != null) {
            return false;
        }
        if (label != null ? !label.equals(that.label) : that.label != null) {
            return false;
        }
        if (group != null ? !group.equals(that.group) : that.group != null) {
            return false;
        }
        if (sortby != null ? !sortby.equals(that.sortby) : that.sortby != null) {
            return false;
        }
        if (fontColorKey != null ? !fontColorKey.equals(that.fontColorKey) : that.fontColorKey != null) {
            return false;
        }
        if (fontSize != null ? !fontSize.equals(that.fontSize) : that.fontSize != null) {
            return false;
        }
        if (minWidth != null ? !minWidth.equals(that.minWidth) : that.minWidth != null) {
            return false;
        }
        if (maxWidth != null ? !maxWidth.equals(that.maxWidth) : that.maxWidth != null) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() { // modified so longest strings are at the end
        int result;
        result = index;
        result = 31 * result + (minWidth != null ? minWidth.hashCode() : 0);
        result = 31 * result + (maxWidth != null ? maxWidth.hashCode() : 0);
        result = 31 * result + (fontSize != null ? fontSize.hashCode() : 0);
        result = 31 * result + (fontColorKey != null ? fontColorKey.hashCode() : 0);
        result = 31 * result + (colorKey != null ? colorKey.hashCode() : 0);
        result = 31 * result + (hotKey != null ? hotKey.hashCode() : 0);
        result = 31 * result + (label != null ? label.hashCode() : 0);
        result = 31 * result + (group != null ? group.hashCode() : 0);
        result = 31 * result + (sortby != null ? sortby.hashCode() : 0);
        result = 31 * result + (command != null ? command.hashCode() : 0);
        return result;
    }

    // Don't include the index, so you can compare all the other properties between two macros
    // Also don't include hot key since they can't be the same anyway, or cosmetic fields
    public int hashCodeForComparison() {
        int result;
        result = 0;
        result = 31 * result + (getLabel() != null ? label.hashCode() : 0);
        result = 31 * result + (getCompareGroup() && group != null ? group.hashCode() : 0);
        result = 31 * result + (getCompareSortPrefix() && sortby != null ? sortby.hashCode() : 0);
        result = 31 * result + (getCompareCommand() && command != null ? command.hashCode() : 0);
        return result;
    }

    // function to enable sorting of buttons; uses the group first, then sortby field
    // concatenated with the label field.  Case Insensitive
    @Override
    public int compareTo(MacroButtonProperties b2) throws ClassCastException {
        if (b2 != this) {
            String b1group = getGroup();
            if (b1group == null)
                b1group = "";
            String b1sortby = getSortby();
            if (b1sortby == null)
                b1sortby = "";
            String b1label = getLabel();
            if (b1label == null)
                b1label = "";

            String b2group = b2.getGroup();
            if (b2group == null)
                b2group = "";
            String b2sortby = b2.getSortby();
            if (b2sortby == null)
                b2sortby = "";
            String b2label = b2.getLabel();
            if (b2label == null)
                b2label = "";

            // now parse the sort strings to help dice codes sort properly, use space as a separator
            String b1string = modifySortString(" " + b1group + " " + b1sortby + " " + b1label);
            String b2string = modifySortString(" " + b2group + " " + b2sortby + " " + b2label);
            return b1string.compareToIgnoreCase(b2string);
        }
        return 0;
    }

    // function to pad numbers with leading zeroes to help sort them appropriately.
    // So this will turn a 2d6 into 0002d0006, and 10d6 into 0010d0006, so the 2d6
    // will sort as lower.
    private static final Pattern sortStringPattern = Pattern.compile("(\\d+)");

    private static String modifySortString(String str) {
        StringBuffer result = new StringBuffer();
        Matcher matcher = sortStringPattern.matcher(str);
        while (matcher.find()) {
            matcher.appendReplacement(result, paddingString(matcher.group(1), 4, '0', true));
        }
        matcher.appendTail(result);
        return result.toString();
    }

    // function found at http://www.rgagnon.com/javadetails/java-0448.html
    // to pad a string by inserting additional characters
    public static String paddingString(String s, int n, char c, boolean paddingLeft) {
        StringBuffer str = new StringBuffer(s);
        int strLength = str.length();
        if (n > 0 && n > strLength) {
            for (int i = 0; i <= n; i++) {
                if (paddingLeft) {
                    if (i < n - strLength)
                        str.insert(0, c);
                } else {
                    if (i > strLength)
                        str.append(c);
                }
            }
        }
        return str.toString();
    }

    // Begin comparison customization

    private boolean commonMacro = false;
    private boolean compareGroup = true;
    private boolean compareSortPrefix = true;
    private boolean compareCommand = true;

    public boolean getCommonMacro() {
        return commonMacro;
    }

    public void setCommonMacro(boolean value) {
        commonMacro = value;
    }

    public boolean getCompareGroup() {
        return compareGroup;
    }

    public void setCompareGroup(boolean value) {
        compareGroup = value;
    }

    public boolean getCompareSortPrefix() {
        return compareSortPrefix;
    }

    public void setCompareSortPrefix(boolean value) {
        compareSortPrefix = value;
    }

    public boolean getCompareCommand() {
        return compareCommand;
    }

    public void setCompareCommand(boolean value) {
        compareCommand = value;
    }

    public Object executeMacro(Token token, Map<String, Object> arguments) {
        return executeCommand(token, arguments);
    }
}