/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.util; import java.util.Collections; import java.util.Map; import java.util.Map.Entry; import org.json.JSONException; /** * @author jcompagner * */ @SuppressWarnings("nls") public class FormatParser { public static ParsedFormat parseFormatProperty(String formatProperty) { return parseFormatProperty(formatProperty, null); } public static ParsedFormat parseFormatProperty(String formatProperty, String defaultFormat) { if (formatProperty != null && formatProperty.startsWith("{") && formatProperty.endsWith("}")) { // json try { Map<String, Object> props = new JSONWrapperMap<Object>(new ServoyJSONObject(formatProperty, false, true, false)); String uiConverterName = null; Map<String, String> uiConverterProperties = null; Map<String, Object> converterInfo = (Map<String, Object>)props.get("converter"); if (converterInfo != null) { uiConverterName = (String)converterInfo.get("name"); uiConverterProperties = (Map<String, String>)converterInfo.get("properties"); } String formatString = (String)props.get("format"); if (formatString == null) formatString = defaultFormat; if (formatString != null) { return parseFormatString(formatString, uiConverterName, uiConverterProperties); } // all in json boolean allUpperCase = Boolean.TRUE.equals(props.get("allUpperCase")); boolean allLowerCase = Boolean.TRUE.equals(props.get("allLowerCase")); boolean numberValidator = Boolean.TRUE.equals(props.get("numberValidator")); boolean raw = Boolean.TRUE.equals(props.get("raw")); boolean mask = Boolean.TRUE.equals(props.get("mask")); String editOrPlaceholder = (String)props.get("editOrPlaceholder"); String displayFormat = (String)props.get("displayFormat"); Integer maxLength = (Integer)props.get("maxLength"); String allowedCharacters = (String)props.get("allowedCharacters"); return new ParsedFormat(allUpperCase, allLowerCase, numberValidator, raw, mask, editOrPlaceholder, displayFormat, maxLength, uiConverterName, uiConverterProperties, allowedCharacters); } catch (JSONException e) { Debug.error("Could not parse format properties: '" + formatProperty + "'", e); } } // plain format string return parseFormatString(formatProperty, null, null); } /** * Parsers a format string, current supported formats: * * numbers/integers: display, display|edit * date: display, display|edit, display|mask, display|placeholder|mask * text: |U , |L , |#, display, display|raw, display|placeholder, display|placeholder|raw * * @param format */ private static ParsedFormat parseFormatString(String fmtString, String uiConverterName, Map<String, String> uiConverterProperties) { String formatString = fmtString == null || fmtString.length() == 0 ? null : fmtString; boolean allLowerCase = false; boolean allUpperCase = false; boolean numberValidator = false; Integer maxLength = null; boolean raw = false; boolean mask = false; String displayFormat = null; String editOrPlaceholder = null; if (formatString != null) { int index = formatString.indexOf("|"); if (index == -1) { displayFormat = formatString; } else { displayFormat = formatString.substring(0, index); editOrPlaceholder = formatString.substring(index + 1); if (displayFormat.length() == 0 && (editOrPlaceholder.length() == 1 || editOrPlaceholder.startsWith("U[") || editOrPlaceholder.startsWith("L[") || editOrPlaceholder.startsWith("#["))) { if (editOrPlaceholder.charAt(0) == 'U') { allUpperCase = true; } else if (editOrPlaceholder.charAt(0) == 'L') { allLowerCase = true; } else if (editOrPlaceholder.charAt(0) == '#') { numberValidator = true; } if (editOrPlaceholder.length() > 1) { maxLength = Integer.valueOf(editOrPlaceholder.substring(2, editOrPlaceholder.length() - 1)); } displayFormat = null; editOrPlaceholder = null; } else { String ml = editOrPlaceholder; index = ml.indexOf("|#("); if (index != -1 && ml.endsWith(")")) { editOrPlaceholder = ml.substring(0, index); ml = ml.substring(index + 1); } if (ml.startsWith("#(")) { try { maxLength = Integer.valueOf(ml.substring(2, ml.length() - 1)); if (ml == editOrPlaceholder) { editOrPlaceholder = ""; } } catch (Exception e) { Debug.log(e); } } if (editOrPlaceholder.endsWith("raw")) { raw = true; editOrPlaceholder = trim(editOrPlaceholder.substring(0, editOrPlaceholder.length() - "raw".length())); } if (editOrPlaceholder.endsWith("mask")) { mask = true; editOrPlaceholder = trim(editOrPlaceholder.substring(0, editOrPlaceholder.length() - "mask".length())); // re test raw if (editOrPlaceholder.endsWith("raw")) { raw = true; editOrPlaceholder = trim(editOrPlaceholder.substring(0, editOrPlaceholder.length() - "raw".length())); } } else editOrPlaceholder = trim(editOrPlaceholder); } } } return new ParsedFormat(allUpperCase, allLowerCase, numberValidator, raw, mask, editOrPlaceholder, displayFormat, maxLength, uiConverterName, uiConverterProperties == null ? null : Collections.unmodifiableMap(uiConverterProperties), null); } /** * @param eFormat * @return */ private static String trim(String eFormat) { String tmp = eFormat.trim(); if (tmp.startsWith("|")) tmp = tmp.substring(1); if (tmp.endsWith("|")) tmp = tmp.substring(0, tmp.length() - 1); return tmp; } /** * Immutable parsed format. * * @author rgansevles * */ public static class ParsedFormat { private final boolean allUpperCase; private final boolean allLowerCase; private final boolean numberValidator; private final boolean raw; private final boolean mask; private final String editOrPlaceholder; private final String displayFormat; private Integer maxLength; private final String uiConverterName; private final Map<String, String> uiConverterProperties; private final String allowedCharacters; public ParsedFormat(boolean allUpperCase, boolean allLowerCase, boolean numberValidator, boolean raw, boolean mask, String editOrPlaceholder, String displayFormat, Integer maxLength, String uiConverterName, Map<String, String> uiConverterProperties, String allowedCharacters) { this.allUpperCase = allUpperCase; this.allLowerCase = allLowerCase; this.numberValidator = numberValidator; this.raw = raw; this.mask = mask; this.editOrPlaceholder = editOrPlaceholder == null || editOrPlaceholder.length() == 0 ? null : editOrPlaceholder; this.displayFormat = displayFormat == null || displayFormat.length() == 0 ? null : displayFormat; this.maxLength = maxLength; this.uiConverterName = uiConverterName; this.uiConverterProperties = uiConverterProperties; // constructor is private, all callers should wrap with unmodifiable map this.allowedCharacters = allowedCharacters == null || allowedCharacters.length() == 0 ? null : allowedCharacters; } public String toFormatProperty() { if (uiConverterName == null && allowedCharacters == null) { // old style return toSimpleFormatProperty(); } // create json string try { ServoyJSONObject json = new ServoyJSONObject(false, false); if (allUpperCase) json.put("allUpperCase", Boolean.TRUE); if (allLowerCase) json.put("allLowerCase", Boolean.TRUE); if (numberValidator) json.put("numberValidator", Boolean.TRUE); if (raw) json.put("raw", Boolean.TRUE); if (mask) json.put("mask", Boolean.TRUE); if (editOrPlaceholder != null) json.put("editOrPlaceholder", editOrPlaceholder); if (displayFormat != null) json.put("displayFormat", displayFormat); if (maxLength != null) json.put("maxLength", maxLength); if (allowedCharacters != null) json.put("allowedCharacters", allowedCharacters); if (uiConverterName != null) { ServoyJSONObject conv = new ServoyJSONObject(false, false); json.put("converter", conv); conv.put("name", uiConverterName); if (uiConverterProperties != null) { ServoyJSONObject props = new ServoyJSONObject(false, false); for (Entry<String, String> entry : uiConverterProperties.entrySet()) { props.put(entry.getKey(), entry.getValue()); } conv.put("properties", props); } } return json.toString(false); } catch (JSONException e) { Debug.error(e); return null; } } /** * @return */ private String toSimpleFormatProperty() { if (allUpperCase) return maxLength != null ? "|U[" + maxLength.intValue() + ']' : "|U"; if (allLowerCase) return maxLength != null ? "|L[" + maxLength.intValue() + ']' : "|L"; if (numberValidator) return maxLength != null ? "|#[" + maxLength.intValue() + ']' : "|#"; StringBuilder sb = new StringBuilder(); if (displayFormat != null) { sb.append(displayFormat); if (editOrPlaceholder != null) sb.append('|').append(editOrPlaceholder); if (mask) sb.append("|mask"); if (raw) sb.append("|raw"); } if (maxLength != null) sb.append("|#(").append(maxLength.intValue()).append(')'); return sb.toString(); } /** * @return the maxLength */ public Integer getMaxLength() { return maxLength; } public void updateMaxLength(Integer maxLength) { this.maxLength = maxLength; } public String getDateMask() { if (!mask) return null; StringBuilder maskPattern = new StringBuilder(displayFormat.length()); int counter = 0; while (counter < displayFormat.length()) { char ch = displayFormat.charAt(counter++); switch (ch) { case 'y' : case 'M' : case 'w' : case 'W' : case 'D' : case 'd' : case 'F' : case 'H' : case 'k' : case 'K' : case 'h' : case 'm' : case 's' : case 'S' : maskPattern.append('#'); break; case 'a' : maskPattern.append('?'); break; default : maskPattern.append(ch); } } return maskPattern.toString(); } public boolean hasEditFormat() { // if it is a mask format then the editorplaceholder is always the place holder. // currently we dont have display and edit (with mask) support return !mask && editOrPlaceholder != null && !editOrPlaceholder.equals(displayFormat); } /** * @return the format */ public String getFormatString() { return toFormatProperty(); } public boolean isEmpty() { return !allUpperCase && !allLowerCase && !numberValidator && displayFormat == null && maxLength == null; } public char getPlaceHolderCharacter() { if (editOrPlaceholder != null && editOrPlaceholder.length() > 0) return editOrPlaceholder.charAt(0); return 0; } public String getPlaceHolderString() { if (editOrPlaceholder != null && editOrPlaceholder.length() > 1) return editOrPlaceholder; return null; } /** * @return the displayFormat */ public String getDisplayFormat() { return displayFormat; } /** * @return the editFormat */ public String getEditFormat() { return editOrPlaceholder; } /** * @return the allLowerCase */ public boolean isAllLowerCase() { return allLowerCase; } /** * @return the allUpperCase */ public boolean isAllUpperCase() { return allUpperCase; } /** * @return the mask */ public boolean isMask() { return mask; } /** * @return the numberValidator */ public boolean isNumberValidator() { return numberValidator; } /** * @return the raw */ public boolean isRaw() { return raw; } public String getUIConverterName() { return uiConverterName; } public Map<String, String> getUIConverterProperties() { return uiConverterProperties; } public ParsedFormat getCopy(String newUIConverterName, Map<String, String> newUIConverterProperties) { return new ParsedFormat(this.allUpperCase, this.allLowerCase, this.numberValidator, this.raw, this.mask, this.editOrPlaceholder, this.displayFormat, this.maxLength, newUIConverterName, newUIConverterProperties == null ? null : Collections.unmodifiableMap(newUIConverterProperties), allowedCharacters); } /** * @return */ public String getAllowedCharacters() { return allowedCharacters; } } }