/*******************************************************************************
* Copyright (c) 2017 itemis AG 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:
* Matthias Wienand (itemis AG) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.gef.dot.internal.ui.language.contentassist;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.dot.internal.language.htmllabel.DotHtmlLabelHelper;
import org.eclipse.gef.dot.internal.language.htmllabel.HtmlTag;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.swt.graphics.Image;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.ui.editor.contentassist.ConfigurableCompletionProposal;
import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext;
import org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor;
/**
* See
* https://www.eclipse.org/Xtext/documentation/304_ide_concepts.html#content-assist
* on how to customize the content assistant.
*/
public class DotHtmlLabelProposalProvider extends
org.eclipse.gef.dot.internal.ui.language.contentassist.AbstractDotHtmlLabelProposalProvider {
@Override
public void complete_HtmlTag(EObject model, RuleCall ruleCall,
ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
String parentName = null;
if (model instanceof HtmlTag) {
parentName = ((HtmlTag) model).getName();
} else {
parentName = DotHtmlLabelHelper.getRootTagKey();
}
for (String tagName : DotHtmlLabelHelper.getValidTags()
.get(parentName)) {
String proposal = calculateProposalString(tagName);
String displayString = proposal;
Image image = null;
ICompletionProposal completionProposal = createCompletionProposal(
proposal, displayString, image, context);
// place the cursor between the opening and the closing html tag
// after the proposal has been applied
if (completionProposal instanceof ConfigurableCompletionProposal) {
ConfigurableCompletionProposal configurableCompletionProposal = (ConfigurableCompletionProposal) completionProposal;
int cursorPosition = calculateCursorPosition(displayString);
configurableCompletionProposal
.setCursorPosition(cursorPosition);
acceptor.accept(configurableCompletionProposal);
}
}
}
@Override
public void completeHtmlAttr_Name(EObject model, Assignment assignment,
ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
super.completeHtmlAttr_Name(model, assignment, context, acceptor);
if (model instanceof HtmlTag) {
HtmlTag htmlTag = (HtmlTag) model;
String htmlTagName = htmlTag.getName();
Map<String, Set<String>> validAttributes = DotHtmlLabelHelper
.getValidAttributes();
if (validAttributes.containsKey(htmlTagName)) {
Set<String> validAttributeNames = validAttributes
.get(htmlTagName);
for (String validAttributeName : validAttributeNames) {
acceptor.accept(createCompletionProposal(validAttributeName,
context));
}
}
}
}
/**
* Calculates the proposal string to a given tag. Proposes self-closing tags
* whenever possible.
*
* @param tagName
* @return
*/
private String calculateProposalString(String tagName) {
StringBuilder sb = new StringBuilder();
if (DotHtmlLabelHelper.getNonSelfClosingTags()
.contains(tagName.toUpperCase())) {
sb.append("<"); //$NON-NLS-1$
sb.append(tagName);
sb.append(">"); //$NON-NLS-1$
sb.append("</"); //$NON-NLS-1$
sb.append(tagName);
sb.append(">"); //$NON-NLS-1$
} else {
sb.append("<"); //$NON-NLS-1$
sb.append(tagName);
sb.append("/>"); //$NON-NLS-1$
}
return sb.toString();
}
/**
* Calculates the cursor position where the cursor has to be placed after
* the given proposal has been applied.
*
* @param htmlTagText
* the htmlTagText representing the proposal
* @return the proper cursor position
*/
private int calculateCursorPosition(String htmlTagText) {
// in case of a self-closing tag, place the cursor immediately before
// the "/>" symbol
if (htmlTagText.contains("/>")) { //$NON-NLS-1$
return htmlTagText.indexOf("/>"); //$NON-NLS-1$
// in case of a non self-closing tag, place the cursor between the
// ">" and "<" symbols
} else {
return htmlTagText.indexOf("><") + 1; //$NON-NLS-1$
}
}
}