| /******************************************************************************* |
| * Copyright (c) 2001, 2008 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Jens Lukowski/Innoopract - initial renaming/restructuring |
| * |
| *******************************************************************************/ |
| package org.eclipse.wst.xml.ui.internal.properties; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Stack; |
| |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.views.properties.IPropertyDescriptor; |
| import org.eclipse.ui.views.properties.IPropertySheetEntry; |
| import org.eclipse.ui.views.properties.IPropertySource; |
| import org.eclipse.ui.views.properties.IPropertySource2; |
| import org.eclipse.ui.views.properties.TextPropertyDescriptor; |
| import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier; |
| import org.eclipse.wst.sse.ui.views.properties.IPropertySourceExtension; |
| import org.eclipse.wst.xml.core.internal.contentmodel.CMAttributeDeclaration; |
| import org.eclipse.wst.xml.core.internal.contentmodel.CMDataType; |
| import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration; |
| import org.eclipse.wst.xml.core.internal.contentmodel.CMNamedNodeMap; |
| import org.eclipse.wst.xml.core.internal.contentmodel.CMNode; |
| import org.eclipse.wst.xml.core.internal.contentmodel.basic.CMNamedNodeMapImpl; |
| import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.ModelQuery; |
| import org.eclipse.wst.xml.core.internal.contentmodel.util.DOMNamespaceHelper; |
| import org.eclipse.wst.xml.core.internal.document.DocumentTypeAdapter; |
| import org.eclipse.wst.xml.core.internal.modelquery.ModelQueryUtil; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; |
| import org.eclipse.wst.xml.ui.internal.Logger; |
| import org.eclipse.wst.xml.ui.internal.XMLUIMessages; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.DOMException; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| |
| /** |
| * An IPropertySource implementation for a JFace viewer used to display |
| * properties of DOM nodes. |
| */ |
| public class XMLPropertySource implements IPropertySource, IPropertySourceExtension, IPropertySource2 { |
| protected final static String CATEGORY_ATTRIBUTES = XMLUIMessages.XMLPropertySourceAdapter_0; |
| |
| private static final boolean fSetExpertFilter = false; |
| |
| /** |
| * derive categories from CMDataTypes; disabled until display strings can |
| * be planned |
| */ |
| private final static boolean fShouldDeriveCategories = false; |
| |
| private final static boolean fSortEnumeratedValues = true; |
| |
| /** |
| * Note: we want the default fCaseSensitive to be true, but, to avoid |
| * meaningless double initialization, we leave default here, and set in |
| * constructor only. |
| */ |
| private boolean fCaseSensitive; |
| private IPropertyDescriptor[] fDescriptors = null; |
| private Node fNode = null; |
| |
| private Stack fValuesBeingSet = new Stack(); |
| |
| public XMLPropertySource(INodeNotifier target) { |
| super(); |
| fNode = initNode(target); |
| fCaseSensitive = initCaseSensitive(fNode); |
| |
| } |
| |
| /** seperate method just to isolate error processing */ |
| private Node initNode(INodeNotifier target) { |
| Node node = null; |
| if (target instanceof Node) { |
| node = (Node) target; |
| } |
| else { |
| throw new IllegalArgumentException("XMLPropertySource is only for Nodes"); //$NON-NLS-1$ |
| } |
| return node; |
| } |
| |
| private boolean initCaseSensitive(Node node) { |
| // almost all tags are case senstive, except that old HTML |
| boolean caseSensitive = true; |
| DocumentTypeAdapter adapter = null; |
| if (node instanceof IDOMNode) { |
| adapter = getDocTypeFromDOMNode(node); |
| } |
| if (adapter != null) { |
| caseSensitive = (adapter.getTagNameCase() == DocumentTypeAdapter.STRICT_CASE); |
| } |
| return caseSensitive; |
| } |
| |
| /** |
| * by "internal spec" the DOCTYPE adapter is only available from Document |
| * Node |
| * |
| * @return {@link DocumentTypeAdapter} |
| */ |
| private DocumentTypeAdapter getDocTypeFromDOMNode(Node node) { |
| DocumentTypeAdapter adapter = null; |
| Document ownerDocument = node.getOwnerDocument(); |
| if (ownerDocument == null) { |
| // if ownerDocument is null, then fNode must be the Document Node |
| // [old, old comment] |
| // hmmmm, guess not. See |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=130233 |
| // guess this is used for many INodeNotifiers, not just XML. |
| // (and DTD's use IDOMNode? ... that doesn't sound quite right |
| // ... but, maybe a separate issue). |
| if (node instanceof Document) { |
| ownerDocument = (Document) node; |
| } |
| } |
| if (ownerDocument != null) { |
| adapter = (DocumentTypeAdapter) ((INodeNotifier) ownerDocument).getAdapterFor(DocumentTypeAdapter.class); |
| } |
| |
| return adapter; |
| } |
| |
| private String[] _getValidFixedStrings(CMAttributeDeclaration attrDecl, CMDataType helper) { |
| String attributeName = DOMNamespaceHelper.computeName(attrDecl, fNode, null); |
| List values = new ArrayList(1); |
| String impliedValue = helper.getImpliedValue(); |
| if (impliedValue != null) { |
| values.add(impliedValue); |
| } |
| boolean checkIfCurrentValueIsIncluded = ((fNode.getAttributes() != null) && (fNode.getAttributes().getNamedItem(attributeName) != null) && (fNode.getAttributes().getNamedItem(attributeName).getNodeValue() != null)); |
| if (checkIfCurrentValueIsIncluded) { |
| String currentValue = null; |
| currentValue = fNode.getAttributes().getNamedItem(attributeName).getNodeValue(); |
| if (!currentValue.equals(impliedValue)) { |
| values.add(currentValue); |
| } |
| } |
| String[] validStrings = new String[values.size()]; |
| validStrings = (String[]) values.toArray(validStrings); |
| return validStrings; |
| } |
| |
| private String[] _getValidStrings(CMAttributeDeclaration attrDecl, CMDataType valuesHelper) { |
| String attributeName = DOMNamespaceHelper.computeName(attrDecl, fNode, null); |
| List values = new ArrayList(1); |
| boolean currentValueKnown = false; |
| boolean checkIfCurrentValueIsKnown = ((fNode.getAttributes() != null) && (fNode.getAttributes().getNamedItem(attributeName) != null) && (fNode.getAttributes().getNamedItem(attributeName).getNodeValue() != null)); |
| String currentValue = null; |
| if (checkIfCurrentValueIsKnown) { |
| currentValue = fNode.getAttributes().getNamedItem(attributeName).getNodeValue(); |
| } |
| |
| if ((valuesHelper.getImpliedValueKind() == CMDataType.IMPLIED_VALUE_FIXED) && (valuesHelper.getImpliedValue() != null)) { |
| // FIXED value |
| currentValueKnown = (currentValue != null) && valuesHelper.getImpliedValue().equals(currentValue); |
| values.add(valuesHelper.getImpliedValue()); |
| } |
| else { |
| // ENUMERATED values |
| String[] valueStrings = null; |
| // valueStrings = valuesHelper.getEnumeratedValues(); |
| ModelQuery modelQuery = ModelQueryUtil.getModelQuery(fNode.getOwnerDocument()); |
| if ((modelQuery != null) && (fNode.getNodeType() == Node.ELEMENT_NODE)) { |
| valueStrings = modelQuery.getPossibleDataTypeValues((Element) fNode, attrDecl); |
| } |
| else { |
| valueStrings = attrDecl.getAttrType().getEnumeratedValues(); |
| } |
| if (valueStrings != null) { |
| for (int i = 0; i < valueStrings.length; i++) { |
| if (checkIfCurrentValueIsKnown && valueStrings[i].equals(currentValue)) { |
| currentValueKnown = true; |
| } |
| values.add(valueStrings[i]); |
| } |
| } |
| } |
| if ((valuesHelper.getImpliedValueKind() != CMDataType.IMPLIED_VALUE_NONE) && (valuesHelper.getImpliedValue() != null)) { |
| if (!values.contains(valuesHelper.getImpliedValue())) { |
| values.add(valuesHelper.getImpliedValue()); |
| } |
| } |
| |
| if (checkIfCurrentValueIsKnown && !currentValueKnown && (currentValue != null) && (currentValue.length() > 0)) { |
| values.add(currentValue); |
| } |
| String[] validStrings = new String[values.size()]; |
| validStrings = (String[]) values.toArray(validStrings); |
| return validStrings; |
| } |
| |
| private IPropertyDescriptor createDefaultPropertyDescriptor(String attributeName) { |
| return createDefaultPropertyDescriptor(attributeName, false); |
| } |
| |
| private IPropertyDescriptor createDefaultPropertyDescriptor(String attributeName, boolean hideOnFilter) { |
| // The descriptor class used here is also used in |
| // updatePropertyDescriptors() |
| TextPropertyDescriptor descriptor = new TextPropertyDescriptor(attributeName, attributeName); |
| descriptor.setCategory(getCategory(null)); |
| descriptor.setDescription(attributeName); |
| if (hideOnFilter && fSetExpertFilter) { |
| descriptor.setFilterFlags(new String[]{IPropertySheetEntry.FILTER_ID_EXPERT}); |
| } |
| return descriptor; |
| } |
| |
| /** |
| * Creates a property descriptor for an attribute with ENUMERATED values - |
| * if the value does not exist, an editable combo box is returned - if the |
| * value exists but is not one in the enumerated list of value, a combo |
| * box featuring the current and correct values is returned - if the value |
| * exists and it is a valid value, a combo box featuring the correct |
| * values with the current one visible is returned |
| */ |
| private IPropertyDescriptor createEnumeratedPropertyDescriptor(CMAttributeDeclaration attrDecl, CMDataType valuesHelper) { |
| // the displayName MUST be set |
| String attrName = DOMNamespaceHelper.computeName(attrDecl, fNode, null); |
| EnumeratedStringPropertyDescriptor descriptor = new EnumeratedStringPropertyDescriptor(attrName, attrName, _getValidStrings(attrDecl, valuesHelper)); |
| descriptor.setCategory(getCategory(attrDecl)); |
| descriptor.setDescription(attrName); |
| if ((attrDecl.getUsage() != CMAttributeDeclaration.REQUIRED) && fSetExpertFilter) { |
| descriptor.setFilterFlags(new String[]{IPropertySheetEntry.FILTER_ID_EXPERT}); |
| } |
| return descriptor; |
| } |
| |
| /** |
| * Creates a property descriptor for an attribute with a FIXED value - if |
| * the value does not exist, an editable combo box is returned - if the |
| * value exists but is not the fixed/default value, a combo box featuring |
| * the current and correct value is returned - if the value exists and it |
| * is the fixed/default value, no cell editor is provided "locking" the |
| * value in |
| */ |
| private IPropertyDescriptor createFixedPropertyDescriptor(CMAttributeDeclaration attrDecl, CMDataType helper) { |
| // the displayName MUST be set |
| String attrName = DOMNamespaceHelper.computeName(attrDecl, fNode, null); |
| EnumeratedStringPropertyDescriptor descriptor = new EnumeratedStringPropertyDescriptor(attrName, attrName, _getValidFixedStrings(attrDecl, helper)); |
| descriptor.setCategory(getCategory(attrDecl)); |
| descriptor.setDescription(DOMNamespaceHelper.computeName(attrDecl, fNode, null)); |
| return descriptor; |
| } |
| |
| protected IPropertyDescriptor createPropertyDescriptor(CMAttributeDeclaration attrDecl) { |
| IPropertyDescriptor descriptor = null; |
| CMDataType attrType = attrDecl.getAttrType(); |
| |
| if (attrType != null) { |
| // handle declarations that provide FIXED/ENUMERATED values |
| if ((attrType.getEnumeratedValues() != null) && (attrType.getEnumeratedValues().length > 0)) { |
| descriptor = createEnumeratedPropertyDescriptor(attrDecl, attrType); |
| } |
| else if (((attrDecl.getUsage() == CMAttributeDeclaration.FIXED) || (attrType.getImpliedValueKind() == CMDataType.IMPLIED_VALUE_FIXED)) && (attrType.getImpliedValue() != null)) { |
| descriptor = createFixedPropertyDescriptor(attrDecl, attrType); |
| } |
| else { |
| // plain text |
| descriptor = createTextPropertyDescriptor(attrDecl); |
| } |
| } |
| else { |
| // no extra information given |
| descriptor = createTextPropertyDescriptor(attrDecl); |
| } |
| return descriptor; |
| } |
| |
| /** |
| * Returns the current collection of property descriptors. |
| * |
| * @return all valid descriptors. |
| */ |
| private IPropertyDescriptor[] createPropertyDescriptors() { |
| CMNamedNodeMap attrMap = null; |
| CMElementDeclaration ed = getDeclaration(); |
| if (ed != null) { |
| attrMap = ed.getAttributes(); |
| CMNamedNodeMapImpl allAttributes = new CMNamedNodeMapImpl(attrMap); |
| List nodes = ModelQueryUtil.getModelQuery(fNode.getOwnerDocument()).getAvailableContent((Element) fNode, ed, ModelQuery.INCLUDE_ATTRIBUTES); |
| for (int k = 0; k < nodes.size(); k++) { |
| CMNode cmnode = (CMNode) nodes.get(k); |
| if (cmnode.getNodeType() == CMNode.ATTRIBUTE_DECLARATION) { |
| allAttributes.put(cmnode); |
| } |
| } |
| attrMap = allAttributes; |
| } |
| |
| List descriptorList = new ArrayList(); |
| List names = new ArrayList(); |
| IPropertyDescriptor descriptor; |
| |
| CMAttributeDeclaration attrDecl = null; |
| |
| // add descriptors for existing attributes |
| NamedNodeMap attributes = fNode.getAttributes(); |
| if (attributes != null) { |
| for (int i = 0; i < attributes.getLength(); i++) { |
| Attr attr = (Attr) attributes.item(i); |
| // if metainfo is present for this attribute, use the |
| // CMAttributeDeclaration to derive a descriptor |
| if (attrMap != null) { |
| String attrName = attr.getName(); |
| if (fCaseSensitive) { |
| attrDecl = (CMAttributeDeclaration) attrMap.getNamedItem(attrName); |
| } |
| else { |
| attrDecl = null; |
| for (int j = 0; j < attrMap.getLength(); j++) { |
| if (!fCaseSensitive && attrMap.item(j).getNodeName().equalsIgnoreCase(attrName)) { |
| attrDecl = (CMAttributeDeclaration) attrMap.item(j); |
| break; |
| } |
| } |
| } |
| } |
| // be consistent: if there's metainfo, use *that* as the |
| // descriptor ID |
| descriptor = null; |
| if (attrDecl != null) { |
| String attrName = DOMNamespaceHelper.computeName(attrDecl, fNode, null); |
| if (!names.contains(attrName)) { |
| descriptor = createPropertyDescriptor(attrDecl); |
| if (descriptor != null) |
| names.add(attrName); |
| } |
| } |
| else { |
| if (!names.contains(attr.getName())) { |
| descriptor = createDefaultPropertyDescriptor(attr.getName()); |
| if (descriptor != null) |
| names.add(attr.getName()); |
| } |
| } |
| if (descriptor != null) { |
| descriptorList.add(descriptor); |
| } |
| } |
| } |
| |
| // add descriptors from the metainfo that are not yet listed |
| if (attrMap != null) { |
| for (int i = 0; i < attrMap.getLength(); i++) { |
| attrDecl = (CMAttributeDeclaration) attrMap.item(i); |
| String attrName = DOMNamespaceHelper.computeName(attrDecl, fNode, null); |
| if (!names.contains(attrName)) { |
| IPropertyDescriptor holdDescriptor = createPropertyDescriptor(attrDecl); |
| if (holdDescriptor != null) { |
| names.add(attrName); |
| descriptorList.add(holdDescriptor); |
| } |
| } |
| } |
| } |
| |
| // add MQE-based descriptors |
| if (ed != null && fNode.getNodeType() == Node.ELEMENT_NODE) { |
| List nodes = ModelQueryUtil.getModelQuery(fNode.getOwnerDocument()).getAvailableContent((Element) fNode, ed, ModelQuery.INCLUDE_ATTRIBUTES); |
| for (int i = 0; i < nodes.size(); i++) { |
| CMNode node = (CMNode) nodes.get(i); |
| if (node.getNodeType() == CMNode.ATTRIBUTE_DECLARATION) { |
| attrDecl = (CMAttributeDeclaration) node; |
| String attrName = DOMNamespaceHelper.computeName(attrDecl, fNode, null); |
| if (!names.contains(attrName)) { |
| IPropertyDescriptor holdDescriptor = createPropertyDescriptor(attrDecl); |
| if (holdDescriptor != null) { |
| names.add(attrName); |
| descriptorList.add(holdDescriptor); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| IPropertyDescriptor[] descriptors = new IPropertyDescriptor[descriptorList.size()]; |
| for (int i = 0; i < descriptors.length; i++) { |
| descriptors[i] = (IPropertyDescriptor) descriptorList.get(i); |
| } |
| return descriptors; |
| } |
| |
| private IPropertyDescriptor createTextPropertyDescriptor(CMAttributeDeclaration attrDecl) { |
| String attrName = DOMNamespaceHelper.computeName(attrDecl, fNode, null); |
| TextPropertyDescriptor descriptor = new TextPropertyDescriptor(attrName, attrName); |
| descriptor.setCategory(getCategory(attrDecl)); |
| descriptor.setDescription(attrName); |
| if ((attrDecl.getUsage() != CMAttributeDeclaration.REQUIRED) && fSetExpertFilter) { |
| descriptor.setFilterFlags(new String[]{IPropertySheetEntry.FILTER_ID_EXPERT}); |
| } |
| return descriptor; |
| } |
| |
| private String getCategory(CMAttributeDeclaration attrDecl) { |
| if (attrDecl != null) { |
| if (attrDecl.supports("category")) { //$NON-NLS-1$ |
| return (String) attrDecl.getProperty("category"); //$NON-NLS-1$ |
| } |
| if (fShouldDeriveCategories && (attrDecl.getAttrType() != null) && (attrDecl.getAttrType().getNodeName() != null) && (attrDecl.getAttrType().getNodeName().length() > 0)) { |
| return attrDecl.getAttrType().getDataTypeName(); |
| } |
| } |
| return CATEGORY_ATTRIBUTES; |
| } |
| |
| private CMElementDeclaration getDeclaration() { |
| if ((fNode == null) || (fNode.getNodeType() != Node.ELEMENT_NODE)) { |
| return null; |
| } |
| ModelQuery modelQuery = ModelQueryUtil.getModelQuery(fNode.getOwnerDocument()); |
| if (modelQuery != null) { |
| return modelQuery.getCMElementDeclaration((Element) fNode); |
| } |
| return null; |
| } |
| |
| private Display getDisplay() { |
| |
| return PlatformUI.getWorkbench().getDisplay(); |
| } |
| |
| /** |
| * Returns a value for this Node that can be editted in a property sheet. |
| * |
| * @return a value that can be editted |
| */ |
| public Object getEditableValue() { |
| return null; |
| } |
| |
| /** |
| * Returns the current collection of property descriptors. |
| * |
| * @return all valid descriptors. |
| */ |
| public final IPropertyDescriptor[] getPropertyDescriptors() { |
| if ((fDescriptors == null) || (fDescriptors.length == 0)) { |
| fDescriptors = createPropertyDescriptors(); |
| } |
| else { |
| updatePropertyDescriptors(); |
| } |
| return fDescriptors; |
| } |
| |
| /** |
| * Returns the current value for the named property. |
| * |
| */ |
| public Object getPropertyValue(Object nameObject) { |
| String name = nameObject.toString(); |
| String returnedValue = null; |
| NamedNodeMap attrMap = fNode.getAttributes(); |
| if (attrMap != null) { |
| Node attribute = attrMap.getNamedItem(name); |
| if (attribute != null) { |
| if (attribute instanceof IDOMNode) { |
| returnedValue = ((IDOMNode) attribute).getValueSource(); |
| } |
| else { |
| returnedValue = attribute.getNodeValue(); |
| } |
| } |
| } |
| if (returnedValue == null) { |
| returnedValue = ""; //$NON-NLS-1$ |
| } |
| return returnedValue; |
| } |
| |
| private String[] getValidValues(CMAttributeDeclaration attrDecl) { |
| if (attrDecl == null) { |
| return new String[0]; |
| } |
| |
| String[] validValues = null; |
| CMDataType attrType = attrDecl.getAttrType(); |
| if (attrType != null) { |
| validValues = _getValidStrings(attrDecl, attrType); |
| if (fSortEnumeratedValues) { |
| Arrays.sort(validValues); |
| } |
| } |
| if (validValues == null) { |
| validValues = new String[0]; |
| } |
| return validValues; |
| } |
| |
| public boolean isPropertyRemovable(Object id) { |
| return true; |
| } |
| |
| public boolean isPropertyResettable(Object id) { |
| boolean resettable = false; |
| String property = id.toString(); |
| CMNamedNodeMap attrDecls = null; |
| |
| CMElementDeclaration ed = getDeclaration(); |
| if (ed != null) { |
| attrDecls = ed.getAttributes(); |
| CMNamedNodeMapImpl allAttributes = new CMNamedNodeMapImpl(attrDecls); |
| List nodes = ModelQueryUtil.getModelQuery(fNode.getOwnerDocument()).getAvailableContent((Element) fNode, ed, ModelQuery.INCLUDE_ATTRIBUTES); |
| for (int k = 0; k < nodes.size(); k++) { |
| CMNode cmnode = (CMNode) nodes.get(k); |
| if (cmnode.getNodeType() == CMNode.ATTRIBUTE_DECLARATION) { |
| allAttributes.put(cmnode); |
| } |
| } |
| attrDecls = allAttributes; |
| } |
| |
| if (attrDecls != null) { |
| CMAttributeDeclaration attrDecl = (CMAttributeDeclaration) attrDecls.getNamedItem(property); |
| if (attrDecl != null) { |
| if (attrDecl.getAttrType() != null) { |
| CMDataType helper = attrDecl.getAttrType(); |
| if ((helper.getImpliedValueKind() != CMDataType.IMPLIED_VALUE_NONE) && (helper.getImpliedValue() != null)) { |
| resettable = true; |
| } |
| } |
| } |
| } |
| return resettable; |
| } |
| |
| /** |
| * Returns whether the property value has changed from the default. |
| * |
| * @return <code>true</code> if the value of the specified property has |
| * changed from its original default value; <code>false</code> |
| * otherwise. |
| */ |
| public boolean isPropertySet(Object propertyObject) { |
| String property = propertyObject.toString(); |
| |
| NamedNodeMap attrMap = fNode.getAttributes(); |
| if (attrMap != null) { |
| return attrMap.getNamedItem(property) != null; |
| } |
| return false; |
| } |
| |
| /** |
| * Remove the given attribute from the Node |
| * |
| * @param propertyObject |
| */ |
| public void removeProperty(Object propertyObject) { |
| NamedNodeMap attrMap = fNode.getAttributes(); |
| if (attrMap != null) { |
| Node attribute = attrMap.getNamedItem(propertyObject.toString()); |
| if (attribute != null) { |
| try { |
| attrMap.removeNamedItem(propertyObject.toString()); |
| } |
| catch (DOMException e) { |
| if (e.code != DOMException.INVALID_MODIFICATION_ERR) { |
| Logger.logException(e); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Resets the specified property's value to its default value. |
| * |
| */ |
| public void resetPropertyValue(Object propertyObject) { |
| String property = propertyObject.toString(); |
| CMNamedNodeMap attrDecls = null; |
| |
| CMElementDeclaration ed = getDeclaration(); |
| if (ed != null) { |
| attrDecls = ed.getAttributes(); |
| CMNamedNodeMapImpl allAttributes = new CMNamedNodeMapImpl(attrDecls); |
| List nodes = ModelQueryUtil.getModelQuery(fNode.getOwnerDocument()).getAvailableContent((Element) fNode, ed, ModelQuery.INCLUDE_ATTRIBUTES); |
| for (int k = 0; k < nodes.size(); k++) { |
| CMNode cmnode = (CMNode) nodes.get(k); |
| if (cmnode.getNodeType() == CMNode.ATTRIBUTE_DECLARATION) { |
| allAttributes.put(cmnode); |
| } |
| } |
| attrDecls = allAttributes; |
| } |
| |
| NamedNodeMap attrMap = fNode.getAttributes(); |
| if (attrDecls != null) { |
| CMAttributeDeclaration attrDecl = (CMAttributeDeclaration) attrDecls.getNamedItem(property); |
| String defValue = null; |
| if (attrDecl != null) { |
| if (attrDecl.getAttrType() != null) { |
| CMDataType helper = attrDecl.getAttrType(); |
| if ((helper.getImpliedValueKind() != CMDataType.IMPLIED_VALUE_NONE) && (helper.getImpliedValue() != null)) { |
| defValue = helper.getImpliedValue(); |
| } |
| } |
| } |
| if ((defValue != null) && (defValue.length() > 0)) { |
| ((Attr) attrMap.getNamedItem(property)).setValue(defValue); |
| } |
| else { |
| attrMap.removeNamedItem(property); |
| } |
| } |
| else { |
| attrMap.removeNamedItem(property); |
| } |
| } |
| |
| /** |
| * Sets the named property to the given value. |
| * |
| */ |
| public void setPropertyValue(Object nameObject, Object value) { |
| // Avoid cycling - can happen if a closing cell editor causes a |
| // refresh |
| // on the PropertySheet page and the setInput again asks the editor to |
| // close; besides, why apply the same value twice? |
| if (!fValuesBeingSet.isEmpty() && (fValuesBeingSet.peek() == nameObject)) { |
| return; |
| } |
| fValuesBeingSet.push(nameObject); |
| String name = nameObject.toString(); |
| String valueString = null; |
| if (value != null) { |
| valueString = value.toString(); |
| } |
| NamedNodeMap attrMap = fNode.getAttributes(); |
| try { |
| if (attrMap != null) { |
| Attr attr = (Attr) attrMap.getNamedItem(name); |
| if (attr != null) { |
| // EXISTING VALUE |
| // potential out of control loop if updating the value |
| // triggers a viewer update, forcing the |
| // active cell editor to save its value and causing the |
| // loop to continue |
| if ((attr.getValue() == null) || !attr.getValue().equals(valueString)) { |
| if (attr instanceof IDOMNode) { |
| ((IDOMNode) attr).setValueSource(valueString); |
| } |
| else { |
| attr.setValue(valueString); |
| } |
| } |
| } |
| else { |
| // NEW(?) value |
| if (value != null) { // never create an empty attribute |
| Attr newAttr = fNode.getOwnerDocument().createAttribute(name); |
| if (newAttr instanceof IDOMNode) { |
| ((IDOMNode) newAttr).setValueSource(valueString); |
| } |
| else { |
| newAttr.setValue(valueString); |
| } |
| attrMap.setNamedItem(newAttr); |
| } |
| } |
| } |
| else { |
| if (fNode instanceof Element) { |
| ((Element) fNode).setAttribute(name, valueString); |
| } |
| } |
| } |
| catch (DOMException e) { |
| Display d = getDisplay(); |
| if (d != null) { |
| d.beep(); |
| } |
| } |
| fValuesBeingSet.pop(); |
| } |
| |
| protected void updatePropertyDescriptors() { |
| if ((fDescriptors == null) || (fDescriptors.length == 0)) { |
| // Nothing to update |
| return; |
| } |
| |
| // List of all names encountered in the tag and defined by the element |
| List declaredNames = new ArrayList(); |
| // New descriptor list that will become fDescriptors after all |
| // processing is done |
| List descriptors = new ArrayList(); |
| // Names of the descriptors in the above List |
| List descriptorNames = new ArrayList(); |
| |
| // Update any descriptors derived from the metainfo |
| CMElementDeclaration ed = getDeclaration(); |
| CMNamedNodeMap attrMap = null; |
| if (ed != null) { |
| attrMap = ed.getAttributes(); |
| CMNamedNodeMapImpl allAttributes = new CMNamedNodeMapImpl(attrMap); |
| List nodes = ModelQueryUtil.getModelQuery(fNode.getOwnerDocument()).getAvailableContent((Element) fNode, ed, ModelQuery.INCLUDE_ATTRIBUTES); |
| for (int k = 0; k < nodes.size(); k++) { |
| CMNode cmnode = (CMNode) nodes.get(k); |
| if (cmnode.getNodeType() == CMNode.ATTRIBUTE_DECLARATION) { |
| allAttributes.put(cmnode); |
| } |
| } |
| attrMap = allAttributes; |
| } |
| // Update exiting descriptors; not added to the final list here |
| if (attrMap != null) { |
| // Update existing descriptor types based on metainfo |
| CMAttributeDeclaration attrDecl = null; |
| for (int i = 0; i < attrMap.getLength(); i++) { |
| attrDecl = (CMAttributeDeclaration) attrMap.item(i); |
| String attrName = DOMNamespaceHelper.computeName(attrDecl, fNode, null); |
| if (!declaredNames.contains(attrName)) { |
| declaredNames.add(attrName); |
| } |
| for (int j = 0; j < fDescriptors.length; j++) { |
| boolean sameName = (fCaseSensitive && fDescriptors[j].getId().equals(attrDecl.getNodeName())) || (!fCaseSensitive && attrDecl.getNodeName().equals(fDescriptors[j].getId().toString())); |
| if (sameName) { |
| String[] validValues = getValidValues(attrDecl); |
| // Update the descriptor for this |
| // CMAttributeDeclaration (only enumerated values get |
| // updated for now) |
| if (fDescriptors[j] instanceof EnumeratedStringPropertyDescriptor) { |
| ((EnumeratedStringPropertyDescriptor) fDescriptors[j]).updateValues(validValues); |
| } |
| // Replace with better descriptor |
| else if ((validValues != null) && (validValues.length > 0)) { |
| fDescriptors[j] = createPropertyDescriptor(attrDecl); |
| } |
| } |
| } |
| } |
| } |
| else { |
| // Update existing descriptors based on not having any metainfo |
| for (int j = 0; j < fDescriptors.length; j++) { |
| // Replace with basic descriptor |
| if (!(fDescriptors[j] instanceof TextPropertyDescriptor)) { |
| fDescriptors[j] = createDefaultPropertyDescriptor((String) fDescriptors[j].getId()); |
| } |
| } |
| } |
| |
| NamedNodeMap attributes = fNode.getAttributes(); |
| |
| // Remove descriptors for attributes that aren't present AND aren't |
| // known through metainfo, |
| // do this by only reusing existing descriptors for attributes that |
| // are present or declared |
| for (int i = 0; i < fDescriptors.length; i++) { |
| if (fDescriptors[i] != null) { |
| String descriptorName = fDescriptors[i].getId().toString(); |
| if ((declaredNames.contains(descriptorName) || (attributes.getNamedItem(descriptorName) != null)) && !descriptorNames.contains(descriptorName)) { |
| descriptorNames.add(descriptorName); |
| descriptors.add(fDescriptors[i]); |
| } |
| } |
| } |
| |
| // Add descriptors for declared attributes that don't already have one |
| if (attrMap != null) { |
| // Update existing descriptor types based on metainfo |
| CMAttributeDeclaration attrDecl = null; |
| for (int i = 0; i < attrMap.getLength(); i++) { |
| attrDecl = (CMAttributeDeclaration) attrMap.item(i); |
| String attrName = DOMNamespaceHelper.computeName(attrDecl, fNode, null); |
| if (fCaseSensitive) { |
| if (!descriptorNames.contains(attrName)) { |
| IPropertyDescriptor descriptor = createPropertyDescriptor(attrDecl); |
| if (descriptor != null) { |
| descriptorNames.add(attrName); |
| descriptors.add(descriptor); |
| } |
| } |
| } |
| else { |
| boolean exists = false; |
| for (int j = 0; j < descriptorNames.size(); j++) { |
| exists = (descriptorNames.get(j).toString().equalsIgnoreCase(attrName)) || exists; |
| } |
| if (!exists) { |
| descriptorNames.add(attrName); |
| IPropertyDescriptor descriptor = createPropertyDescriptor(attrDecl); |
| if (descriptor != null) { |
| descriptorNames.add(attrName); |
| descriptors.add(descriptor); |
| } |
| } |
| } |
| } |
| } |
| |
| // Add descriptors for existing attributes that don't already have one |
| if (attributes != null) { |
| for (int i = 0; i < attributes.getLength(); i++) { |
| Attr attr = (Attr) attributes.item(i); |
| String attrName = attr.getName(); |
| if (fCaseSensitive) { |
| if (!descriptorNames.contains(attrName)) { |
| descriptorNames.add(attrName); |
| descriptors.add(createDefaultPropertyDescriptor(attrName)); |
| } |
| } |
| else { |
| boolean exists = false; |
| for (int j = 0; j < descriptorNames.size(); j++) { |
| exists = (descriptorNames.get(j).toString().equalsIgnoreCase(attrName)) || exists; |
| } |
| if (!exists) { |
| descriptorNames.add(attrName); |
| descriptors.add(createDefaultPropertyDescriptor(attrName)); |
| } |
| } |
| } |
| } |
| |
| // Update fDescriptors |
| IPropertyDescriptor[] newDescriptors = new IPropertyDescriptor[descriptors.size()]; |
| for (int i = 0; i < newDescriptors.length; i++) { |
| newDescriptors[i] = (IPropertyDescriptor) descriptors.get(i); |
| } |
| fDescriptors = newDescriptors; |
| } |
| } |