| /******************************************************************************* |
| * Copyright (c) 2004 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 |
| *******************************************************************************/ |
| package org.eclipse.wst.html.core.internal.contentmodel; |
| |
| |
| |
| import java.util.Iterator; |
| |
| import org.eclipse.wst.html.core.internal.provisional.HTMLCMProperties; |
| import org.eclipse.wst.xml.core.internal.contentmodel.CMContent; |
| 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; |
| |
| /** |
| * Base class for all Hed???? classes. |
| */ |
| abstract class HTMLElemDeclImpl extends CMContentImpl implements HTMLElementDeclaration, HTMLPropertyDeclaration { |
| |
| // DTD |
| protected CMNamedNodeMapImpl attributes = null; |
| protected String typeDefinitionName = ComplexTypeDefinitionFactory.CTYPE_EMPTY; |
| /** Never access this field directly. Instead, use getComplexTypeDefinition method. */ |
| private ComplexTypeDefinition typeDefinition = null; |
| protected CMGroupImpl inclusion = null; |
| protected CMGroupImpl exclusion = null; |
| // advanced information |
| protected CMNamedNodeMap prohibitedAncestors = null; |
| protected int correctionType = CORRECT_NONE; |
| protected int formatType = FORMAT_HTML; |
| protected int layoutType = LAYOUT_NONE; |
| protected int omitType = OMIT_NONE; |
| protected boolean keepSpaces = false; |
| protected boolean indentChild = false; |
| protected ElementCollection elementCollection = null; |
| protected AttributeCollection attributeCollection = null; |
| protected final static CMNamedNodeMap EMPTY_MAP = new CMNamedNodeMap() { |
| public int getLength() { |
| return 0; |
| } |
| |
| public CMNode getNamedItem(String name) { |
| return null; |
| } |
| |
| public CMNode item(int index) { |
| return null; |
| } |
| |
| public Iterator iterator() { |
| return new Iterator() { |
| public boolean hasNext() { |
| return false; |
| } |
| |
| public Object next() { |
| return null; |
| } |
| |
| public void remove() { |
| } |
| }; |
| } |
| }; |
| |
| /** |
| * HTMLElemDeclImpl constructor. |
| * In the HTML DTD, an element declaration has no specification |
| * for its occurrence. Occurrence is specifed in content model, like |
| * <code>(LI)+</code>. To avoid confusion (and complexity), |
| * occurrence of an element declaration is always 1 (it means, min = 1 and |
| * max = 1). Instead, occurrence of CMGroup represents actual occurrence |
| * of the content. |
| * <br> |
| * @param name java.lang.String |
| */ |
| public HTMLElemDeclImpl(String elementName, ElementCollection collection) { |
| super(elementName, 1, 1); |
| elementCollection = collection; |
| attributeCollection = collection.getAttributeCollection(); |
| } |
| |
| /** |
| */ |
| protected abstract void createAttributeDeclarations(); |
| |
| private ComplexTypeDefinition createComplexTypeDefinition() { |
| if (typeDefinitionName.equals(ComplexTypeDefinitionFactory.CTYPE_CDATA) || typeDefinitionName.equals(ComplexTypeDefinitionFactory.CTYPE_EMPTY) || typeDefinitionName.equals(ComplexTypeDefinitionFactory.CTYPE_PCDATA)) |
| return null; |
| |
| ComplexTypeDefinitionFactory factory = ComplexTypeDefinitionFactory.getInstance(); |
| if (factory == null) |
| return null; // fatal error. |
| |
| ComplexTypeDefinition def = factory.createTypeDefinition(typeDefinitionName, elementCollection); |
| return def; |
| } |
| |
| /** |
| * Get an attribute declaration. |
| */ |
| public HTMLAttributeDeclaration getAttributeDeclaration(String attrName) { |
| if (attributes == null) { |
| createAttributeDeclarations(); |
| if (attributes == null) |
| return null; // fail to create |
| } |
| |
| CMNode cmnode = attributes.getNamedItem(attrName); |
| if (cmnode == null) { |
| return null; |
| } |
| else { |
| return (HTMLAttributeDeclaration) cmnode; // already exists. |
| } |
| } |
| |
| /** |
| * @see org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration |
| */ |
| public CMNamedNodeMap getAttributes() { |
| if (attributes == null) |
| createAttributeDeclarations(); // lazy eval. |
| return attributes; |
| } |
| |
| /** |
| * Get an instance of complex type definition. |
| */ |
| private ComplexTypeDefinition getComplexTypeDefinition() { |
| if (typeDefinition == null) |
| typeDefinition = createComplexTypeDefinition(); |
| return typeDefinition; |
| } |
| |
| /** |
| * Content.<br> |
| * Element declarations which type is EMPTY or CDATA (maybe PCDATA) |
| * <strong>MUST</strong> override this method and always return null. |
| * This default implementation always tries to create a complex type definition |
| * instance and access to it. |
| * <br> |
| * @see org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration |
| */ |
| public CMContent getContent() { |
| ComplexTypeDefinition def = getComplexTypeDefinition(); // lazy eval. |
| return (def != null) ? def.getContent() : null; |
| } |
| |
| /** |
| * Content type.<br> |
| * Element declarations which type is EMPTY or CDATA (maybe PCDATA) |
| * <strong>MUST</strong> override this method and return an appropriate type. |
| * This default implementation always tries to create a complex type definition |
| * instance and access to it. |
| * <br> |
| * @see org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration |
| */ |
| public int getContentType() { |
| ComplexTypeDefinition def = getComplexTypeDefinition(); // lazy eval. |
| return (def != null) ? def.getContentType() : CMElementDeclaration.CDATA; |
| } |
| |
| /** |
| * @see HTMLElementDeclaration#getCorrectionType |
| */ |
| public int getCorrectionType() { |
| return correctionType; |
| } |
| |
| /** |
| * HTML element doesn't have any data type. So, this method always |
| * returns <code>null</code>.<br> |
| * @see org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration |
| */ |
| public CMDataType getDataType() { |
| return null; |
| } |
| |
| /** |
| * @see org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration |
| */ |
| public String getElementName() { |
| return getNodeName(); |
| } |
| |
| /** |
| * Exclusion. |
| * Almost elements don't have a exclusion. |
| * Only classes those have exclusion should override this method. |
| */ |
| public CMContent getExclusion() { |
| return null; |
| } |
| |
| /** |
| * Default format type is <code>FORMAT_HTML</code>.<br> |
| */ |
| public int getFormatType() { |
| return formatType; |
| } |
| |
| /** |
| * Inclusion. |
| * Almost elements don't have a inclusion. |
| * Only classes those have inclusion should override this method. |
| */ |
| public CMContent getInclusion() { |
| return null; |
| } |
| |
| /** |
| */ |
| public int getLayoutType() { |
| return layoutType; |
| } |
| |
| /** |
| * Line break hint is strongly related to layout type. |
| * Indeed, in the C++DOM, it is determined from layout type only. |
| * So, this implementation, as the default implementation for all declarations, |
| * also determines from layout type only.<br> |
| * @return int |
| */ |
| public int getLineBreakHint() { |
| switch (getLayoutType()) { |
| case HTMLElementDeclaration.LAYOUT_BLOCK : |
| return HTMLElementDeclaration.BREAK_BEFORE_START_AND_AFTER_END; |
| case HTMLElementDeclaration.LAYOUT_BREAK : |
| return HTMLElementDeclaration.BREAK_AFTER_START; |
| case HTMLElementDeclaration.LAYOUT_HIDDEN : |
| return HTMLElementDeclaration.BREAK_BEFORE_START_AND_AFTER_END; |
| default : |
| return HTMLElementDeclaration.BREAK_NONE; |
| } |
| } |
| |
| /** |
| * No HTML element has local elements. So, this method always |
| * returns an empty map. |
| * @see org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration |
| */ |
| public CMNamedNodeMap getLocalElements() { |
| return EMPTY_MAP; |
| } |
| |
| /** |
| * @see org.eclipse.wst.xml.core.internal.contentmodel.CMNode |
| */ |
| public int getNodeType() { |
| return CMNode.ELEMENT_DECLARATION; |
| } |
| |
| /** |
| */ |
| public int getOmitType() { |
| return omitType; |
| } |
| |
| /** |
| */ |
| public CMNamedNodeMap getProhibitedAncestors() { |
| return EMPTY_MAP; |
| } |
| |
| /** |
| */ |
| public boolean supports(String propertyName) { |
| if (propertyName.equals(HTMLCMProperties.SHOULD_IGNORE_CASE)) { |
| return true; |
| } |
| else if (propertyName.equals(HTMLCMProperties.CONTENT_HINT)) { |
| ComplexTypeDefinition def = getComplexTypeDefinition(); |
| return (def != null); |
| } |
| else { |
| PropertyProvider pp = PropertyProviderFactory.getProvider(propertyName); |
| if (pp == null) |
| return false; |
| return pp.supports(this); |
| } |
| |
| } |
| |
| /** |
| */ |
| public Object getProperty(String propertyName) { |
| if (propertyName.equals(HTMLCMProperties.SHOULD_IGNORE_CASE)) { |
| return new Boolean(true); |
| } |
| else if (propertyName.equals(HTMLCMProperties.CONTENT_HINT)) { |
| ComplexTypeDefinition def = getComplexTypeDefinition(); |
| return (def != null) ? def.getPrimaryCandidate() : null; |
| } |
| else { |
| PropertyProvider pp = PropertyProviderFactory.getProvider(propertyName); |
| if (pp == null) |
| return null; |
| return pp.get(this); |
| } |
| } |
| |
| /** |
| * Return element names which terminates this element.<br> |
| * @return java.util.Iterator |
| */ |
| protected Iterator getTerminators() { |
| return null; |
| } |
| |
| /** |
| * return true when the element is a JSP element. |
| */ |
| public boolean isJSP() { |
| return false; |
| } |
| |
| /** |
| * In some elements, such as APPLET, a source generator should indent child |
| * elements that their parents. That is, a source generator should generate |
| * source of APPLET and PARAMS like this: |
| * <PRE> |
| * <APPLET ...> |
| * <PARAM ... > |
| * <PARAM ... > |
| * </APPLET> |
| * <PRE> |
| * @return boolean |
| */ |
| public boolean shouldIndentChildSource() { |
| return indentChild; |
| } |
| |
| /** |
| * Most of elements can compact spaces in their child text nodes. |
| * Some special elements should keep them in their source. |
| * @return boolean |
| */ |
| public boolean shouldKeepSpaces() { |
| return keepSpaces; |
| } |
| |
| /** |
| * @return boolean |
| */ |
| public boolean shouldTerminateAt(HTMLElementDeclaration nextElement) { |
| Iterator i = getTerminators(); |
| if (i == null) |
| return false; |
| String nextName = nextElement.getElementName(); |
| while (i.hasNext()) { |
| if (nextName.equals(i.next())) |
| return true; |
| } |
| return false; |
| } |
| } |