/******************************************************************************* * Copyright (c) 2016 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: * Alexander Nyßen (itemis AG) - initial API and implementation *******************************************************************************/ package org.eclipse.gef.dot.internal.language.validation; import java.util.Arrays; import java.util.List; import java.util.TreeSet; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.gef.dot.internal.DotAttributes.Context; import org.eclipse.gef.dot.internal.language.style.EdgeStyle; import org.eclipse.gef.dot.internal.language.style.NodeStyle; import org.eclipse.gef.dot.internal.language.style.StyleItem; import org.eclipse.gef.dot.internal.language.style.StylePackage; import org.eclipse.xtext.nodemodel.INode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.validation.Check; /** * This class contains custom validation rules. * * See * https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation */ public class DotStyleJavaValidator extends org.eclipse.gef.dot.internal.language.validation.AbstractDotStyleJavaValidator { /** * Validates that the used {@link StyleItem}s are applicable in the * respective {@link Context}. * * @param styleItem * The {@link StyleItem} to check. */ @Check public void checkStyleItemConformsToContext(StyleItem styleItem) { // The use of setlinewidth is deprecated, but still valid if (styleItem.getName().equals("setlinewidth")) { return; } Context attributeContext = getAttributeContext(); if (Context.NODE.equals(attributeContext)) { for (Object validValue : NodeStyle.values()) { if (validValue.toString().equals(styleItem.getName())) { return; } } // check each style item with the corresponding parser reportRangeBaseError( "Value should be one of " + getFormattedValues(NodeStyle.values()) + ".", styleItem, StylePackage.Literals.STYLE_ITEM__NAME, attributeContext); } else if (Context.EDGE.equals(attributeContext)) { for (Object validValue : EdgeStyle.values()) { if (validValue.toString().equals(styleItem.getName())) { return; } } // check each style item with the corresponding parser reportRangeBaseError( "Value should be one of " + getFormattedValues(EdgeStyle.values()) + ".", styleItem, StylePackage.Literals.STYLE_ITEM__NAME, attributeContext); } } /** * Validates that the used {@link StyleItem}s are not deprecated. Generates * warnings in case of the usage of deprecated style items. * * @param styleItem * The {@link StyleItem} to check. */ @Check public void checkDeprecatedStyleItem(StyleItem styleItem) { if (styleItem.getName().equals("setlinewidth")) { reportRangeBasedWarning( "The usage of setlinewidth is deprecated, use the penwidth attribute instead.", styleItem, StylePackage.Literals.STYLE_ITEM__NAME); } } private void reportRangeBasedWarning(String message, StyleItem styleItem, EStructuralFeature feature) { List<INode> nodes = NodeModelUtils.findNodesForFeature(styleItem, feature); if (nodes.size() != 1) { throw new IllegalStateException( "Exact 1 node is expected for the feature, but got " + nodes.size() + " node(s)."); } INode node = nodes.get(0); int offset = node.getTotalOffset(); int length = node.getLength(); String code = null; // the issueData will be evaluated by the quickfixes String[] issueData = { styleItem.getName() }; getMessageAcceptor().acceptWarning(message, styleItem, offset, length, code, issueData); } private void reportRangeBaseError(String message, StyleItem styleItem, EStructuralFeature feature, Context attributeContext) { List<INode> nodes = NodeModelUtils.findNodesForFeature(styleItem, feature); if (nodes.size() != 1) { throw new IllegalStateException( "Exact 1 node is expected for the feature, but got " + nodes.size() + " node(s)."); } INode node = nodes.get(0); int offset = node.getTotalOffset(); int length = node.getLength(); String code = null; // the issueData will be evaluated by the quickfixes String[] issueData = { styleItem.getName(), attributeContext.toString() }; getMessageAcceptor().acceptError(message, styleItem, offset, length, code, issueData); } private Context getAttributeContext() { // XXX: This context information is provided by the EObjectValidator Context attributeContext = (Context) getContext() .get(Context.class.getName()); if (attributeContext == null) { throw new IllegalStateException("Attribute context not specified."); } return attributeContext; } private String getFormattedValues(Object[] values) { StringBuilder sb = new StringBuilder(); for (Object value : new TreeSet<>(Arrays.asList(values))) { if (sb.length() > 0) { sb.append(", "); } sb.append("'" + value + "'"); } return sb.toString(); } }