blob: dec68cf9b4408de07c16fbbd9aa5318cbc213fcd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM - Initial API and implementation
* ARM Ltd. - basic tooltip support
* Petri Tuononen - [321040] Get Library Search Paths
* Baltasar Belyavsky (Texas Instruments) - [279633] Custom command-generator support
* cartu38 opendev (STMicroelectronics) - [514385] Custom defaultValue-generator support
*******************************************************************************/
package org.eclipse.cdt.managedbuilder.internal.core;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.core.settings.model.ICStorageElement;
import org.eclipse.cdt.internal.core.SafeStringInterner;
import org.eclipse.cdt.managedbuilder.core.BuildException;
import org.eclipse.cdt.managedbuilder.core.IBuildObject;
import org.eclipse.cdt.managedbuilder.core.IBuildPropertiesRestriction;
import org.eclipse.cdt.managedbuilder.core.IConfiguration;
import org.eclipse.cdt.managedbuilder.core.IHoldsOptions;
import org.eclipse.cdt.managedbuilder.core.IManagedConfigElement;
import org.eclipse.cdt.managedbuilder.core.IManagedOptionValueHandler;
import org.eclipse.cdt.managedbuilder.core.IOption;
import org.eclipse.cdt.managedbuilder.core.IOptionApplicability;
import org.eclipse.cdt.managedbuilder.core.IOptionCategory;
import org.eclipse.cdt.managedbuilder.core.IOptionCommandGenerator;
import org.eclipse.cdt.managedbuilder.core.IOptionDefaultValueGenerator;
import org.eclipse.cdt.managedbuilder.core.IProjectType;
import org.eclipse.cdt.managedbuilder.core.ITool;
import org.eclipse.cdt.managedbuilder.core.IToolChain;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
import org.eclipse.cdt.managedbuilder.core.ManagedOptionValueHandler;
import org.eclipse.cdt.managedbuilder.core.OptionStringValue;
import org.eclipse.cdt.managedbuilder.internal.enablement.OptionEnablementExpression;
import org.eclipse.cdt.managedbuilder.internal.macros.OptionContextData;
import org.eclipse.cdt.managedbuilder.macros.IOptionContextData;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.osgi.framework.Version;
public class Option extends BuildObject implements IOption, IBuildPropertiesRestriction {
private static final String IS_BUILTIN_EMPTY = "IS_BUILTIN_EMPTY"; //$NON-NLS-1$
private static final String IS_VALUE_EMPTY = "IS_VALUE_EMPTY"; //$NON-NLS-1$
// Static default return values
public static final String EMPTY_STRING = ""; //$NON-NLS-1$
public static final String[] EMPTY_STRING_ARRAY = new String[0];
public static final OptionStringValue[] EMPTY_LV_ARRAY = new OptionStringValue[0];
// Superclass
private IOption superClass;
private String superClassId;
// Parent and children
private IHoldsOptions holder;
// Managed Build model attributes
private String unusedChildren;
private Integer browseType;
private String browseFilterPath;
private String[] browseFilterExtensions;
private List<OptionStringValue> builtIns;
private IOptionCategory category;
private String categoryId;
private String command;
private IConfigurationElement commandGeneratorElement;
private IOptionCommandGenerator commandGenerator;
private String commandFalse;
private Boolean isForScannerDiscovery;
private String tip;
private String contextId;
private List<String> applicableValuesList;
private Map<String, String> commandsMap;
private Map<String, String> namesMap;
private Object value;
private Object defaultValue;
private IConfigurationElement defaultValueGeneratorElement;
private IOptionDefaultValueGenerator defaultValueGenerator;
private Integer valueType;
private Boolean isAbstract;
private Integer resourceFilter;
private IConfigurationElement valueHandlerElement = null;
private IManagedOptionValueHandler valueHandler = null;
private String valueHandlerExtraArgument;
private String fieldEditorId;
private String fieldEditorExtraArgument;
private IConfigurationElement applicabilityCalculatorElement = null;
private IOptionApplicability applicabilityCalculator = null;
private BooleanExpressionApplicabilityCalculator booleanExpressionCalculator = null;
private ITreeRoot treeRoot;
// Miscellaneous
private boolean isExtensionOption = false;
private boolean isDirty = false;
private boolean resolved = true;
private boolean verified = false;
/**
* False for options which are invalid. getOption()
* routines will ignore invalid options.
*/
private boolean isValid = true;
/**
* True for options which are created because of an
* MBS 2.0 model OptionReference element
*/
private boolean wasOptRef = false;
private boolean isUdjusted = false;
private boolean rebuildState;
/**
* This constructor is called to create an option defined by an extension point in
* a plugin manifest file, or returned by a dynamic element provider
*
* @param parent The IHoldsOptions parent of this option, or <code>null</code> if
* defined at the top level
* @param element The option definition from the manifest file or a dynamic element
* provider
*/
public Option(IHoldsOptions parent, IManagedConfigElement element) {
this.holder = parent;
isExtensionOption = true;
// setup for resolving
resolved = false;
loadFromManifest(element);
// Hook me up to the Managed Build Manager
ManagedBuildManager.addExtensionOption(this);
}
/**
* This constructor is called to create an Option whose attributes and children will be
* added by separate calls.
*
* @param parent - the parent of the option, if any
* @param superClass - the superClass, if any
* @param Id - the id for the new option
* @param name - the name for the new option
* @param isExtensionElement - indicates whether this is an extension element or a managed project element
*/
public Option(IHoldsOptions parent, IOption superClass, String Id, String name, boolean isExtensionElement) {
this.holder = parent;
this.superClass = superClass;
if (this.superClass != null) {
superClassId = this.superClass.getId();
}
setId(Id);
setName(name);
isExtensionOption = isExtensionElement;
if (isExtensionElement) {
// Hook me up to the Managed Build Manager
ManagedBuildManager.addExtensionOption(this);
} else {
setDirty(true);
setRebuildState(true);
}
}
/**
* Create an <code>Option</code> based on the specification stored in the
* project file (.cdtbuild).
*
* @param parent The <code>IHoldsOptions</code> the option will be added to.
* @param element The XML element that contains the option settings.
*/
public Option(IHoldsOptions parent, ICStorageElement element) {
this.holder = parent;
isExtensionOption = false;
// Initialize from the XML attributes
loadFromProject(element);
}
/**
* Create an <code>Option</code> based upon an existing option.
*
* @param parent The <code>IHoldsOptions</code> the option will be added to.
* @param Id New ID for the option.
* @param name New name for the option.
* @param option The existing option to clone, except for the above fields.
*/
public Option(IHoldsOptions parent, String Id, String name, Option option) {
this.holder = parent;
superClass = option.superClass;
if (superClass != null) {
superClassId = option.superClass.getId();
} else if (option.superClassId != null) {
superClassId = option.superClassId;
}
setId(Id);
setName(name);
isExtensionOption = false;
boolean copyIds = Id.equals(option.id);
// Copy the remaining attributes
if (option.unusedChildren != null) {
unusedChildren = option.unusedChildren;
}
if (option.isAbstract != null) {
isAbstract = option.isAbstract;
}
if (option.command != null) {
command = option.command;
}
if (option.commandFalse != null) {
commandFalse = option.commandFalse;
}
if (option.isForScannerDiscovery != null) {
isForScannerDiscovery = option.isForScannerDiscovery;
}
if (option.tip != null) {
tip = option.tip;
}
if (option.contextId != null) {
contextId = option.contextId;
}
if (option.categoryId != null) {
categoryId = option.categoryId;
}
if (option.builtIns != null) {
builtIns = new ArrayList<>(option.builtIns);
}
if (option.browseType != null) {
browseType = option.browseType;
}
if (option.browseFilterPath != null) {
browseFilterPath = option.browseFilterPath;
}
if (option.browseFilterExtensions != null) {
browseFilterExtensions = option.browseFilterExtensions.clone();
}
if (option.resourceFilter != null) {
resourceFilter = option.resourceFilter;
}
if (option.applicableValuesList != null) {
applicableValuesList = new ArrayList<>(option.applicableValuesList);
commandsMap = new HashMap<>(option.commandsMap);
namesMap = new HashMap<>(option.namesMap);
}
if (option.treeRoot != null) {
treeRoot = new TreeRoot((TreeRoot) option.treeRoot);
}
if (option.valueType != null) {
valueType = option.valueType;
}
try {
int vType = option.getValueType();
switch (vType) {
case BOOLEAN:
if (option.value != null) {
value = option.value;
}
if (option.defaultValue != null) {
defaultValue = option.defaultValue;
}
break;
case STRING:
case ENUMERATED:
case TREE:
if (option.value != null) {
value = option.value;
}
if (option.defaultValue != null) {
defaultValue = option.defaultValue;
}
break;
case STRING_LIST:
case INCLUDE_PATH:
case PREPROCESSOR_SYMBOLS:
case LIBRARIES:
case OBJECTS:
case INCLUDE_FILES:
case LIBRARY_PATHS:
case LIBRARY_FILES:
case MACRO_FILES:
case UNDEF_INCLUDE_PATH:
case UNDEF_PREPROCESSOR_SYMBOLS:
case UNDEF_INCLUDE_FILES:
case UNDEF_LIBRARY_PATHS:
case UNDEF_LIBRARY_FILES:
case UNDEF_MACRO_FILES:
if (option.value != null) {
@SuppressWarnings("unchecked")
ArrayList<OptionStringValue> list = new ArrayList<>((ArrayList<OptionStringValue>) option.value);
value = list;
}
if (option.defaultValue != null) {
@SuppressWarnings("unchecked")
ArrayList<OptionStringValue> list = new ArrayList<>(
(ArrayList<OptionStringValue>) option.defaultValue);
defaultValue = list;
}
break;
}
} catch (BuildException be) {
// TODO: should we ignore this??
}
category = option.category;
defaultValueGeneratorElement = option.defaultValueGeneratorElement;
defaultValueGenerator = option.defaultValueGenerator;
commandGeneratorElement = option.commandGeneratorElement;
commandGenerator = option.commandGenerator;
applicabilityCalculatorElement = option.applicabilityCalculatorElement;
applicabilityCalculator = option.applicabilityCalculator;
booleanExpressionCalculator = option.booleanExpressionCalculator;
if (option.valueHandlerElement != null) {
valueHandlerElement = option.valueHandlerElement;
valueHandler = option.valueHandler;
}
if (option.valueHandlerExtraArgument != null) {
valueHandlerExtraArgument = option.valueHandlerExtraArgument;
}
if (option.fieldEditorId != null) {
fieldEditorId = option.fieldEditorId;
}
if (option.fieldEditorExtraArgument != null) {
fieldEditorExtraArgument = option.fieldEditorExtraArgument;
}
if (copyIds) {
isDirty = option.isDirty;
rebuildState = option.rebuildState;
} else {
setDirty(true);
setRebuildState(true);
}
}
/*
* E L E M E N T A T T R I B U T E R E A D E R S A N D W R I T E R S
*/
/**
* Loads the option information from the ManagedConfigElement specified in the
* argument.
*
* @param element Contains the option information
*/
protected void loadFromManifest(IManagedConfigElement element) {
ManagedBuildManager.putConfigElement(this, element);
// id
setId(SafeStringInterner.safeIntern(element.getAttribute(IBuildObject.ID)));
// Get the name
setName(SafeStringInterner.safeIntern(element.getAttribute(IBuildObject.NAME)));
// superClass
superClassId = SafeStringInterner.safeIntern(element.getAttribute(IProjectType.SUPERCLASS));
// Get the unused children, if any
unusedChildren = SafeStringInterner.safeIntern(element.getAttribute(IProjectType.UNUSED_CHILDREN));
// isAbstract
String isAbs = element.getAttribute(IProjectType.IS_ABSTRACT);
if (isAbs != null) {
isAbstract = Boolean.parseBoolean(isAbs);
}
// Get the defaultValue-generator, if any
String defaultValueGeneratorStr = element.getAttribute(DEFAULTVALUE_GENERATOR);
if (defaultValueGeneratorStr != null && element instanceof DefaultManagedConfigElement) {
defaultValueGeneratorElement = ((DefaultManagedConfigElement) element).getConfigurationElement();
}
// Get the command defined for the option
command = SafeStringInterner.safeIntern(element.getAttribute(COMMAND));
// Get the command-generator, if any
String commandGeneratorStr = element.getAttribute(COMMAND_GENERATOR);
if (commandGeneratorStr != null && element instanceof DefaultManagedConfigElement) {
commandGeneratorElement = ((DefaultManagedConfigElement) element).getConfigurationElement();
}
// Get the command defined for a Boolean option when the value is False
commandFalse = SafeStringInterner.safeIntern(element.getAttribute(COMMAND_FALSE));
// isForScannerDiscovery
String isForSD = element.getAttribute(USE_BY_SCANNER_DISCOVERY);
if (isForSD != null) {
isForScannerDiscovery = Boolean.parseBoolean(isForSD);
}
// Get the tooltip for the option
tip = SafeStringInterner.safeIntern(element.getAttribute(TOOL_TIP));
// Get the contextID for the option
contextId = SafeStringInterner.safeIntern(element.getAttribute(CONTEXT_ID));
// Options hold different types of values
String valueTypeStr = element.getAttribute(VALUE_TYPE);
if (valueTypeStr != null) {
valueType = Integer.valueOf(ValueTypeStrToInt(valueTypeStr));
}
// Note: The value and defaultValue attributes are loaded in the resolveReferences routine.
// This is because we need to have the value-type, and this may be defined in a
// superClass that is not yet loaded.
// Determine if there needs to be a browse button
String browseTypeStr = element.getAttribute(BROWSE_TYPE);
if (browseTypeStr == null) {
// Set to null, to indicate no browse type specification
// This will allow any superclasses to be searched for the
// browse type specification, and thus inherited, if found,
// which they should be
browseType = null;
} else if (browseTypeStr.equals(NONE)) {
browseType = BROWSE_NONE;
} else if (browseTypeStr.equals(FILE)) {
browseType = BROWSE_FILE;
} else if (browseTypeStr.equals(DIR)) {
browseType = BROWSE_DIR;
}
// Get the browseFilterPath attribute
this.browseFilterPath = SafeStringInterner.safeIntern(element.getAttribute(BROWSE_FILTER_PATH));
// Get the browseFilterExtensions attribute
String browseFilterExtensionsStr = element.getAttribute(BROWSE_FILTER_EXTENSIONS);
if (browseFilterExtensionsStr != null) {
this.browseFilterExtensions = SafeStringInterner.safeIntern(browseFilterExtensionsStr.split("\\s*,\\s*")); //$NON-NLS-1$
}
categoryId = SafeStringInterner.safeIntern(element.getAttribute(CATEGORY));
// Get the resourceFilter attribute
String resFilterStr = element.getAttribute(RESOURCE_FILTER);
if (resFilterStr == null) {
// Set to null, to indicate no resource filter specification
// This will allow any superclasses to be searched for the
// resource filter specification, and thus inherited, if found,
// which they should be
resourceFilter = null;
} else if (resFilterStr.equals(ALL)) {
resourceFilter = FILTER_ALL;
} else if (resFilterStr.equals(FILE)) {
resourceFilter = FILTER_FILE;
} else if (resFilterStr.equals(PROJECT)) {
resourceFilter = FILTER_PROJECT;
}
//get enablements
IManagedConfigElement enablements[] = element.getChildren(OptionEnablementExpression.NAME);
if (enablements.length > 0) {
booleanExpressionCalculator = new BooleanExpressionApplicabilityCalculator(enablements);
}
// get the applicability calculator, if any
String applicabilityCalculatorStr = element.getAttribute(APPLICABILITY_CALCULATOR);
if (applicabilityCalculatorStr != null && element instanceof DefaultManagedConfigElement) {
applicabilityCalculatorElement = ((DefaultManagedConfigElement) element).getConfigurationElement();
} else {
applicabilityCalculator = booleanExpressionCalculator;
}
// valueHandler
// Store the configuration element IFF there is a value handler defined
String valueHandler = element.getAttribute(VALUE_HANDLER);
if (valueHandler != null && element instanceof DefaultManagedConfigElement) {
valueHandlerElement = ((DefaultManagedConfigElement) element).getConfigurationElement();
}
// valueHandlerExtraArgument
valueHandlerExtraArgument = SafeStringInterner.safeIntern(element.getAttribute(VALUE_HANDLER_EXTRA_ARGUMENT));
// fieldEditor and optional argument
fieldEditorId = element.getAttribute(FIELD_EDITOR_ID);
fieldEditorExtraArgument = element.getAttribute(FIELD_EDITOR_EXTRA_ARGUMENT);
}
/**
* Initialize the option information from the XML element
* specified in the argument
*
* @param element An XML element containing the option information
*/
protected void loadFromProject(ICStorageElement element) {
// id (unique, don't intern)
setId(element.getAttribute(IBuildObject.ID));
// name
if (element.getAttribute(IBuildObject.NAME) != null) {
setName(SafeStringInterner.safeIntern(element.getAttribute(IBuildObject.NAME)));
}
// superClass
superClassId = SafeStringInterner.safeIntern(element.getAttribute(IProjectType.SUPERCLASS));
if (superClassId != null && superClassId.length() > 0) {
superClass = ManagedBuildManager.getExtensionOption(superClassId);
if (superClass == null) {
/*
* This can happen when options are set at the resource level, for a project using a toolchain definition
* where there are options at the toolchain level & one or more of those options is set at a
* non-default value.
*
* In these cases the superclass is set to the option from the parent not the extension's ID
* Workaround this by searching for any missing superclass IDs at on the parent configs toolchain
*
* See the "bug580009.tests.cfg1.tc" definition in org.eclipse.cdt.managedbuilder.core.tests for an example
*/
IBuildObject parent = this.getParent();
if (parent instanceof IToolChain) {
IConfiguration config = ((IToolChain) parent).getParent();
IOption foundOption = null;
if (config != null) {
IToolChain parentToolchain = config.getToolChain();
if (parentToolchain != null) {
foundOption = parentToolchain.getOptionById(superClassId);
}
}
if (foundOption != null) {
superClass = foundOption;
} else {
ManagedBuilderCorePlugin.log(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID,
MessageFormat.format("Missing superclass \"{0}\" for \"{1}\"", superClassId, getId()))); //$NON-NLS-1$
}
} else {
ManagedBuilderCorePlugin.log(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID,
MessageFormat.format("Missing superclass \"{0}\" for \"{1}\"", superClassId, getId()))); //$NON-NLS-1$
}
}
}
// Get the unused children, if any
if (element.getAttribute(IProjectType.UNUSED_CHILDREN) != null) {
unusedChildren = SafeStringInterner.safeIntern(element.getAttribute(IProjectType.UNUSED_CHILDREN));
}
// isAbstract
if (element.getAttribute(IProjectType.IS_ABSTRACT) != null) {
String isAbs = element.getAttribute(IProjectType.IS_ABSTRACT);
if (isAbs != null) {
isAbstract = Boolean.parseBoolean(isAbs);
}
}
// Get the command defined for the option
if (element.getAttribute(COMMAND) != null) {
command = SafeStringInterner.safeIntern(element.getAttribute(COMMAND));
}
// Get the command defined for a Boolean option when the value is False
if (element.getAttribute(COMMAND_FALSE) != null) {
commandFalse = SafeStringInterner.safeIntern(element.getAttribute(COMMAND_FALSE));
}
// isForScannerDiscovery
if (element.getAttribute(USE_BY_SCANNER_DISCOVERY) != null) {
String isForSD = element.getAttribute(USE_BY_SCANNER_DISCOVERY);
if (isForSD != null) {
isForScannerDiscovery = Boolean.parseBoolean(isForSD);
}
}
// Get the tooltip for the option
if (element.getAttribute(TOOL_TIP) != null) {
tip = SafeStringInterner.safeIntern(element.getAttribute(TOOL_TIP));
}
// Get the contextID for the option
if (element.getAttribute(CONTEXT_ID) != null) {
contextId = SafeStringInterner.safeIntern(element.getAttribute(CONTEXT_ID));
}
// Options hold different types of values
if (element.getAttribute(VALUE_TYPE) != null) {
String valueTypeStr = element.getAttribute(VALUE_TYPE);
valueType = Integer.valueOf(ValueTypeStrToInt(valueTypeStr));
}
// Now get the actual value based upon value-type
try {
int valType = getValueType();
switch (valType) {
case BOOLEAN:
// Convert the string to a boolean
if (element.getAttribute(VALUE) != null) {
value = Boolean.valueOf(element.getAttribute(VALUE));
}
if (element.getAttribute(DEFAULT_VALUE) != null) {
defaultValue = Boolean.valueOf(element.getAttribute(DEFAULT_VALUE));
}
break;
case STRING:
// Just get the value out of the option directly
if (element.getAttribute(VALUE) != null) {
value = SafeStringInterner.safeIntern(element.getAttribute(VALUE));
}
if (element.getAttribute(DEFAULT_VALUE) != null) {
defaultValue = SafeStringInterner.safeIntern(element.getAttribute(DEFAULT_VALUE));
}
break;
case ENUMERATED:
if (element.getAttribute(VALUE) != null) {
value = SafeStringInterner.safeIntern(element.getAttribute(VALUE));
}
if (element.getAttribute(DEFAULT_VALUE) != null) {
defaultValue = SafeStringInterner.safeIntern(element.getAttribute(DEFAULT_VALUE));
}
// Do we have enumeratedOptionValue children? If so, load them
// to define the valid values and the default value.
ICStorageElement configElements[] = element.getChildren();
for (int i = 0; i < configElements.length; ++i) {
ICStorageElement configNode = configElements[i];
if (configNode.getName().equals(ENUM_VALUE)) {
ICStorageElement configElement = configNode;
String optId = SafeStringInterner.safeIntern(configElement.getAttribute(ID));
if (i == 0) {
applicableValuesList = new ArrayList<>();
if (defaultValue == null) {
defaultValue = optId; // Default value to be overridden is default is specified
}
}
applicableValuesList.add(optId);
if (configElement.getAttribute(COMMAND) != null) {
getCommandMap().put(optId,
SafeStringInterner.safeIntern(configElement.getAttribute(COMMAND)));
} else {
getCommandMap().put(optId, EMPTY_STRING);
}
getNameMap().put(optId, SafeStringInterner.safeIntern(configElement.getAttribute(NAME)));
if (configElement.getAttribute(IS_DEFAULT) != null) {
Boolean isDefault = Boolean.valueOf(configElement.getAttribute(IS_DEFAULT));
if (isDefault.booleanValue()) {
defaultValue = optId;
}
}
}
}
break;
case TREE:
if (element.getAttribute(VALUE) != null) {
value = element.getAttribute(VALUE);
}
if (element.getAttribute(DEFAULT_VALUE) != null) {
defaultValue = element.getAttribute(DEFAULT_VALUE);
}
break;
case STRING_LIST:
case INCLUDE_PATH:
case PREPROCESSOR_SYMBOLS:
case LIBRARIES:
case OBJECTS:
case INCLUDE_FILES:
case LIBRARY_PATHS:
case LIBRARY_FILES:
case MACRO_FILES:
case UNDEF_INCLUDE_PATH:
case UNDEF_PREPROCESSOR_SYMBOLS:
case UNDEF_INCLUDE_FILES:
case UNDEF_LIBRARY_PATHS:
case UNDEF_LIBRARY_FILES:
case UNDEF_MACRO_FILES:
// Note: These string-list options do not load either the "value" or
// "defaultValue" attributes. Instead, the ListOptionValue children
// are loaded in the value field.
List<OptionStringValue> vList = new ArrayList<>();
List<OptionStringValue> biList = new ArrayList<>();
configElements = element.getChildren();
for (ICStorageElement veNode : configElements) {
if (veNode.getName().equals(LIST_VALUE)) {
OptionStringValue ve = new OptionStringValue(veNode);
if (ve.isBuiltIn()) {
biList.add(ve);
} else {
vList.add(ve);
}
}
}
//Assume not empty unless specificaly flagged
boolean isValueEmpty = false;
boolean isBuiltinEmpty = false;
if (element.getAttribute(IS_VALUE_EMPTY) != null) {
Boolean isEmpty = Boolean.valueOf(element.getAttribute(IS_VALUE_EMPTY));
if (isEmpty.booleanValue()) {
isValueEmpty = true;
}
}
if (element.getAttribute(IS_BUILTIN_EMPTY) != null) {
Boolean isEmpty = Boolean.valueOf(element.getAttribute(IS_BUILTIN_EMPTY));
if (isEmpty.booleanValue()) {
isBuiltinEmpty = true;
}
}
if (vList.size() != 0 || isValueEmpty) {
value = vList;
} else {
value = null;
}
if (biList.size() != 0 || isBuiltinEmpty) {
builtIns = biList;
} else {
builtIns = null;
}
break;
default:
break;
}
} catch (BuildException e) {
// TODO: report error
}
// Determine if there needs to be a browse button
if (element.getAttribute(BROWSE_TYPE) != null) {
String browseTypeStr = element.getAttribute(BROWSE_TYPE);
if (browseTypeStr == null) {
// Set to null, to indicate no browse type specification
// This will allow any superclasses to be searched for the
// browse type specification, and thus inherited, if found,
// which they should be
browseType = null;
} else if (browseTypeStr.equals(NONE)) {
browseType = BROWSE_NONE;
} else if (browseTypeStr.equals(FILE)) {
browseType = BROWSE_FILE;
} else if (browseTypeStr.equals(DIR)) {
browseType = BROWSE_DIR;
}
}
// Get the browseFilterPath attribute
if (element.getAttribute(BROWSE_FILTER_PATH) != null) {
this.browseFilterPath = SafeStringInterner.safeIntern(element.getAttribute(BROWSE_FILTER_PATH));
}
// Get the browseFilterExtensions attribute
if (element.getAttribute(BROWSE_FILTER_EXTENSIONS) != null) {
String browseFilterExtensionsStr = element.getAttribute(BROWSE_FILTER_EXTENSIONS);
if (browseFilterExtensionsStr != null) {
this.browseFilterExtensions = SafeStringInterner
.safeIntern(browseFilterExtensionsStr.split("\\s*,\\s*")); //$NON-NLS-1$
}
}
if (element.getAttribute(CATEGORY) != null) {
categoryId = SafeStringInterner.safeIntern(element.getAttribute(CATEGORY));
if (categoryId != null) {
category = holder.getOptionCategory(categoryId);
}
}
// Get the resourceFilter attribute
if (element.getAttribute(RESOURCE_FILTER) != null) {
String resFilterStr = element.getAttribute(RESOURCE_FILTER);
if (resFilterStr == null) {
// Set to null, to indicate no resource filter specification
// This will allow any superclasses to be searched for the
// resource filter specification, and thus inherited, if found,
// which they should be
resourceFilter = null;
} else if (resFilterStr.equals(ALL)) {
resourceFilter = FILTER_ALL;
} else if (resFilterStr.equals(FILE)) {
resourceFilter = FILTER_FILE;
} else if (resFilterStr.equals(PROJECT)) {
resourceFilter = FILTER_PROJECT;
}
}
// Note: valueHandlerElement and VALUE_HANDLER are not restored,
// as they are not saved. See note in serialize().
// valueHandlerExtraArgument
if (element.getAttribute(VALUE_HANDLER_EXTRA_ARGUMENT) != null) {
valueHandlerExtraArgument = SafeStringInterner
.safeIntern(element.getAttribute(VALUE_HANDLER_EXTRA_ARGUMENT));
}
}
private int ValueTypeStrToInt(String valueTypeStr) {
if (valueTypeStr == null) {
return -1;
}
if (valueTypeStr.equals(TYPE_STRING)) {
return STRING;
} else if (valueTypeStr.equals(TYPE_STR_LIST)) {
return STRING_LIST;
} else if (valueTypeStr.equals(TYPE_BOOL)) {
return BOOLEAN;
} else if (valueTypeStr.equals(TYPE_ENUM)) {
return ENUMERATED;
} else if (valueTypeStr.equals(TYPE_INC_PATH)) {
return INCLUDE_PATH;
} else if (valueTypeStr.equals(TYPE_LIB)) {
return LIBRARIES;
} else if (valueTypeStr.equals(TYPE_USER_OBJS)) {
return OBJECTS;
} else if (valueTypeStr.equals(TYPE_DEFINED_SYMBOLS)) {
return PREPROCESSOR_SYMBOLS;
} else if (valueTypeStr.equals(TYPE_LIB_PATHS)) {
return LIBRARY_PATHS;
} else if (valueTypeStr.equals(TYPE_LIB_FILES)) {
return LIBRARY_FILES;
} else if (valueTypeStr.equals(TYPE_INC_FILES)) {
return INCLUDE_FILES;
} else if (valueTypeStr.equals(TYPE_SYMBOL_FILES)) {
return MACRO_FILES;
} else if (valueTypeStr.equals(TYPE_UNDEF_INC_PATH)) {
return UNDEF_INCLUDE_PATH;
} else if (valueTypeStr.equals(TYPE_UNDEF_DEFINED_SYMBOLS)) {
return UNDEF_PREPROCESSOR_SYMBOLS;
} else if (valueTypeStr.equals(TYPE_UNDEF_LIB_PATHS)) {
return UNDEF_LIBRARY_PATHS;
} else if (valueTypeStr.equals(TYPE_UNDEF_LIB_FILES)) {
return UNDEF_LIBRARY_FILES;
} else if (valueTypeStr.equals(TYPE_UNDEF_INC_FILES)) {
return UNDEF_INCLUDE_FILES;
} else if (valueTypeStr.equals(TYPE_UNDEF_SYMBOL_FILES)) {
return UNDEF_MACRO_FILES;
} else if (valueTypeStr.equals(TYPE_TREE)) {
return TREE;
} else {
ManagedBuilderCorePlugin.log(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID,
"Invalid option type=\"" + valueTypeStr + "\" specified for option " + getId())); //$NON-NLS-1$ //$NON-NLS-2$
// This was the CDT 2.0 default
return PREPROCESSOR_SYMBOLS;
}
}
/**
* Persist the option to the {@link ICStorageElement}.
*
* @param element - storage element to persist the option
*/
public void serialize(ICStorageElement element) throws BuildException {
if (superClass != null) {
element.setAttribute(IProjectType.SUPERCLASS, superClass.getId());
} else if (superClassId != null) {
element.setAttribute(IProjectType.SUPERCLASS, superClassId);
}
element.setAttribute(IBuildObject.ID, id);
if (name != null) {
element.setAttribute(IBuildObject.NAME, name);
}
if (unusedChildren != null) {
element.setAttribute(IProjectType.UNUSED_CHILDREN, unusedChildren);
}
if (isAbstract != null) {
element.setAttribute(IProjectType.IS_ABSTRACT, isAbstract.toString());
}
if (command != null) {
element.setAttribute(COMMAND, command);
}
if (commandFalse != null) {
element.setAttribute(COMMAND_FALSE, commandFalse);
}
if (isForScannerDiscovery != null) {
element.setAttribute(USE_BY_SCANNER_DISCOVERY, isForScannerDiscovery.toString());
}
if (tip != null) {
element.setAttribute(TOOL_TIP, tip);
}
if (contextId != null) {
element.setAttribute(CONTEXT_ID, contextId);
}
/*
* Note: We store value & value-type as a pair, so we know what type of value we are
* dealing with when we read it back in.
* This is also true of defaultValue.
*/
boolean storeValueType = false;
// value
if (value != null) {
storeValueType = true;
switch (getValueType()) {
case BOOLEAN:
element.setAttribute(VALUE, ((Boolean) value).toString());
break;
case STRING:
case ENUMERATED:
case TREE:
element.setAttribute(VALUE, (String) value);
break;
case STRING_LIST:
case INCLUDE_PATH:
case PREPROCESSOR_SYMBOLS:
case LIBRARIES:
case OBJECTS:
case INCLUDE_FILES:
case LIBRARY_PATHS:
case LIBRARY_FILES:
case MACRO_FILES:
case UNDEF_INCLUDE_PATH:
case UNDEF_PREPROCESSOR_SYMBOLS:
case UNDEF_INCLUDE_FILES:
case UNDEF_LIBRARY_PATHS:
case UNDEF_LIBRARY_FILES:
case UNDEF_MACRO_FILES:
if (value != null) {
@SuppressWarnings("unchecked")
ArrayList<OptionStringValue> stringList = (ArrayList<OptionStringValue>) value;
for (OptionStringValue optValue : stringList) {
ICStorageElement valueElement = element.createChild(LIST_VALUE);
optValue.serialize(valueElement);
}
if (stringList.isEmpty()) {
element.setAttribute(IS_VALUE_EMPTY, Boolean.TRUE.toString());
} else {
element.setAttribute(IS_VALUE_EMPTY, Boolean.FALSE.toString());
}
} else {
element.setAttribute(IS_VALUE_EMPTY, Boolean.FALSE.toString());
}
// Serialize the built-ins that have been overridden
if (builtIns != null) {
for (OptionStringValue optionValue : builtIns) {
ICStorageElement valueElement = element.createChild(LIST_VALUE);
optionValue.serialize(valueElement);
}
if (builtIns.isEmpty()) {
element.setAttribute(IS_BUILTIN_EMPTY, Boolean.TRUE.toString());
} else {
element.setAttribute(IS_BUILTIN_EMPTY, Boolean.FALSE.toString());
}
} else {
element.setAttribute(IS_BUILTIN_EMPTY, Boolean.FALSE.toString());
}
break;
}
}
// defaultValue
if (defaultValue != null) {
storeValueType = true;
switch (getValueType()) {
case BOOLEAN:
element.setAttribute(DEFAULT_VALUE, ((Boolean) defaultValue).toString());
break;
case STRING:
case ENUMERATED:
case TREE:
element.setAttribute(DEFAULT_VALUE, (String) defaultValue);
break;
default:
break;
}
}
if (storeValueType) {
String str;
switch (getValueType()) {
case BOOLEAN:
str = TYPE_BOOL;
break;
case STRING:
str = TYPE_STRING;
break;
case ENUMERATED:
str = TYPE_ENUM;
break;
case STRING_LIST:
str = TYPE_STR_LIST;
break;
case INCLUDE_PATH:
str = TYPE_INC_PATH;
break;
case LIBRARIES:
str = TYPE_LIB;
break;
case OBJECTS:
str = TYPE_USER_OBJS;
break;
case PREPROCESSOR_SYMBOLS:
str = TYPE_DEFINED_SYMBOLS;
break;
case INCLUDE_FILES:
str = TYPE_INC_FILES;
break;
case LIBRARY_PATHS:
str = TYPE_LIB_PATHS;
break;
case LIBRARY_FILES:
str = TYPE_LIB_FILES;
break;
case MACRO_FILES:
str = TYPE_SYMBOL_FILES;
break;
case UNDEF_INCLUDE_PATH:
str = TYPE_UNDEF_INC_PATH;
break;
case UNDEF_PREPROCESSOR_SYMBOLS:
str = TYPE_UNDEF_DEFINED_SYMBOLS;
break;
case UNDEF_INCLUDE_FILES:
str = TYPE_UNDEF_INC_FILES;
break;
case UNDEF_LIBRARY_PATHS:
str = TYPE_UNDEF_LIB_PATHS;
break;
case UNDEF_LIBRARY_FILES:
str = TYPE_UNDEF_LIB_FILES;
break;
case UNDEF_MACRO_FILES:
str = TYPE_UNDEF_SYMBOL_FILES;
break;
case TREE:
str = TYPE_TREE;
break;
default:
// TODO; is this a problem...
str = EMPTY_STRING;
break;
}
element.setAttribute(VALUE_TYPE, str);
}
// browse type
if (browseType != null) {
String str;
switch (getBrowseType()) {
case BROWSE_NONE:
str = NONE;
break;
case BROWSE_FILE:
str = FILE;
break;
case BROWSE_DIR:
str = DIR;
break;
default:
str = EMPTY_STRING;
break;
}
element.setAttribute(BROWSE_TYPE, str);
}
// browse filter path
if (browseFilterPath != null) {
element.setAttribute(BROWSE_FILTER_PATH, browseFilterPath);
}
// browse filter extensions
if (browseFilterExtensions != null) {
StringBuilder sb = new StringBuilder();
for (String ext : browseFilterExtensions) {
sb.append(ext).append(',');
}
element.setAttribute(BROWSE_FILTER_EXTENSIONS, sb.toString());
}
if (categoryId != null) {
element.setAttribute(CATEGORY, categoryId);
}
// resource filter
if (resourceFilter != null) {
String str;
switch (getResourceFilter()) {
case FILTER_ALL:
str = ALL;
break;
case FILTER_FILE:
str = FILE;
break;
case FILTER_PROJECT:
str = PROJECT;
break;
default:
str = EMPTY_STRING;
break;
}
element.setAttribute(RESOURCE_FILTER, str);
}
// Note: applicability calculator cannot be specified in a project file because
// an IConfigurationElement is needed to load it!
if (applicabilityCalculatorElement != null) {
// TODO: issue warning?
}
// Note: a value handler cannot be specified in a project file because
// an IConfigurationElement is needed to load it!
if (valueHandlerElement != null) {
// TODO: Issue warning? Stuck with behavior of this elsewhere in
// CDT, e.g. the implementation of Tool
}
if (valueHandlerExtraArgument != null) {
element.setAttribute(VALUE_HANDLER_EXTRA_ARGUMENT, valueHandlerExtraArgument);
}
// I am clean now
isDirty = false;
}
@Override
public IOptionContextData getOptionContextData(IHoldsOptions holder) {
return new OptionContextData(this, holder);
}
/*
* P A R E N T A N D C H I L D H A N D L I N G
*/
@Override
public IBuildObject getParent() {
return holder;
}
@Override
public IHoldsOptions getOptionHolder() {
// Do not take superclasses into account
return holder;
}
/*
* M O D E L A T T R I B U T E A C C E S S O R S
*/
@Override
public IOption getSuperClass() {
return superClass;
}
@Override
public String getName() {
return (name == null && superClass != null) ? superClass.getName() : name;
}
@Override
public String[] getApplicableValues() {
// Does this option instance have the list of values?
if (applicableValuesList == null) {
if (superClass != null) {
return superClass.getApplicableValues();
} else {
return EMPTY_STRING_ARRAY;
}
}
// Get all of the enumerated names from the option
if (applicableValuesList.size() == 0) {
return EMPTY_STRING_ARRAY;
} else {
// Return the elements in the order they are specified in the manifest
String[] enumNames = new String[applicableValuesList.size()];
for (int index = 0; index < applicableValuesList.size(); ++index) {
enumNames[index] = getNameMap().get(applicableValuesList.get(index));
}
return enumNames;
}
}
@Override
public boolean getBooleanValue() {
return ((Boolean) getValue()).booleanValue();
}
@Override
public int getBrowseType() {
if (browseType == null) {
if (superClass != null) {
return superClass.getBrowseType();
} else {
return BROWSE_NONE;
}
}
return browseType.intValue();
}
@Override
public String getBrowseFilterPath() {
if (browseFilterPath == null) {
if (superClass != null) {
return superClass.getBrowseFilterPath();
} else {
return null;
}
}
return browseFilterPath;
}
@Override
public String[] getBrowseFilterExtensions() {
if (browseFilterExtensions == null) {
if (superClass != null) {
return superClass.getBrowseFilterExtensions();
} else {
return null;
}
}
return browseFilterExtensions.clone();
}
@Override
public int getResourceFilter() {
if (resourceFilter == null) {
if (superClass != null) {
return superClass.getResourceFilter();
} else {
return FILTER_ALL;
}
}
return resourceFilter.intValue();
}
public IConfigurationElement getApplicabilityCalculatorElement() {
/* if (applicabilityCalculatorElement == null) {
if (superClass != null) {
return ((Option)superClass).getApplicabilityCalculatorElement();
}
}
*/
return applicabilityCalculatorElement;
}
@Override
public IOptionApplicability getApplicabilityCalculator() {
if (applicabilityCalculator == null) {
if (applicabilityCalculatorElement != null) {
try {
if (applicabilityCalculatorElement.getAttribute(APPLICABILITY_CALCULATOR) != null) {
applicabilityCalculator = (IOptionApplicability) applicabilityCalculatorElement
.createExecutableExtension(APPLICABILITY_CALCULATOR);
}
} catch (CoreException e) {
ManagedBuilderCorePlugin.log(e);
}
} else if (superClass != null) {
applicabilityCalculator = superClass.getApplicabilityCalculator();
}
}
return applicabilityCalculator;
}
@Override
public String[] getBuiltIns() {
// Return the list of built-ins as an array
List<OptionStringValue> list = getExactBuiltinsList();
List<String> valueList = listValueListToValueList(list);
if (valueList == null) {
return EMPTY_STRING_ARRAY;
}
return valueList.toArray(new String[valueList.size()]);
}
public List<OptionStringValue> getExactBuiltinsList() {
// Return the list of built-ins as an array
if (builtIns == null) {
if (superClass != null) {
return ((Option) superClass).getExactBuiltinsList();
} else {
return null;
}
}
return builtIns;
}
@Override
public IOptionCategory getCategory() {
if (category == null) {
if (superClass != null) {
return superClass.getCategory();
} else {
if (getOptionHolder() instanceof ITool) {
return ((ITool) getOptionHolder()).getTopOptionCategory();
} else {
return null;
}
}
}
return category;
}
@Override
public IOptionDefaultValueGenerator getDefaultValueGenerator() {
if (defaultValueGenerator == null) {
if (defaultValueGeneratorElement != null) {
try {
if (defaultValueGeneratorElement.getAttribute(DEFAULTVALUE_GENERATOR) != null) {
defaultValueGenerator = (IOptionDefaultValueGenerator) defaultValueGeneratorElement
.createExecutableExtension(DEFAULTVALUE_GENERATOR);
}
} catch (CoreException e) {
ManagedBuilderCorePlugin.log(e);
}
} else if (superClass != null) {
defaultValueGenerator = superClass.getDefaultValueGenerator();
}
}
return defaultValueGenerator;
}
@Override
public String getCommand() {
if (command == null) {
if (superClass != null) {
return superClass.getCommand();
} else {
return EMPTY_STRING;
}
}
return command;
}
@Override
public IOptionCommandGenerator getCommandGenerator() {
if (commandGenerator == null) {
if (commandGeneratorElement != null) {
try {
if (commandGeneratorElement.getAttribute(COMMAND_GENERATOR) != null) {
commandGenerator = (IOptionCommandGenerator) commandGeneratorElement
.createExecutableExtension(COMMAND_GENERATOR);
}
} catch (CoreException e) {
ManagedBuilderCorePlugin.log(e);
}
} else if (superClass != null) {
commandGenerator = superClass.getCommandGenerator();
}
}
return commandGenerator;
}
@Override
public String getCommandFalse() {
if (commandFalse == null) {
if (superClass != null) {
return superClass.getCommandFalse();
} else {
return EMPTY_STRING;
}
}
return commandFalse;
}
@Override
public boolean isForScannerDiscovery() {
if (isForScannerDiscovery == null) {
isForScannerDiscovery = superClass != null && superClass.isForScannerDiscovery();
}
return isForScannerDiscovery;
}
@Override
public String getToolTip() {
if (tip == null) {
if (superClass != null) {
return superClass.getToolTip();
} else {
return EMPTY_STRING;
}
}
return tip;
}
@Override
public String getContextId() {
if (contextId == null) {
if (superClass != null) {
return superClass.getContextId();
} else {
return EMPTY_STRING;
}
}
return contextId;
}
@Override
public String[] getDefinedSymbols() throws BuildException {
if (getValueType() != PREPROCESSOR_SYMBOLS) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
@SuppressWarnings("unchecked")
ArrayList<String> v = (ArrayList<String>) getValue();
if (v == null) {
return EMPTY_STRING_ARRAY;
} else {
v.trimToSize();
return v.toArray(new String[v.size()]);
}
}
@Override
public String getCommand(String id) throws BuildException {
// Sanity
if (id == null) {
return EMPTY_STRING;
}
// Does this option instance have the list of values?
if (applicableValuesList == null) {
if (superClass != null) {
return superClass.getCommand(id);
} else {
return EMPTY_STRING;
}
}
if (getValueType() != ENUMERATED && getValueType() != TREE) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
// First check for the command in ID->command map
String cmd = getCommandMap().get(id);
if (cmd == null) {
// This may be a 1.2 project or plugin manifest. If so, the argument is the human readable
// name of the enumeration. Search for the ID that maps to the name and use that to find the
// command.
for (String realID : applicableValuesList) {
String name = getNameMap().get(realID);
if (id.equals(name)) {
cmd = getCommandMap().get(realID);
break;
}
}
}
return cmd == null ? EMPTY_STRING : cmd;
}
@Override
public String getEnumCommand(String id) throws BuildException {
return getCommand(id);
}
@Override
public String getEnumName(String id) throws BuildException {
return getName(id);
}
@Override
public String getName(String id) throws BuildException {
// Sanity
if (id == null) {
return EMPTY_STRING;
}
// Does this option instance have the list of values?
if (applicableValuesList == null) {
if (superClass != null) {
return superClass.getName(id);
} else {
return EMPTY_STRING;
}
}
if (getValueType() != ENUMERATED) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
// First check for the command in ID->name map
String name = getNameMap().get(id);
if (name == null) {
// This may be a 1.2 project or plugin manifest. If so, the argument is the human readable
// name of the enumeration.
name = id;
}
return name;
}
/**
* A memory-safe accessor to the map of enumerated option value IDs to the commands
* that a tool understands.
*
* @return a Map of enumerated option value IDs to actual commands that are passed
* to a tool on the command line.
*/
private Map<String, String> getCommandMap() {
if (commandsMap == null) {
commandsMap = new HashMap<>();
}
return commandsMap;
}
@Override
public String getEnumeratedId(String name) throws BuildException {
return getId(name);
}
@Override
public String getId(String name) throws BuildException {
if (name == null) {
return null;
}
// Does this option instance have the list of values?
if (applicableValuesList == null) {
if (superClass != null) {
return superClass.getId(name);
} else {
return EMPTY_STRING;
}
}
if (getValueType() != ENUMERATED && getValueType() != TREE) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
Set<String> idSet = getNameMap().keySet();
for (String id : idSet) {
String enumName = getNameMap().get(id);
if (name.equals(enumName)) {
return id;
}
}
return null;
}
/**
* @return a Map of enumerated option value IDs to the selection displayed to the user.
*/
private Map<String, String> getNameMap() {
if (namesMap == null) {
namesMap = new HashMap<>();
}
return namesMap;
}
@Override
public String[] getIncludePaths() throws BuildException {
if (getValueType() != INCLUDE_PATH) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
@SuppressWarnings("unchecked")
ArrayList<String> v = (ArrayList<String>) getValue();
if (v == null) {
return EMPTY_STRING_ARRAY;
} else {
v.trimToSize();
return v.toArray(new String[v.size()]);
}
}
@Override
public String[] getLibraries() throws BuildException {
if (getValueType() != LIBRARIES) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
@SuppressWarnings("unchecked")
ArrayList<String> v = (ArrayList<String>) getValue();
if (v == null) {
return EMPTY_STRING_ARRAY;
} else {
v.trimToSize();
return v.toArray(new String[v.size()]);
}
}
@Override
public String[] getLibraryFiles() throws BuildException {
if (getValueType() != LIBRARY_FILES) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
@SuppressWarnings("unchecked")
ArrayList<String> v = (ArrayList<String>) getValue();
if (v == null) {
return EMPTY_STRING_ARRAY;
} else {
v.trimToSize();
return v.toArray(new String[v.size()]);
}
}
@Override
public String[] getLibraryPaths() throws BuildException {
if (getValueType() != LIBRARY_PATHS) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
@SuppressWarnings("unchecked")
ArrayList<String> v = (ArrayList<String>) getValue();
if (v == null) {
return EMPTY_STRING_ARRAY;
} else {
v.trimToSize();
return v.toArray(new String[v.size()]);
}
}
@Override
public String getSelectedEnum() throws BuildException {
if (getValueType() != ENUMERATED) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
return getStringValue();
}
@Override
public String[] getStringListValue() throws BuildException {
if (getValueType() != STRING_LIST) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
@SuppressWarnings("unchecked")
ArrayList<String> v = (ArrayList<String>) getValue();
if (v == null) {
return EMPTY_STRING_ARRAY;
} else {
v.trimToSize();
return v.toArray(new String[v.size()]);
}
}
@Override
public String getStringValue() throws BuildException {
if (getValueType() != STRING && getValueType() != ENUMERATED && getValueType() != TREE) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
return getValue() == null ? EMPTY_STRING : (String) getValue();
}
@Override
public String[] getUserObjects() throws BuildException {
if (getValueType() != OBJECTS) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
// This is the right puppy, so return its list value
@SuppressWarnings("unchecked")
ArrayList<String> v = (ArrayList<String>) getValue();
if (v == null) {
return EMPTY_STRING_ARRAY;
} else {
v.trimToSize();
return v.toArray(new String[v.size()]);
}
}
@Override
public int getValueType() throws BuildException {
if (valueType == null) {
if (superClass != null) {
return superClass.getValueType();
} else {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$;
}
}
return valueType.intValue();
}
/**
* Gets the value, applying appropriate defaults if necessary.
*/
@Override
public Object getValue() {
/*
* In order to determine the current value of an option, perform the following steps until a value is found:
* 1. Examine the value attribute of the option.
* 2. Examine the value attribute of the option's superClass recursively.
* 3. Examine the dynamicDefaultValue attribute of the option and invoke it if specified. (not yet implemented)
* 4. Examine the defaultValue attribute of the option.
* 5. Examine the dynamicDefaultValue attribute of the option's superClass and invoke it if specified. (not yet implemented)
* 6. Examine the defaultValue attribute of the option's superClass.
* 7. Go to step 5 recursively until no more super classes.
* 8. Use the default value for the option type.
*/
Object val = getRawValue();
if (val == null) {
val = getDefaultValue();
if (val == null) {
int valType;
try {
valType = getValueType();
} catch (BuildException e) {
return EMPTY_STRING;
}
switch (valType) {
case BOOLEAN:
val = Boolean.FALSE;
break;
case STRING:
case TREE:
val = EMPTY_STRING;
break;
case ENUMERATED:
// TODO: Can we default to the first enumerated id?
val = EMPTY_STRING;
break;
case STRING_LIST:
case INCLUDE_PATH:
case PREPROCESSOR_SYMBOLS:
case LIBRARIES:
case OBJECTS:
case INCLUDE_FILES:
case LIBRARY_PATHS:
case LIBRARY_FILES:
case MACRO_FILES:
case UNDEF_INCLUDE_PATH:
case UNDEF_PREPROCESSOR_SYMBOLS:
case UNDEF_INCLUDE_FILES:
case UNDEF_LIBRARY_PATHS:
case UNDEF_LIBRARY_FILES:
case UNDEF_MACRO_FILES:
val = new ArrayList<String>();
break;
default:
val = EMPTY_STRING;
break;
}
}
}
return val;
}
public Object getExactValue() {
/*
* In order to determine the current value of an option, perform the following steps until a value is found:
* 1. Examine the value attribute of the option.
* 2. Examine the value attribute of the option's superClass recursively.
* 3. Examine the dynamicDefaultValue attribute of the option and invoke it if specified. (not yet implemented)
* 4. Examine the defaultValue attribute of the option.
* 5. Examine the dynamicDefaultValue attribute of the option's superClass and invoke it if specified. (not yet implemented)
* 6. Examine the defaultValue attribute of the option's superClass.
* 7. Go to step 5 recursively until no more super classes.
* 8. Use the default value for the option type.
*/
Object val = getExactRawValue();
if (val == null) {
val = getExactDefaultValue();
if (val == null) {
int valType;
try {
valType = getValueType();
} catch (BuildException e) {
return EMPTY_STRING;
}
switch (valType) {
case BOOLEAN:
val = Boolean.FALSE;
break;
case STRING:
case TREE:
val = EMPTY_STRING;
break;
case ENUMERATED:
// TODO: Can we default to the first enumerated id?
val = EMPTY_STRING;
break;
case STRING_LIST:
case INCLUDE_PATH:
case PREPROCESSOR_SYMBOLS:
case LIBRARIES:
case OBJECTS:
case INCLUDE_FILES:
case LIBRARY_PATHS:
case LIBRARY_FILES:
case MACRO_FILES:
case UNDEF_INCLUDE_PATH:
case UNDEF_PREPROCESSOR_SYMBOLS:
case UNDEF_INCLUDE_FILES:
case UNDEF_LIBRARY_PATHS:
case UNDEF_LIBRARY_FILES:
case UNDEF_MACRO_FILES:
val = new ArrayList<OptionStringValue>();
break;
default:
val = EMPTY_STRING;
break;
}
}
}
return val;
}
/**
* Gets the raw value, applying appropriate defauls if necessary.
*/
public Object getRawValue() {
Object ev = getExactRawValue();
if (ev instanceof List<?>) {
@SuppressWarnings("unchecked")
List<String> evList = listValueListToValueList((List<OptionStringValue>) ev);
return evList;
}
return ev;
}
public Object getExactRawValue() {
if (value == null) {
if (superClass != null) {
Option mySuperClass = (Option) superClass;
return mySuperClass.getExactRawValue();
}
}
return value;
}
private List<String> listValueListToValueList(List<OptionStringValue> list) {
if (list == null) {
return null;
}
List<String> valueList = new ArrayList<>(list.size());
for (int i = 0; i < list.size(); i++) {
OptionStringValue el = list.get(i);
valueList.add(el.getValue());
}
return valueList;
}
private List<OptionStringValue> valueListToListValueList(List<String> list, boolean builtIn) {
if (list == null) {
return null;
}
List<OptionStringValue> lvList = new ArrayList<>(list.size());
for (int i = 0; i < list.size(); i++) {
String v = list.get(i);
lvList.add(new OptionStringValue(v, builtIn));
}
return lvList;
}
/**
* Gets the raw default value.
*/
@Override
public Object getDefaultValue() {
Object ev = getExactDefaultValue();
if (ev instanceof List<?>) {
@SuppressWarnings("unchecked")
List<String> evList = listValueListToValueList((List<OptionStringValue>) ev);
return evList;
}
return ev;
}
public Object getExactDefaultValue() {
// Note: string-list options do not have a default value
if (defaultValue == null) {
if (superClass != null) {
return ((Option) superClass).getExactDefaultValue();
}
}
return defaultValue;
}
@Override
public void setDefaultValue(Object v) {
if (v instanceof List<?>) {
@SuppressWarnings("unchecked")
List<OptionStringValue> vList = valueListToListValueList((List<String>) v, false);
defaultValue = vList;
} else {
defaultValue = v;
}
if (!isExtensionElement()) {
setDirty(true);
rebuildState = true;
}
}
@Override
public void setCategory(IOptionCategory category) {
if (this.category != category) {
this.category = category;
if (category != null) {
categoryId = category.getId();
} else {
categoryId = null;
}
if (!isExtensionElement()) {
setDirty(true);
rebuildState = true;
}
}
}
@Override
public void setCommand(String cmd) {
if (cmd == null && command == null) {
return;
}
if (cmd == null || command == null || !cmd.equals(command)) {
command = cmd;
if (!isExtensionElement()) {
isDirty = true;
rebuildState = true;
}
}
}
@Override
public void setCommandFalse(String cmd) {
if (cmd == null && commandFalse == null) {
return;
}
if (cmd == null || commandFalse == null || !cmd.equals(commandFalse)) {
commandFalse = cmd;
if (!isExtensionElement()) {
isDirty = true;
rebuildState = true;
}
}
}
@Override
public void setToolTip(String tooltip) {
if (tooltip == null && tip == null) {
return;
}
if (tooltip == null || tip == null || !tooltip.equals(tip)) {
tip = tooltip;
if (!isExtensionElement()) {
isDirty = true;
rebuildState = true;
}
}
}
@Override
public void setContextId(String id) {
if (id == null && contextId == null) {
return;
}
if (id == null || contextId == null || !id.equals(contextId)) {
contextId = id;
if (!isExtensionElement()) {
isDirty = true;
rebuildState = true;
}
}
}
@Override
public void setResourceFilter(int filter) {
if (resourceFilter == null || !(filter == resourceFilter.intValue())) {
resourceFilter = Integer.valueOf(filter);
if (!isExtensionElement()) {
isDirty = true;
rebuildState = true;
}
}
}
@Override
public void setBrowseType(int type) {
if (browseType == null || !(type == browseType.intValue())) {
browseType = Integer.valueOf(type);
if (!isExtensionElement()) {
isDirty = true;
rebuildState = true;
}
}
}
@Override
public void setBrowseFilterPath(String path) {
if (browseFilterPath == null || !(browseFilterPath.equals(path))) {
browseFilterPath = path;
if (!isExtensionElement()) {
isDirty = true;
rebuildState = true;
}
}
}
@Override
public void setBrowseFilterExtensions(String[] extensions) {
if (browseFilterExtensions == null || !(browseFilterExtensions.equals(extensions))) {
browseFilterExtensions = extensions;
if (!isExtensionElement()) {
isDirty = true;
rebuildState = true;
}
}
}
@Override
public void setValue(boolean value) throws BuildException {
if (/*!isExtensionElement() && */getValueType() == BOOLEAN) {
this.value = value;
} else {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
if (!isExtensionElement()) {
setDirty(true);
rebuildState = true;
}
}
@Override
public void setValue(String value) throws BuildException {
// Note that we can still set the human-readable value here
if (/*!isExtensionElement() && */(getValueType() == STRING || getValueType() == ENUMERATED
|| getValueType() == TREE)) {
this.value = value;
} else {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
if (!isExtensionElement()) {
setDirty(true);
rebuildState = true;
}
}
@Override
public void setValue(String[] value) throws BuildException {
if (/*!isExtensionElement() && */
(getValueType() == STRING_LIST || getValueType() == INCLUDE_PATH || getValueType() == PREPROCESSOR_SYMBOLS
|| getValueType() == LIBRARIES || getValueType() == OBJECTS || getValueType() == INCLUDE_FILES
|| getValueType() == LIBRARY_PATHS || getValueType() == LIBRARY_FILES || getValueType() == MACRO_FILES
|| getValueType() == UNDEF_INCLUDE_PATH || getValueType() == UNDEF_PREPROCESSOR_SYMBOLS
|| getValueType() == UNDEF_INCLUDE_FILES || getValueType() == UNDEF_LIBRARY_PATHS
|| getValueType() == UNDEF_LIBRARY_FILES || getValueType() == UNDEF_MACRO_FILES)) {
// Just replace what the option reference is holding onto
if (value == null) {
this.value = null;
} else {
this.value = valueListToListValueList(Arrays.asList(value), false);
}
} else {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
if (!isExtensionElement()) {
setDirty(true);
rebuildState = true;
}
}
public void setValue(OptionStringValue[] value) throws BuildException {
if (/*!isExtensionElement() && */
(getValueType() == STRING_LIST || getValueType() == INCLUDE_PATH || getValueType() == PREPROCESSOR_SYMBOLS
|| getValueType() == LIBRARIES || getValueType() == OBJECTS || getValueType() == INCLUDE_FILES
|| getValueType() == LIBRARY_PATHS || getValueType() == LIBRARY_FILES || getValueType() == MACRO_FILES
|| getValueType() == UNDEF_INCLUDE_PATH || getValueType() == UNDEF_PREPROCESSOR_SYMBOLS
|| getValueType() == UNDEF_INCLUDE_FILES || getValueType() == UNDEF_LIBRARY_PATHS
|| getValueType() == UNDEF_LIBRARY_FILES || getValueType() == UNDEF_MACRO_FILES)) {
// Just replace what the option reference is holding onto
if (value == null) {
this.value = null;
} else {
this.value = new ArrayList<>(Arrays.asList(value));
}
} else {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
if (!isExtensionElement()) {
setDirty(true);
rebuildState = true;
}
}
@Override
public void setValue(Object v) {
if (v instanceof List<?>) {
@SuppressWarnings("unchecked")
List<OptionStringValue> vList = valueListToListValueList((List<String>) v, false);
value = vList;
} else {
value = v;
}
if (!isExtensionElement()) {
setDirty(true);
rebuildState = true;
}
}
@Override
public void setValueType(int type) {
// TODO: Verify that this is a valid type
if (valueType == null || valueType.intValue() != type) {
valueType = Integer.valueOf(type);
if (!isExtensionElement()) {
setDirty(true);
rebuildState = true;
}
}
}
public IConfigurationElement getValueHandlerElement() {
if (valueHandlerElement == null) {
if (superClass != null) {
return ((Option) superClass).getValueHandlerElement();
}
}
return valueHandlerElement;
}
public void setValueHandlerElement(IConfigurationElement element) {
valueHandlerElement = element;
if (!isExtensionElement()) {
setDirty(true);
rebuildState = true;
}
}
@Override
public IManagedOptionValueHandler getValueHandler() {
if (valueHandler != null) {
return valueHandler;
}
IConfigurationElement element = getValueHandlerElement();
if (element != null) {
try {
if (element.getAttribute(VALUE_HANDLER) != null) {
valueHandler = (IManagedOptionValueHandler) element.createExecutableExtension(VALUE_HANDLER);
return valueHandler;
}
} catch (CoreException e) {
ManagedBuildManager.optionValueHandlerError(element.getAttribute(VALUE_HANDLER), getId());
// Assign the default handler to avoid further error messages
valueHandler = ManagedOptionValueHandler.getManagedOptionValueHandler();
return valueHandler;
}
}
// If no handler is provided, then use the default handler
return ManagedOptionValueHandler.getManagedOptionValueHandler();
}
@Override
public String getValueHandlerExtraArgument() {
if (valueHandlerExtraArgument == null) {
if (superClass != null) {
return superClass.getValueHandlerExtraArgument();
} else {
return EMPTY_STRING;
}
}
return valueHandlerExtraArgument;
}
@Override
public void setValueHandlerExtraArgument(String extraArgument) {
if (extraArgument == null && valueHandlerExtraArgument == null) {
return;
}
if (extraArgument == null || valueHandlerExtraArgument == null
|| !extraArgument.equals(valueHandlerExtraArgument)) {
valueHandlerExtraArgument = extraArgument;
if (!isExtensionElement()) {
isDirty = true;
rebuildState = true;
}
}
}
@Override
public String getFieldEditorId() {
if (fieldEditorId == null) {
if (superClass != null) {
return ((Option) superClass).getFieldEditorId();
}
}
return fieldEditorId;
}
@Override
public String getFieldEditorExtraArgument() {
if (fieldEditorExtraArgument == null) {
if (superClass != null) {
return superClass.getFieldEditorExtraArgument();
} else {
return null;
}
}
return fieldEditorExtraArgument;
}
@Override
public void setFieldEditorExtraArgument(String extraArgument) {
if (extraArgument == null && fieldEditorExtraArgument == null) {
return;
}
if (extraArgument == null || fieldEditorExtraArgument == null
|| !extraArgument.equals(fieldEditorExtraArgument)) {
fieldEditorExtraArgument = extraArgument;
if (!isExtensionElement()) {
isDirty = true;
rebuildState = true;
}
}
}
/*
* O B J E C T S T A T E M A I N T E N A N C E
*/
@Override
public boolean isExtensionElement() {
return isExtensionOption;
}
public boolean isDirty() {
// This shouldn't be called for an extension option
if (isExtensionOption) {
return false;
}
return isDirty;
}
public void setDirty(boolean isDirty) {
this.isDirty = isDirty;
}
public void resolveReferences() {
if (!resolved) {
resolved = true;
// Resolve superClass
if (superClassId != null && superClassId.length() > 0) {
superClass = ManagedBuildManager.getExtensionOption(superClassId);
if (superClass == null) {
// Report error
ManagedBuildManager.outputResolveError("superClass", //$NON-NLS-1$
superClassId, "option", //$NON-NLS-1$
getId());
} else {
// All of our superclasses must be resolved in order to call
// getValueType below.
((Option) superClass).resolveReferences();
}
}
if (categoryId != null) {
category = holder.getOptionCategory(categoryId);
if (category == null) {
// Report error
ManagedBuildManager.outputResolveError("category", //$NON-NLS-1$
categoryId, "option", //$NON-NLS-1$
getId());
}
}
// Process the value and default value attributes. This is delayed until now
// because we may not know the valueType until after we have resolved the superClass above
// Now get the actual value
try {
IManagedConfigElement element = ManagedBuildManager.getConfigElement(this);
switch (getValueType()) {
case BOOLEAN:
// Convert the string to a boolean
String val = element.getAttribute(VALUE);
if (val != null) {
value = Boolean.valueOf(val);
}
val = element.getAttribute(DEFAULT_VALUE);
if (val != null) {
defaultValue = Boolean.valueOf(val);
}
break;
case STRING:
// Just get the value out of the option directly
value = element.getAttribute(VALUE);
defaultValue = element.getAttribute(DEFAULT_VALUE);
break;
case ENUMERATED:
value = element.getAttribute(VALUE);
defaultValue = element.getAttribute(DEFAULT_VALUE);
// Do we have enumeratedOptionValue children? If so, load them
// to define the valid values and the default value.
IManagedConfigElement[] enumElements = element.getChildren(ENUM_VALUE);
for (int i = 0; i < enumElements.length; ++i) {
String optId = SafeStringInterner.safeIntern(enumElements[i].getAttribute(ID));
if (i == 0) {
applicableValuesList = new ArrayList<>();
if (defaultValue == null) {
defaultValue = optId; // Default value to be overridden if default is specified
}
}
applicableValuesList.add(optId);
getCommandMap().put(optId,
SafeStringInterner.safeIntern(enumElements[i].getAttribute(COMMAND)));
getNameMap().put(optId, SafeStringInterner.safeIntern(enumElements[i].getAttribute(NAME)));
Boolean isDefault = Boolean.valueOf(enumElements[i].getAttribute(IS_DEFAULT));
if (isDefault.booleanValue()) {
defaultValue = optId;
}
}
break;
case TREE:
value = element.getAttribute(VALUE);
defaultValue = element.getAttribute(DEFAULT_VALUE);
IManagedConfigElement[] treeRootConfigs = element.getChildren(TREE_ROOT);
if (treeRootConfigs != null && treeRootConfigs.length == 1) {
IManagedConfigElement treeRootConfig = treeRootConfigs[0];
treeRoot = new TreeRoot(treeRootConfig, element, getParent() instanceof IToolChain);
applicableValuesList = new ArrayList<>();
iterateOnTree(treeRoot, new ITreeNodeIterator() {
@Override
public void iterateOnNode(ITreeOption node) {
}
@Override
public void iterateOnLeaf(ITreeOption leafNode) {
applicableValuesList.add(leafNode.getID());
getCommandMap().put(leafNode.getID(), leafNode.getCommand());
getNameMap().put(leafNode.getID(), leafNode.getName());
}
});
}
break;
case STRING_LIST:
case INCLUDE_PATH:
case PREPROCESSOR_SYMBOLS:
case LIBRARIES:
case OBJECTS:
case INCLUDE_FILES:
case LIBRARY_PATHS:
case LIBRARY_FILES:
case MACRO_FILES:
case UNDEF_INCLUDE_PATH:
case UNDEF_PREPROCESSOR_SYMBOLS:
case UNDEF_INCLUDE_FILES:
case UNDEF_LIBRARY_PATHS:
case UNDEF_LIBRARY_FILES:
case UNDEF_MACRO_FILES:
// Note: These string-list options do not load either the "value" or
// "defaultValue" attributes. Instead, the ListOptionValue children
// are loaded in the value field.
List<OptionStringValue> vList = null;
IManagedConfigElement[] vElements = element.getChildren(LIST_VALUE);
for (IManagedConfigElement vElement : vElements) {
if (vList == null) {
vList = new ArrayList<>();
builtIns = new ArrayList<>();
}
OptionStringValue ve = new OptionStringValue(vElement);
if (ve.isBuiltIn()) {
builtIns.add(ve);
} else {
vList.add(ve);
}
}
value = vList;
break;
default:
break;
}
} catch (BuildException e) {
// TODO: report error
}
}
}
/**
* @return Returns the managedBuildRevision.
*/
@Override
public String getManagedBuildRevision() {
if (managedBuildRevision == null) {
if (getParent() != null) {
return getParent().getManagedBuildRevision();
}
}
return managedBuildRevision;
}
/* (non-Javadoc)
* For now implement this method just as a utility to make code
* within the Option class cleaner.
* TODO: In future we may want to move this to IOption
*/
protected boolean isAbstract() {
if (isAbstract != null) {
return isAbstract.booleanValue();
} else {
return false; // Note: no inheritance from superClass
}
}
/**
* Verifies whether the option is valid and handles
* any errors for the option. The following errors
* can occur:
* (a) Options that are children of a ToolChain must
* ALWAYS have a category
* (b) Options that are children of a ToolChain must
* NEVER have a resourceFilter of "file".
* If an error occurs, the option is set to being invalid.
*
* @pre All references have been resolved.
*/
private void verify() {
if (verified) {
return;
}
verified = true;
// Ignore elements that are superclasses
if (getOptionHolder() instanceof IToolChain && isAbstract() == false) {
// Check for error (a)
if (getCategory() == null) {
ManagedBuildManager.optionValidError(ManagedBuildManager.ERROR_CATEGORY, getId());
// Object becomes invalid
isValid = false;
}
// Check for error (b). Not specifying an attribute is OK.
// Do not use getResourceFilter as it does not allow
// differentiating between "all" and no attribute specified.
if (resourceFilter != null) {
switch (getResourceFilter()) {
case IOption.FILTER_FILE:
// TODO: Cannot differentiate between "all" and attribute not
// specified. Thus do not produce an error. We can argue that "all"
// means all valid resource configurations.
ManagedBuildManager.optionValidError(ManagedBuildManager.ERROR_FILTER, getId());
// Object becomes invalid
isValid = false;
}
}
}
}
@Override
public boolean isValid() {
// We use a lazy scheme to check whether the option is valid.
// Note that by default an option is valid. verify() is only called if
// the option has been resolved. This gets us around having to deal with
// ordering problems during a resolve, or introducing another global
// stage to verify the configuration after a resolve.
// The trade-off is that errors in the MBS grammar may not be
// detected on load, but only when a particular grammar element
// is used, say in the GUI.
if (verified == false && resolved == true) {
verify();
}
return isValid;
}
/**
* @return Returns true if this Option was created from an MBS 2.0 model
* OptionReference element.
*/
public boolean wasOptRef() {
return wasOptRef;
}
public void setWasOptRef(boolean was) {
wasOptRef = was;
}
/**
* @return Returns the version.
*/
@Override
public Version getVersion() {
if (version == null) {
if (getParent() != null) {
return getParent().getVersion();
}
}
return version;
}
@Override
public void setVersion(Version version) {
// Do nothing
}
public BooleanExpressionApplicabilityCalculator getBooleanExpressionCalculator(boolean isExtensionAdjustment) {
if (booleanExpressionCalculator == null && !isExtensionAdjustment) {
if (superClass != null) {
return ((Option) superClass).getBooleanExpressionCalculator(isExtensionAdjustment);
}
}
return booleanExpressionCalculator;
}
public boolean isAdjustedExtension() {
return isUdjusted;
}
public void setAdjusted(boolean adjusted) {
isUdjusted = adjusted;
}
public void setSuperClass(IOption superClass) {
if (this.superClass != superClass) {
this.superClass = superClass;
if (this.superClass == null) {
superClassId = null;
} else {
superClassId = this.superClass.getId();
}
if (!isExtensionElement()) {
setDirty(true);
}
}
}
public boolean needsRebuild() {
return rebuildState;
}
public void setRebuildState(boolean rebuild) {
if (isExtensionElement() && rebuild) {
return;
}
rebuildState = rebuild;
}
public boolean matches(IOption option) {
try {
if (option.getValueType() != getValueType()) {
return false;
}
if (!option.getName().equals(getName())) {
return false;
}
} catch (BuildException e) {
return false;
}
return true;
}
@Override
public String[] getRequiredTypeIds() {
return new String[0];
}
@Override
public String[] getSupportedTypeIds() {
String referenced[] = null;
BooleanExpressionApplicabilityCalculator calc = getBooleanExpressionCalculator(false);
if (calc != null) {
referenced = calc.getReferencedPropertyIds();
}
if (referenced == null) {
referenced = new String[0];
}
return referenced;
}
@Override
public String[] getSupportedValueIds(String typeId) {
String referenced[] = null;
BooleanExpressionApplicabilityCalculator calc = getBooleanExpressionCalculator(false);
if (calc != null) {
referenced = calc.getReferencedValueIds(typeId);
}
if (referenced == null) {
referenced = new String[0];
}
return referenced;
}
@Override
public boolean requiresType(String typeId) {
return false;
}
@Override
public boolean supportsType(String id) {
boolean supports = false;
BooleanExpressionApplicabilityCalculator calc = getBooleanExpressionCalculator(false);
if (calc != null) {
if (calc.referesProperty(id)) {
supports = true;
}
}
return supports;
}
@Override
public boolean supportsValue(String typeId, String valueId) {
boolean supports = false;
BooleanExpressionApplicabilityCalculator calc = getBooleanExpressionCalculator(false);
if (calc != null) {
if (calc.referesPropertyValue(typeId, valueId)) {
supports = true;
}
}
return supports;
}
@Override
public String[] getBasicStringListValue() throws BuildException {
if (getBasicValueType() != STRING_LIST) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
@SuppressWarnings("unchecked")
ArrayList<String> v = (ArrayList<String>) getValue();
if (v == null) {
return EMPTY_STRING_ARRAY;
}
return v.toArray(new String[v.size()]);
}
@Override
public OptionStringValue[] getBasicStringListValueElements() throws BuildException {
if (getBasicValueType() != STRING_LIST) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
@SuppressWarnings("unchecked")
ArrayList<OptionStringValue> v = (ArrayList<OptionStringValue>) getExactValue();
if (v == null) {
return EMPTY_LV_ARRAY;
}
return v.toArray(new OptionStringValue[v.size()]);
}
@Override
public int getBasicValueType() throws BuildException {
switch (getValueType()) {
case IOption.BOOLEAN:
return IOption.BOOLEAN;
case IOption.STRING:
return IOption.STRING;
case IOption.ENUMERATED:
return IOption.ENUMERATED;
case IOption.TREE:
return IOption.TREE;
default:
return IOption.STRING_LIST;
}
}
public boolean hasCustomSettings() {
if (superClass == null) {
return true;
}
if (value != null && !value.equals(superClass.getValue())) {
return true;
}
return false;
}
public static int getOppositeType(int type) {
switch (type) {
case INCLUDE_PATH:
return UNDEF_INCLUDE_PATH;
case PREPROCESSOR_SYMBOLS:
return UNDEF_PREPROCESSOR_SYMBOLS;
case INCLUDE_FILES:
return UNDEF_INCLUDE_FILES;
case LIBRARY_PATHS:
return UNDEF_LIBRARY_PATHS;
case LIBRARY_FILES:
return UNDEF_LIBRARY_FILES;
case MACRO_FILES:
return UNDEF_MACRO_FILES;
case UNDEF_INCLUDE_PATH:
return INCLUDE_PATH;
case UNDEF_PREPROCESSOR_SYMBOLS:
return PREPROCESSOR_SYMBOLS;
case UNDEF_INCLUDE_FILES:
return INCLUDE_FILES;
case UNDEF_LIBRARY_PATHS:
return LIBRARY_PATHS;
case UNDEF_LIBRARY_FILES:
return LIBRARY_FILES;
case UNDEF_MACRO_FILES:
return MACRO_FILES;
}
return 0;
}
public static class TreeRoot extends TreeOption implements ITreeRoot {
private boolean selectLeafOnly = true;
TreeRoot(IManagedConfigElement element, IManagedConfigElement buildOption, boolean readTool) {
super(element, null, readTool);
String leaf = element.getAttribute(SELECT_LEAF_ONLY);
if (leaf != null) {
selectLeafOnly = Boolean.valueOf(leaf);
}
String toolTip = buildOption.getAttribute(TOOL_TIP);
if (description == null && toolTip != null) {
description = toolTip;
}
}
public TreeRoot() {
super("", "", null); //$NON-NLS-1$ //$NON-NLS-2$
}
public TreeRoot(TreeRoot clone) {
super(clone, null);
selectLeafOnly = clone.selectLeafOnly;
}
@Override
public boolean isSelectLeafsOnly() {
return selectLeafOnly;
}
@Override
public ITreeOption findNode(String id) {
if (id == null) {
return null;
}
return find(id, children);
}
private ITreeOption find(String id, List<ITreeOption> children) {
ITreeOption found = null;
if (children != null) {
for (ITreeOption child : children) {
if (id.equals(child.getID())) {
found = child;
break;
}
found = find(id, ((TreeOption) child).children);
if (found != null) {
break;
}
}
}
return found;
}
@Override
public ITreeOption addNode(String id, String name, String category, Integer order) {
ITreeOption parent = this;
if (category != null && category.length() > 0) {
ITreeOption tempParent;
String[] categories = category.split("\\."); //$NON-NLS-1$
for (String cat : categories) {
tempParent = parent.getChild(cat);
if (tempParent == null) {
tempParent = parent.addChild(cat, cat);
if (order != null) {
tempParent.setOrder(order);
}
}
parent = tempParent;
}
}
ITreeOption child = parent.addChild(id, name);
if (order != null) {
child.setOrder(order);
}
return child;
}
}
private static class TreeOption implements ITreeOption {
private String treeNodeId;
private String treeNodeName;
protected String description;
protected String icon;
protected String command;
protected List<ITreeOption> children = null;
private int order = DEFAULT_ORDER;
private ITreeOption parent;
TreeOption(IManagedConfigElement element, ITreeOption parent, boolean readTool) {
treeNodeId = element.getAttribute(ID);
treeNodeName = element.getAttribute(NAME);
description = element.getAttribute(DESCRIPTION);
command = element.getAttribute(COMMAND);
icon = element.getAttribute(ICON);
String orderStr = element.getAttribute(ORDER);
if (orderStr != null && orderStr.trim().length() > 0) {
try {
order = Integer.parseInt(orderStr);
} catch (NumberFormatException e) {
// Do nothing, default value is used.
}
}
this.parent = parent;
IManagedConfigElement[] treeChildren = element.getChildren(TREE_VALUE);
if (treeChildren != null && treeChildren.length > 0) {
children = new ArrayList<>();
for (IManagedConfigElement configElement : treeChildren) {
children.add(new TreeOption(configElement, this, readTool));
}
}
}
TreeOption(TreeOption clone, ITreeOption parent) {
treeNodeId = clone.treeNodeId;
treeNodeName = clone.treeNodeName;
description = clone.description;
command = clone.command;
icon = clone.icon;
order = clone.order;
this.parent = parent;
if (clone.children != null) {
children = new ArrayList<>();
for (ITreeOption cloneChild : clone.children) {
children.add(new TreeOption((TreeOption) cloneChild, this));
}
}
}
private TreeOption(String id, String name, ITreeOption parent) {
this.treeNodeId = id;
this.treeNodeName = name;
this.parent = parent;
}
@Override
public ITreeOption addChild(String id, String name) {
ITreeOption option = new TreeOption(id, name, this);
if (children == null) {
children = new ArrayList<>();
}
children.add(0, option);
return option;
}
@Override
public boolean isContainer() {
return children != null && !children.isEmpty(); // TODO do we need explicit marking as container for empty ones
}
@Override
public String getName() {
return treeNodeName;
}
@Override
public String getID() {
return treeNodeId;
}
@Override
public String getDescription() {
return description;
}
@Override
public String getCommand() {
return command;
}
@Override
public String getIcon() {
return icon;
}
@Override
public ITreeOption[] getChildren() {
if (children == null) {
return null;
}
return children.toArray(new ITreeOption[children.size()]);
}
@Override
public ITreeOption getChild(String name) {
if (children == null || name == null) {
return null;
}
for (ITreeOption child : children) {
if (name.equals(child.getName())) {
return child;
}
}
return null;
}
@Override
public ITreeOption getParent() {
return parent;
}
@Override
public int getOrder() {
return order;
}
@Override
public void setOrder(int order) {
this.order = order;
}
@Override
public void remove() {
((TreeOption) parent).children.remove(this);
}
@Override
public String toString() {
return getName();
}
}
/**
* Calls the iterator (visitor) on the passed parent as well as all nodes in its subtree.
*/
public static void iterateOnTree(ITreeOption parent, ITreeNodeIterator it) {
it.iterateOnNode(parent);
if (!parent.isContainer()) {
it.iterateOnLeaf(parent);
}
ITreeOption[] children = parent.getChildren();
if (children != null) {
for (ITreeOption option : children) {
iterateOnTree(option, it);
}
}
}
public interface ITreeNodeIterator {
void iterateOnNode(ITreeOption node);
void iterateOnLeaf(ITreeOption leafNode);
}
@Override
public ITreeRoot getTreeRoot() throws BuildException {
if (getValueType() != TREE) {
throw new BuildException(ManagedMakeMessages.getResourceString("Option.error.bad_value_type")); //$NON-NLS-1$
}
if (treeRoot == null) {
if (superClass != null) {
return superClass.getTreeRoot();
} else {
return null;
}
}
return treeRoot;
}
}