protected void addAttributeNameProposals(
ContentAssistRequest contentAssistRequest,
CompletionProposalInvocationContext context) {
IDOMNode node = (IDOMNode) contentAssistRequest.getNode();
IStructuredDocumentRegion sdRegion = contentAssistRequest.getDocumentRegion();
// retrieve the list of attributes
CMElementDeclaration elementDecl = getCMElementDeclaration(node);
if (elementDecl != null) {
CMNamedNodeMapImpl attributes = new CMNamedNodeMapImpl(elementDecl.getAttributes());
addModelQueryAttributeDeclarations(node, elementDecl,attributes);
String matchString = contentAssistRequest.getMatchString();
int cursorOffset = context.getInvocationOffset();
// check whether an attribute really exists for the replacement
// offsets AND if it possesses a value
boolean attrAtLocationHasValue = false;
boolean proposalNeedsSpace = false;
NamedNodeMap attrs = node.getAttributes();
for (int i = 0; i < attrs.getLength(); i++) {
AttrImpl existingAttr = (AttrImpl) attrs.item(i);
ITextRegion name = existingAttr.getNameRegion();
if (name != null && (sdRegion.getStartOffset(name) <= contentAssistRequest.getReplacementBeginPosition()) &&
(sdRegion.getStartOffset(name) + name.getLength() >= contentAssistRequest.getReplacementBeginPosition() + contentAssistRequest.getReplacementLength()) &&
(existingAttr.getValueRegion() != null)) {
// selected region is attribute name
if (cursorOffset >= sdRegion.getStartOffset(name) && contentAssistRequest.getReplacementLength() != 0)
attrAtLocationHasValue = true;
// propose new attribute, cursor is at the start of another attribute name
else if (cursorOffset == sdRegion.getStartOffset(name))
proposalNeedsSpace = true;
break;
}
}
// only add proposals for the attributes whose names begin with the matchstring
if (attributes != null) {
for (int i = 0; i < attributes.getLength(); i++) {
CMAttributeDeclaration attrDecl = (CMAttributeDeclaration) attributes.item(i);
if(validModelQueryNode(attrDecl)) {
int isRequired = 0;
if (attrDecl.getUsage() == CMAttributeDeclaration.REQUIRED) {
isRequired = XMLRelevanceConstants.R_REQUIRED;
}
boolean showAttribute = true;
showAttribute = showAttribute && beginsWith(getRequiredName(node, attrDecl), matchString.trim());
AttrImpl attr = (AttrImpl) node.getAttributes().getNamedItem(getRequiredName(node, attrDecl));
ITextRegion nameRegion = attr != null ? attr.getNameRegion() : null;
// nameRegion.getEndOffset() + 1 is required to allow for
// matches against the full name of an existing Attr
showAttribute = showAttribute && ((attr == null) || nameRegion == null ||
((nameRegion != null) &&
(sdRegion.getStartOffset(nameRegion) <
contentAssistRequest.getReplacementBeginPosition()) &&
(sdRegion.getStartOffset(nameRegion) + nameRegion.getLength() >=
(contentAssistRequest.getReplacementBeginPosition() +
contentAssistRequest.getReplacementLength()) )));
if (showAttribute) {
//get the proposal image
Image attrImage = CMImageUtil.getImage(attrDecl);
if (attrImage == null) {
if (isRequired > 0) {
attrImage = this.getRequiredAttributeImage();
} else {
attrImage = this.getNotRequiredAttributeImage();
}
}
String proposedText = null;
String proposedInfo = getAdditionalInfo(elementDecl, attrDecl);
CustomCompletionProposal proposal = null;
// attribute is at this location and already exists
if (attrAtLocationHasValue) {
// only propose the name
proposedText = getRequiredName(node, attrDecl);
proposal = new MarkupCompletionProposal(
proposedText, contentAssistRequest.getReplacementBeginPosition(),
contentAssistRequest.getReplacementLength(), proposedText.length(),
attrImage, proposedText, null, proposedInfo,
XMLRelevanceConstants.R_XML_ATTRIBUTE_NAME + isRequired, true);
}
// no attribute exists or is elsewhere, generate
// minimally
else {
Attr existingAttrNode = (Attr) node.getAttributes().getNamedItem(getRequiredName(node, attrDecl));
String value = null;
if (existingAttrNode != null && existingAttrNode.getSpecified()) {
value = existingAttrNode.getNodeValue();
}
int cursorPosition = 0;
if ((value != null) && (value.length() > 0)) {
proposedText = getRequiredName(node, attrDecl);
cursorPosition = proposedText.length() + 2;
}
else {
proposedText = getRequiredText(node, attrDecl);
// skip the cursor past a fixed value
if (attrDecl.getAttrType() != null && attrDecl.getAttrType().getImpliedValueKind() == CMDataType.IMPLIED_VALUE_FIXED)
cursorPosition = proposedText.length();
else
cursorPosition = getRequiredName(node, attrDecl).length() + 2;
}
if (proposalNeedsSpace)
proposedText += " "; //$NON-NLS-1$
proposal = new MarkupCompletionProposal(proposedText,
contentAssistRequest.getReplacementBeginPosition(),
contentAssistRequest.getReplacementLength(),
cursorPosition, attrImage,
// if the value isn't empty (no empty set of quotes), show it
// BUG 203494, content strings may have "", but not be empty
// An empty string is when there's no content between double quotes
// and there is no single quote that may be encasing a double quote
((proposedText.lastIndexOf('\"') - proposedText.indexOf('\"') == 1 &&
proposedText.indexOf('\'') == -1)) ? getRequiredName(node, attrDecl) : proposedText,
null, proposedInfo, XMLRelevanceConstants.R_XML_ATTRIBUTE_NAME + isRequired);
}
contentAssistRequest.addProposal(proposal);
}
}
}
}
}
else {
setErrorMessage(NLS.bind(XMLUIMessages.Element__is_unknown, (new Object[]{node.getNodeName()})));
}
}