/*******************************************************************************
* Copyright (c) 2010, 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:
* Fabian Steeg - intial Xtext generation (see bug #277380)
* Alexander Nyßen - initial implementation
* Tamas Miklossy (itemis AG) - Add quickfix support for all dot attributes (bug #513196)
*
*******************************************************************************/
package org.eclipse.gef.dot.internal.ui.language.quickfix;
import java.util.Arrays;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.dot.internal.DotAttributes;
import org.eclipse.gef.dot.internal.language.arrowtype.DeprecatedShape;
import org.eclipse.gef.dot.internal.language.clustermode.ClusterMode;
import org.eclipse.gef.dot.internal.language.color.DotColors;
import org.eclipse.gef.dot.internal.language.dir.DirType;
import org.eclipse.gef.dot.internal.language.dot.Attribute;
import org.eclipse.gef.dot.internal.language.layout.Layout;
import org.eclipse.gef.dot.internal.language.outputmode.OutputMode;
import org.eclipse.gef.dot.internal.language.pagedir.Pagedir;
import org.eclipse.gef.dot.internal.language.rankdir.Rankdir;
import org.eclipse.gef.dot.internal.language.ranktype.RankType;
import org.eclipse.gef.dot.internal.language.shape.PolygonBasedNodeShape;
import org.eclipse.gef.dot.internal.language.shape.RecordBasedNodeShape;
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.terminals.ID;
import org.eclipse.gef.dot.internal.language.terminals.ID.Type;
import org.eclipse.xtext.diagnostics.Severity;
import org.eclipse.xtext.ui.editor.model.edit.IModificationContext;
import org.eclipse.xtext.ui.editor.model.edit.ISemanticModification;
import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider;
import org.eclipse.xtext.ui.editor.quickfix.Fix;
import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionAcceptor;
import org.eclipse.xtext.validation.Issue;
/**
* A quick-fix provider for Dot.
*
* @author anyssen
*/
public class DotQuickfixProvider extends DefaultQuickfixProvider {
@Fix(DotAttributes.ARROWHEAD__E)
public void fixArrowheadAttributeValue(final Issue issue,
IssueResolutionAcceptor acceptor) {
String[] issueData = issue.getData();
if (issueData != null && issueData.length > 0) {
String deprecatedShapeString = issueData[0];
String validArrowShape = getValidArrowShape(deprecatedShapeString);
if (validArrowShape != null) {
provideQuickfix(validArrowShape, "edge arrowhead", issue, //$NON-NLS-1$
acceptor);
}
}
}
@Fix(DotAttributes.ARROWTAIL__E)
public void fixArrowtailAttributeValue(final Issue issue,
IssueResolutionAcceptor acceptor) {
String[] issueData = issue.getData();
if (issueData != null && issueData.length > 0) {
String deprecatedShapeString = issueData[0];
String validArrowShape = getValidArrowShape(deprecatedShapeString);
if (validArrowShape != null) {
provideQuickfix(validArrowShape, "edge arrowtail", issue, //$NON-NLS-1$
acceptor);
}
}
}
@Fix(DotAttributes.CLUSTERRANK__G)
public void fixClusterRankAttributeValue(final Issue issue,
IssueResolutionAcceptor acceptor) {
provideQuickfixes(ClusterMode.values(), "graph clusterMode", issue, //$NON-NLS-1$
acceptor);
}
@Fix(DotAttributes.COLORSCHEME__GCNE)
public void fixColorschemeAttributeValue(final Issue issue,
IssueResolutionAcceptor acceptor) {
// TODO: use "graph colorscheme", "node colorscheme", "edge colorscheme"
// as suffix.
provideQuickfixes(DotColors.getColorSchemes(), "colorscheme", //$NON-NLS-1$
issue, acceptor);
}
@Fix(DotAttributes.DIR__E)
public void fixDirAttributeValue(final Issue issue,
IssueResolutionAcceptor acceptor) {
provideQuickfixes(DirType.values(), "edge dir", issue, acceptor); //$NON-NLS-1$
}
@Fix(DotAttributes.LAYOUT__G)
public void fixLayoutAttributeValue(final Issue issue,
IssueResolutionAcceptor acceptor) {
provideQuickfixes(Layout.values(), "graph layout", issue, acceptor); //$NON-NLS-1$
}
@Fix(DotAttributes.OUTPUTORDER__G)
public void fixOutputOrderAttributeValue(final Issue issue,
IssueResolutionAcceptor acceptor) {
provideQuickfixes(OutputMode.values(), "graph outputMode", issue, //$NON-NLS-1$
acceptor);
}
@Fix(DotAttributes.PAGEDIR__G)
public void fixPagedirAttributeValue(final Issue issue,
IssueResolutionAcceptor acceptor) {
provideQuickfixes(Pagedir.values(), "graph pagedir", issue, //$NON-NLS-1$
acceptor);
}
@Fix(DotAttributes.RANK__S)
public void fixRankAttributeValue(final Issue issue,
IssueResolutionAcceptor acceptor) {
provideQuickfixes(RankType.values(), "subgraph rankType", issue, //$NON-NLS-1$
acceptor);
}
@Fix(DotAttributes.RANKDIR__G)
public void fixRankdirAttributeValue(final Issue issue,
IssueResolutionAcceptor acceptor) {
provideQuickfixes(Rankdir.values(), "graph rankdir", issue, //$NON-NLS-1$
acceptor);
}
@Fix(DotAttributes.SHAPE__N)
public void fixShapeAttributeValue(final Issue issue,
IssueResolutionAcceptor acceptor) {
provideQuickfixes(PolygonBasedNodeShape.VALUES, "node shape", issue, //$NON-NLS-1$
acceptor);
provideQuickfixes(RecordBasedNodeShape.VALUES, "node shape", issue, //$NON-NLS-1$
acceptor);
}
@Fix(DotAttributes.STYLE__GCNE)
public void fixStyleAttributeValue(final Issue issue,
IssueResolutionAcceptor acceptor) {
// currently there is no support for quick fixing a style warning
if (issue.getSeverity() == Severity.WARNING) {
return;
}
DotAttributes.Context attributeContext = DotAttributes.Context
.valueOf(issue.getData()[1]);
switch (attributeContext) {
case GRAPH:
case SUBGRAPH:
case CLUSTER:
// TODO: implement
break;
case NODE:
provideQuickfixes(NodeStyle.VALUES, "node style", issue, acceptor); //$NON-NLS-1$
break;
case EDGE:
provideQuickfixes(EdgeStyle.VALUES, "edge style", issue, acceptor); //$NON-NLS-1$
break;
default:
break;
}
}
private String getValidArrowShape(String deprecatedShapeString) {
DeprecatedShape deprecatedShape = DeprecatedShape
.get(deprecatedShapeString);
if (deprecatedShape == null) {
return null;
}
switch (deprecatedShape) {
case EDIAMOND:
return "odiamond"; //$NON-NLS-1$
case OPEN:
return "vee"; //$NON-NLS-1$
case HALFOPEN:
return "lvee"; //$NON-NLS-1$
case EMPTY:
return "onormal"; //$NON-NLS-1$
case INVEMPTY:
return "oinv"; //$NON-NLS-1$
default:
return null;
}
}
private void provideQuickfixes(Object[] validValues, String suffix,
Issue issue, IssueResolutionAcceptor acceptor) {
provideQuickfixes(Arrays.asList(validValues), suffix, issue, acceptor);
}
private void provideQuickfixes(List<?> validValues, String suffix,
Issue issue, IssueResolutionAcceptor acceptor) {
for (Object validValue : validValues) {
provideQuickfix(validValue.toString(), suffix, issue, acceptor);
}
}
private void provideQuickfix(String validValue, String suffix, Issue issue,
IssueResolutionAcceptor acceptor) {
acceptor.accept(issue,
"Replace '" + issue.getData()[0] + "' with '" + validValue //$NON-NLS-1$ //$NON-NLS-2$
+ "'.", //$NON-NLS-1$
"Use valid '" + validValue + "' instead of invalid '" //$NON-NLS-1$ //$NON-NLS-2$
+ issue.getData()[0] + "' " + suffix + ".", //$NON-NLS-1$ //$NON-NLS-2$
null, new ISemanticModification() {
@Override
public void apply(EObject element,
IModificationContext context) {
Attribute attribute = (Attribute) element;
Type type = attribute.getValue().getType();
ID validValueAsID = ID.fromValue(validValue, type);
attribute.setValue(validValueAsID);
}
});
}
}