blob: 5dd9fe5c49a4f883a136d79bfee589f760706906 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 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
* Jens Lukowski/Innoopract - initial renaming/restructuring
*
*******************************************************************************/
package org.eclipse.wst.dtd.core.internal;
import java.util.Hashtable;
import org.eclipse.swt.graphics.Image;
import org.eclipse.wst.dtd.core.internal.parser.DTDRegionTypes;
import org.eclipse.wst.dtd.core.internal.text.RegionIterator;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
// base class for an Element's contentmodel
public class Attribute extends DTDNode {
public static final String CDATA = DTDCoreMessages._UI_CHARACTER_DATA_DESC; //$NON-NLS-1$
public static final String ENTITIES = DTDCoreMessages._UI_ENTITY_NAMES_DESC; //$NON-NLS-1$
public static final String ENTITY = DTDCoreMessages._UI_ENTITY_NAME_DESC; //$NON-NLS-1$
public static final String ENUMERATED_NAME = DTDCoreMessages._UI_ENUM_NAME_TOKENS_DESC; //$NON-NLS-1$
public static final String ENUMERATED_NOTATION = DTDCoreMessages._UI_ENUM_NOTATION_DESC; //$NON-NLS-1$
public static final String FIXED = "#FIXED"; //$NON-NLS-1$
public static final String ID = DTDCoreMessages._UI_IDENTIFIER_DESC; //$NON-NLS-1$
public static final String IDREF = DTDCoreMessages._UI_ID_REFERENCE_DESC; //$NON-NLS-1$
public static final String IDREFS = DTDCoreMessages._UI_ID_REFERENCES_DESC; //$NON-NLS-1$
public static final String IMPLIED = "#IMPLIED"; //$NON-NLS-1$
public static final String NMTOKEN = DTDCoreMessages._UI_NAME_TOKEN_DESC; //$NON-NLS-1$
public static final String NMTOKENS = DTDCoreMessages._UI_NAME_TOKENS_DESC; //$NON-NLS-1$
public static final String REQUIRED = "#REQUIRED"; //$NON-NLS-1$
protected static Hashtable typeHash = new Hashtable();
public static final String[] types = {CDATA, ID, IDREF, IDREFS, ENTITY, ENTITIES, NMTOKEN, NMTOKENS, ENUMERATED_NAME, ENUMERATED_NOTATION};
{
typeHash.put(DTDRegionTypes.CDATA_KEYWORD, CDATA);
typeHash.put(DTDRegionTypes.ID_KEYWORD, ID);
typeHash.put(DTDRegionTypes.IDREF_KEYWORD, IDREF);
typeHash.put(DTDRegionTypes.IDREFS_KEYWORD, IDREFS);
typeHash.put(DTDRegionTypes.ENTITY_KEYWORD, ENTITY);
typeHash.put(DTDRegionTypes.ENTITIES_KEYWORD, ENTITIES);
typeHash.put(DTDRegionTypes.NMTOKEN_KEYWORD, NMTOKEN);
typeHash.put(DTDRegionTypes.NMTOKENS_KEYWORD, NMTOKENS);
typeHash.put(DTDRegionTypes.NOTATION_KEYWORD, ENUMERATED_NOTATION);
// this one's a special case since there is no keyword for
// enumerated name tokens
typeHash.put("()", ENUMERATED_NAME); //$NON-NLS-1$
// now put the reverse in place. This gives us a 2 way lookup
// for when we want to retrieve the value and when we want to set it
typeHash.put(CDATA, "CDATA"); //$NON-NLS-1$
typeHash.put(ID, "ID"); //$NON-NLS-1$
typeHash.put(IDREF, "IDREF"); //$NON-NLS-1$
typeHash.put(IDREFS, "IDREFS"); //$NON-NLS-1$
typeHash.put(ENTITY, "ENTITY"); //$NON-NLS-1$
typeHash.put(ENTITIES, "ENTITIES"); //$NON-NLS-1$
typeHash.put(NMTOKEN, "NMTOKEN"); //$NON-NLS-1$
typeHash.put(NMTOKENS, "NMTOKENS"); //$NON-NLS-1$
typeHash.put(ENUMERATED_NAME, ""); //$NON-NLS-1$
typeHash.put(ENUMERATED_NOTATION, "NOTATION"); //$NON-NLS-1$
}
private AttributeEnumList enumList = null;
// public static final String IMPLIED = "IMPLIED";
public Attribute(DTDFile file, IStructuredDocumentRegion flatNode) {
super(file, flatNode);
}
public String getDefaultKind() {
ITextRegion defaultKindRegion = getDefaultKindRegion();
if (defaultKindRegion != null) {
return getStructuredDTDDocumentRegion().getText(defaultKindRegion);
}
return ""; //$NON-NLS-1$
}
public ITextRegion getDefaultKindRegion() {
RegionIterator iter = iterator();
while (iter.hasNext()) {
ITextRegion region = iter.next();
if (region.getType() == DTDRegionTypes.IMPLIED_KEYWORD || region.getType() == DTDRegionTypes.REQUIRED_KEYWORD || region.getType() == DTDRegionTypes.FIXED_KEYWORD) {
return region;
}
}
return null;
}
public String getDefaultValue() {
ITextRegion defaultValue = getNextQuotedLiteral(iterator());
if (defaultValue != null) {
return getValueFromQuotedRegion(defaultValue);
}
return ""; //$NON-NLS-1$
}
public AttributeEnumList getEnumList() {
return enumList;
}
public Image getImage() {
return DTDCorePlugin.getInstance().getImage(DTDResource.ATTRIBUTEICON);
}
public ITextRegion getNameRegion() {
return getNextRegion(iterator(), DTDRegionTypes.ATTRIBUTE_NAME);
}
public ITextRegion getNextQuotedLiteral(RegionIterator iter) {
while (iter.hasNext()) {
ITextRegion region = iter.next();
if (region.getType().equals(DTDRegionTypes.SINGLEQUOTED_LITERAL) || region.getType().equals(DTDRegionTypes.DOUBLEQUOTED_LITERAL)) {
return region;
}
}
return null;
}
protected int getOffsetAfterType() {
ITextRegion typeRegion = getTypeRegion();
String type = getType();
boolean isEnumeration = type.equals(ENUMERATED_NAME) || type.equals(ENUMERATED_NOTATION);
if (isEnumeration) {
// now check if maybe this is an enumeration
if (getEnumList() != null) {
return getEnumList().getEndOffset();
}
}
if (typeRegion != null) {
return getStructuredDTDDocumentRegion().getEndOffset(typeRegion);
}
else {
ITextRegion nameRegion = getNameRegion();
return getStructuredDTDDocumentRegion().getEndOffset(nameRegion);
// // create one
// typeRegion =
// findOrCreateTypeRegion((String)typeHash.get(CDATA));
}
}
public String getType() {
ITextRegion region = getTypeRegion();
if (region != null) {
String type = (String) typeHash.get(region.getType());
if (type == null) {
// just return the text of the type region since this may be
// an entity representing the type;
return getStructuredDTDDocumentRegion().getText(region);
}
return type;
}
else if (getEnumList() != null) {
// enumerated name tokens don't have a type keyword. just
// the existence of the left paren is enough
return (String) typeHash.get("()"); //$NON-NLS-1$
}
return ""; //$NON-NLS-1$
}
public ITextRegion getTypeRegion() {
RegionIterator iter = iterator();
while (iter.hasNext()) {
ITextRegion region = iter.next();
if (region.getType() == DTDRegionTypes.CDATA_KEYWORD || region.getType() == DTDRegionTypes.ID_KEYWORD || region.getType() == DTDRegionTypes.IDREF_KEYWORD || region.getType() == DTDRegionTypes.IDREFS_KEYWORD || region.getType() == DTDRegionTypes.ENTITY_KEYWORD || region.getType() == DTDRegionTypes.ENTITIES_KEYWORD || region.getType() == DTDRegionTypes.NMTOKEN_KEYWORD || region.getType() == DTDRegionTypes.NMTOKENS_KEYWORD || region.getType() == DTDRegionTypes.NOTATION_KEYWORD || region.getType() == DTDRegionTypes.PARM_ENTITY_TYPE) {
return region;
}
}
return null;
}
public String getValueFromQuotedRegion(ITextRegion region) {
String type = region.getType();
if (type.equals(DTDRegionTypes.SINGLEQUOTED_LITERAL) || type.equals(DTDRegionTypes.DOUBLEQUOTED_LITERAL)) {
String text = getStructuredDTDDocumentRegion().getText(region);
return text.substring(1, text.length() - 1);
}
return ""; //$NON-NLS-1$
}
public void resolveRegions() {
removeChildNodes();
RegionIterator iter = iterator();
while (iter.hasNext()) {
ITextRegion currentRegion = iter.next();
if (currentRegion.getType().equals(DTDRegionTypes.LEFT_PAREN)) {
enumList = new AttributeEnumList(getDTDFile(), getStructuredDTDDocumentRegion());
}
if (enumList != null) {
enumList.addRegion(currentRegion);
if (currentRegion.getType() == DTDRegionTypes.RIGHT_PAREN) {
return;
}
}
}
}
public void setDefaultKind(Object requestor, String kind) {
ITextRegion defaultKindRegion = getDefaultKindRegion();
String oldDefaultKind = defaultKindRegion == null ? "" : getStructuredDTDDocumentRegion().getText(defaultKindRegion); //$NON-NLS-1$
if (!kind.equals(oldDefaultKind)) {
String newText = kind;
int startOffset = 0;
int length = 0;
if (defaultKindRegion != null) {
startOffset = getStructuredDTDDocumentRegion().getStartOffset(defaultKindRegion);
length = getStructuredDTDDocumentRegion().getEndOffset(defaultKindRegion) - startOffset;
}
else {
startOffset = getOffsetAfterType();
newText = " " + newText; //$NON-NLS-1$
}
ITextRegion defaultValue = getNextQuotedLiteral(iterator());
if (kind.equals(Attribute.FIXED) || kind.equals("")) { //$NON-NLS-1$
if (defaultValue == null) {
// we are changing to fixed and wehave no quoted region.
// put in an empty value
newText += " \"\""; //$NON-NLS-1$
}
}
else {
if (defaultValue != null) {
length = getStructuredDTDDocumentRegion().getEndOffset(defaultValue) - startOffset;
}
}
replaceText(requestor, startOffset, length, newText);
// do something if there is no "kind" region
}
}
public void setDefaultKind(String kind) {
beginRecording(this, DTDCoreMessages._UI_LABEL_ATTR_DEFAULT_KIND); //$NON-NLS-1$
setDefaultKind(this, kind);
endRecording(this);
}
public void setDefaultValue(Object requestor, String value, boolean fixed) {
ITextRegion defaultValue = getNextQuotedLiteral(iterator());
String quoteChar = value.indexOf("\"") == -1 ? "\"" : "'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
int startOffset = 0;
int endOffset = 0;
String newText = ""; //$NON-NLS-1$
String oldValue = getDefaultValue();
boolean oldKindIsFixed = getDefaultKind().equals(Attribute.FIXED);
if (oldValue.equals(value) && fixed == oldKindIsFixed) {
// nothing to do
return;
}
if (defaultValue != null) {
startOffset = getStructuredDTDDocumentRegion().getStartOffset(defaultValue);
endOffset = getStructuredDTDDocumentRegion().getEndOffset(defaultValue);
}
ITextRegion defaultKindRegion = getDefaultKindRegion();
if (defaultKindRegion != null) {
startOffset = getStructuredDTDDocumentRegion().getStartOffset(defaultKindRegion);
endOffset = endOffset == 0 ? getStructuredDTDDocumentRegion().getEndOffset(defaultKindRegion) : endOffset;
}
else {
if (startOffset == 0) {
endOffset = startOffset = getOffsetAfterType();
newText += " "; //$NON-NLS-1$
}
ITextRegion typeRegion = getTypeRegion();
if (typeRegion == null && getEnumList() == null) {
// tack on a default type
// newText += "CDATA ";
}
}
if (fixed) {
newText += "#FIXED "; //$NON-NLS-1$
}
else {
if (getDefaultKind().equals("") && value.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$
// if not fixed and value is "" then reset the default kind to
// implied
newText += "#IMPLIED"; //$NON-NLS-1$
}
}
if (!getType().equals("") && !value.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$
newText += quoteChar + value + quoteChar;
}
replaceText(requestor, startOffset, endOffset - startOffset, newText);
}
public void setDefaultValue(String value, boolean fixed) {
beginRecording(this, DTDCoreMessages._UI_LABEL_ATTR_DEFAULT_VAL); //$NON-NLS-1$
setDefaultValue(this, value, fixed);
endRecording(this);
}
public void setType(Object requestor, String type) {
String oldType = getType();
if (!type.equals(oldType)) {
boolean wasEnumeration = oldType.equals(ENUMERATED_NAME) || oldType.equals(ENUMERATED_NOTATION);
boolean isEnumeration = type.equals(ENUMERATED_NAME) || type.equals(ENUMERATED_NOTATION);
String newText = ""; //$NON-NLS-1$
int startOffset = 0;
int endOffset = 0;
if (wasEnumeration && !isEnumeration) {
// get rid of the old enumlist
AttributeEnumList enumList = getEnumList();
if (enumList != null) {
startOffset = enumList.getStartOffset();
endOffset = enumList.getEndOffset();
}
}
ITextRegion region = getTypeRegion();
if (region != null) {
startOffset = getStructuredDTDDocumentRegion().getStartOffset(region);
if (endOffset == 0) {
endOffset = getStructuredDTDDocumentRegion().getEndOffset(region);
}
}
else if (startOffset == 0) {
ITextRegion nameRegion = getNameRegion();
newText += " "; //$NON-NLS-1$
endOffset = startOffset = getStructuredDTDDocumentRegion().getEndOffset(nameRegion);
}
String newTypeWord = (String) typeHash.get(type);
if (newTypeWord == null) {
// then this must be a parm entity being used in the type
// use the type text directly
newTypeWord = type;
}
newText += newTypeWord;
if (isEnumeration && !wasEnumeration) {
// put in a new numlist
boolean isSpaceNeeded = !type.equals(ENUMERATED_NAME);
newText += isSpaceNeeded ? " " : ""; //$NON-NLS-1$ //$NON-NLS-2$
newText += "()"; //$NON-NLS-1$
}
replaceText(requestor, startOffset, endOffset - startOffset, newText);
if (newTypeWord.equals("") && !type.equals(ENUMERATED_NAME)) { //$NON-NLS-1$
// the set the defaultkind to ""
// setDefaultKind(requestor, "");
setDefaultValue(requestor, "", false); //$NON-NLS-1$
}
}
}
public void setType(String type) {
beginRecording(this, DTDCoreMessages._UI_LABEL_ATTR_TYPE); //$NON-NLS-1$
setType(this, type);
endRecording(this);
}
}