com.izforge.izpack.panels.userinput.field.Field Maven / Gradle / Ivy
/*
* IzPack - Copyright 2001-2013 Julien Ponge, All Rights Reserved.
*
* http://izpack.org/
* http://izpack.codehaus.org/
*
* Copyright 2012 Tim Anderson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.izforge.izpack.panels.userinput.field;
import com.izforge.izpack.api.data.InstallData;
import com.izforge.izpack.api.data.binding.OsModel;
import com.izforge.izpack.api.exception.IzPackException;
import com.izforge.izpack.api.rules.RulesEngine;
import com.izforge.izpack.core.rules.process.ExistsCondition;
import com.izforge.izpack.panels.userinput.processorclient.ValuesProcessingClient;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Describes a user input field.
*
* @author Tim Anderson
*/
public abstract class Field
{
/**
* The variable. May be {@code null}.
*/
private String variable;
/**
* The variable. May be {@code null}.
*/
private final String summaryKey;
/**
* Specifies the value to override the current variable value for the field.
*/
private final String initialValue;
/**
* Specifies the default value for the field.
*/
private final String defaultValue;
/**
* The field size.
*/
private final int size;
/**
* The packs that the field applies to. May be {@code null} or empty to indicate all packs.
*/
private final List packs;
/**
* The the operating systems that the field applies to. An empty list indicates it applies to all operating systems
*/
private final List models;
/**
* The field validators.
*/
private final List validators;
/**
* The field processor. May be {@code null}
*/
private final FieldProcessor processor;
/**
* The field label. May be {@code null}
*/
private final String label;
/**
* The field description. May be {@code null}
*/
private final String description;
/**
* The field's tooltip. May be {@code null}
*/
private final String tooltip;
/**
* Condition that determines if the field is displayed or not.
*/
private final String condition;
/**
* Determines if the field should always be displayed on the panel regardless if its conditionid is true or false.
* If the conditionid is false, display the field but disable it.
*/
private Boolean displayHidden;
/**
* Determines a condition for which the field should be displayed on the panel regardless if its conditionid is true or false.
*/
private String displayHiddenCondition;
/**
* Determines if the field should always be displayed read-only.
*/
private Boolean readonly;
/**
* Determines a condition for which the field should be displayed read-only.
*/
private String readonlyCondition;
/**
* The installation data.
*/
private final InstallData installData;
/**
* Determines if the 'value' of an entry will be included in the user input panel
*/
private boolean omitFromAuto;
/**
* The logger.
*/
private static final Logger logger = Logger.getLogger(Field.class.getName());
/**
* Constructs a {@code Field}.
*
* @param config the field configuration
* @param installData the installation data
* @throws IzPackException if the configuration is invalid
*/
public Field(FieldConfig config, InstallData installData)
{
variable = config.getVariable();
summaryKey = config.getSummaryKey();
initialValue = config.getInitialValue();
defaultValue = config.getDefaultValue();
size = config.getSize();
packs = config.getPacks();
models = config.getOsModels();
validators = config.getValidators();
processor = config.getProcessor();
label = config.getLabel();
description = config.getDescription();
displayHidden = config.isDisplayHidden();
displayHiddenCondition = config.getDisplayHiddenCondition();
readonly = config.isReadonly();
readonlyCondition = config.getReadonlyCondition();
tooltip = config.getTooltip();
omitFromAuto = config.getOmitFromAuto();
this.condition = config.getCondition();
this.installData = installData;
if (variable != null)
{
addExistsCondition();
}
}
/**
* Returns the variable.
*
* @return the variable. May be {@code null}
*/
public String getVariable()
{
return variable;
}
/**
* Returns the value of 'omitFromAuto' from fields spec
*
* @return the 'omitFromAuto' attribute
*/
public boolean getOmitFromAuto()
{
return omitFromAuto;
}
/**
* Returns all variables that this field updates.
*
* @return all variables that this field updates
*/
public List getVariables()
{
return variable != null ? Arrays.asList(variable) : Collections.emptyList();
}
/**
* Returns the summaryKey.
*
* @return the summaryKey. May be {@code null}
*/
public String getSummaryKey()
{
return summaryKey;
}
/**
* Returns if the field should always be displayed read-only
* on the panel regardless if its conditionid is true or false.
* This equals the value of the 'displayHidden' attribute from the field definition.
*
* @return the 'displayHidden' attribute, or {@code false}
*/
public Boolean isDisplayHidden()
{
return displayHidden;
}
/**
* Returns a condition for which the field should be displayed read-only
* on the panel regardless if its conditionid is true or false.
* If the condition evaluates false, don't apply displayHidden.
* This equals the value of the 'displayHiddenCondition' attribute from the field definition.
*
* @return the condition ID, or {@code null}
*/
public String getDisplayHiddenCondition()
{
return displayHiddenCondition;
}
/**
* Returns if the field should be always displayed read-only.
* This equals the value of the 'readonly' attribute from the field definition.
*
* @return true if field should be shown read-only, or {@code false}
*/
public Boolean isReadonly()
{
return readonly;
}
/**
* Returns an effective value whether a field should be currently displayed read-only.
*
* @return true if field should be shown read-only, or {@code false}
*/
public boolean isEffectiveReadonly(boolean defaultFlag, RulesEngine rules)
{
boolean result = false;
if (readonly != null)
{
result = readonly.booleanValue();
}
else if (readonlyCondition != null && rules.isConditionTrue(readonlyCondition))
{
result = rules.isConditionTrue(readonlyCondition);
}
else
{
result = defaultFlag;
}
return result;
}
/**
* Returns an effective value whether a field should be currently displayed read-only if hidden.
*
* @return true if field should be shown read-only if hidden, or {@code false}
*/
public boolean isEffectiveDisplayHidden(boolean defaultFlag, RulesEngine rules)
{
boolean result = false;
if (displayHidden != null)
{
result = displayHidden.booleanValue();
}
else if (displayHiddenCondition != null && rules.isConditionTrue(displayHiddenCondition))
{
result = rules.isConditionTrue(displayHiddenCondition);
}
else
{
result = defaultFlag;
}
return result;
}
/**
* Returns a condition for which the field should be displayed read-only.
* If the conditionid is false, don't apply readonly.
* This equals the value of the 'readonlyCondition' attribute from the field definition.
*
* @return the condition ID, or {@code null}
*/
public String getReadonlyCondition()
{
return readonlyCondition;
}
/**
* Returns the packs that the field applies to.
*
* @return the pack names
*/
public List getPacks()
{
return packs;
}
/**
* Returns the operating systems that the field applies to.
*
* @return the OS family names
*/
public List getOsModels()
{
return models;
}
/**
* Returns the default value of the field.
*
* @return the default value. May be {@code null}
*/
public String getDefaultValue()
{
String value = wrapDefaultValue(defaultValue);
if (value != null)
{
return replaceVariables(value);
}
return null;
}
/**
* Returns the forced value of the field.
*
* @return the forced value. May be {@code null}
*/
private String getForcedValue()
{
String value = wrapInitialValue(initialValue);
if (value != null)
{
return replaceVariables(value);
}
return null;
}
/**
* Returns the initial value to use for this field.
*
* The following non-null value is used from the following search order
*
* - initial value (substituting variables)
*
- current variable value
*
- default value (substituting variables)
*
*
* @return The initial value to use for this field
*/
public String getInitialValue()
{
String result = null;
if (!installData.getVariables().isBlockedVariableName(variable))
{
result = getForcedValue();
}
if (result == null)
{
result = getValue();
if (result == null)
{
result = getDefaultValue();
}
}
return result;
}
/**
* Returns the variable value.
*
* @return the variable value. May be {@code null}
*/
public String getValue()
{
return installData.getVariable(variable);
}
/**
* Sets the variable value.
*
* @param value the variable value. May be {@code null}
*/
public void setValue(String value)
{
value = process(value);
if (logger.isLoggable(Level.FINE))
{
logger.fine("Field setting variable=" + variable + " to value=" + value);
}
installData.setVariable(variable, value);
}
/**
* Wrap the initial value of a field, which is the value of the set
attribute in the field's spec to
* the effective value to be assigned to the variable. This can be used for enumeration type conversions.
*
* This method can be optionally overridden by several user input field types.
*
* Example: The set
attribute in the checkbox user input field has a boolean value, the value should
* be wrapped to the value of the true
attribute in case of set="true"
or to the value of
* the false
attribute in case of set="false"
.
*
* @param originalValue the original value of the set
attribute
* @return the wrapped value
* @see com.izforge.izpack.panels.userinput.field.check.CheckField
*/
public String wrapInitialValue(String originalValue)
{
return originalValue;
}
/**
* Wrap the default value of a field, which is the value of the default
attribute in the field's spec
* to the effective value to be assigned to the variable. This can be used for enumeration type conversions.
* To be overridden by several user input field types.
*
* This method can be optionally overridden by several user input field types.
*
* Example: The set
attribute in the checkbox user input field has a boolean value, the value should
* be wrapped to the value of the true
attribute in case of default="true"
or to the
* value of the false
attribute in case of default="false"
.
* @see com.izforge.izpack.panels.userinput.field.check.CheckField
*
* @param originalValue the original value of the default
attribute
* @return the wrapped value
* @see com.izforge.izpack.panels.userinput.field.check.CheckField
*/
public String wrapDefaultValue(String originalValue)
{
return originalValue;
}
/**
* Returns the field size.
*
* @return the field size, or {@code -1} if no size is defined
*/
public int getSize()
{
return size;
}
/**
* Validates values using any validators associated with the field.
*
* @param values the values to validate
* @return the status of the validation
*/
public ValidationStatus validate(String... values)
{
return validate(new ValuesProcessingClient(values));
}
/**
* Validates values using any validators associated with the field.
*
* @param format how the values should be formatted into one text
* @param values the values to validate
* @return the status of the validation
*/
public ValidationStatus validate(MessageFormat format, String... values)
{
return validate(new ValuesProcessingClient(format, values));
}
/**
* Validates values using any validators associated with the field.
*
* @param values the values to validate
* @return the status of the validation
*/
public ValidationStatus validate(ValuesProcessingClient values)
{
try
{
for (FieldValidator validator : validators)
{
if (!validator.validate(values))
{
return ValidationStatus.failed(validator.getMessage());
}
}
}
catch (Throwable exception)
{
return ValidationStatus.failed(exception.getMessage());
}
return ValidationStatus.success(values.getValues());
}
/**
* Processes a initialValue of values.
*
* @param values the values to process
* @return the result of processing
* @throws IzPackException if processing fails
*/
public String process(String... values)
{
String result = null;
if (processor != null)
{
result = processor.process(values);
}
else if (values.length > 0)
{
result = values[0];
}
return result;
}
/**
* Returns the field processor.
*
* @return the field processor. May be {@code null}
*/
public FieldProcessor getProcessor()
{
return processor;
}
/**
* Returns the field label.
*
* @return the field label. May be {@code null}
*/
public String getLabel()
{
String result = null;
if (label != null)
{
result = replaceVariables(label);
}
return result;
}
/**
* Returns the field description.
*
* @return the field description. May be {@code null}
*/
public String getDescription()
{
String result = null;
if (description != null)
{
result = replaceVariables(description);
}
return result;
}
/**
* Returns the field tooltip.
*
* @return the field tooltip. May be {@code null}
*/
public String getTooltip() {
String result = null;
if (tooltip != null)
{
result = replaceVariables(tooltip);
}
return result;
}
/**
* Determines if the condition associated with the field is true.
*
* @return {@code true} if the condition evaluates {true} or if the field has no condition
*/
public boolean isConditionTrue()
{
RulesEngine rules = getRules();
return (condition == null || rules.isConditionTrue(condition, installData));
}
/**
* Returns the installation data.
*
* @return the installation data
*/
public InstallData getInstallData()
{
return installData;
}
/**
* Returns the rules.
*
* @return the rules
*/
protected RulesEngine getRules()
{
return installData.getRules();
}
/**
* Replaces any variables in the supplied value.
*
* @param value the value
* @return the value with variables replaced
*/
protected String replaceVariables(String value)
{
return installData.getVariables().replace(value);
}
/**
* Adds an 'exists' condition for the variable.
*/
private void addExistsCondition()
{
RulesEngine rules = getRules();
final String conditionId = "izpack.input." + variable;
if (rules != null)
{
if (rules.getCondition(conditionId) == null)
{
ExistsCondition existsCondition = new ExistsCondition();
existsCondition.setContentType(ExistsCondition.ContentType.VARIABLE);
existsCondition.setContent(variable);
existsCondition.setId(conditionId);
existsCondition.setInstallData(installData);
rules.addCondition(existsCondition);
}
else
{
logger.fine("Condition '" + conditionId + "' for variable '" + variable + "' already exists");
}
}
else
{
logger.fine("Cannot add condition '" + conditionId + "' for variable '" + variable + "'. Rules not supplied");
}
}
//TODO: Scary thought to have variable not final
//TODO: Need to check that variable doesn't already exist
public void setVariable(String newVariableName)
{
this.variable = newVariableName;
}
}