/*******************************************************************************
* Copyright (c) 2007, 2008 Edgar Espina.
* 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
*
*******************************************************************************/
package org.deved.antlride.internal.viz;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import org.deved.antlride.common.ui.AntlrImages;
import org.deved.antlride.core.model.IGrammar;
import org.deved.antlride.core.model.IRule;
import org.deved.antlride.ui.AntlrPreferenceConstants;
import org.deved.antlride.viz.AntlrViz;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.SWTGraphics;
import org.eclipse.draw2d.ScalableLayeredPane;
import org.eclipse.draw2d.ScrollPane;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.services.IDisposable;
public abstract class RuleBasedGraphViewer extends Viewer implements
IDisposable {
protected class ExportAsImage extends Action {
private int format;
private String formatName;
public ExportAsImage(String formatName, int format) {
super("Export as " + formatName, IAction.AS_PUSH_BUTTON);
this.formatName = formatName;
this.format = format;
setImageDescriptor(AntlrImages.getDescriptor(AntlrImages.SAVE_AS));
setToolTipText(getText());
}
@Override
public void run() {
FileDialog dialog = new FileDialog(getControl().getShell(),
SWT.SAVE);
dialog.setFileName(getSelectedRuleName() + "." + formatName);
String path = dialog.open();
if (path != null) {
File out = new File(path);
exportAsImage(out, format);
}
}
}
private class RuleLabelProvider extends LabelProvider {
@Override
public String getText(Object element) {
return ((IRule) element).getElementName();
}
@Override
public Image getImage(Object element) {
return AntlrImages.getImage(AntlrImages.RULE);
}
}
private class RuleContentProvider implements ITreeContentProvider {
public Object[] getChildren(Object element) {
return null;
}
public Object getParent(Object element) {
return null;
}
public boolean hasChildren(Object element) {
return false;
}
public Object[] getElements(Object element) {
return (Object[]) element;
}
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
private class GraphSelectionListener implements ISelectionChangedListener {
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
if (selection.isEmpty()) {
clearGraph();
} else {
IStructuredSelection ss = (IStructuredSelection) selection;
IRule element = (IRule) ss.getFirstElement();
draw(element);
}
}
}
private class ZoomInAction extends Action {
public ZoomInAction() {
setText("Zoom In");
setToolTipText("Zoom In");
setImageDescriptor(AntlrImages.getDescriptor(AntlrImages.ZOOM_IN));
}
@Override
public void run() {
zoomIn();
}
}
private class ZoomOutAction extends Action {
public ZoomOutAction() {
setText("Zoom out");
setToolTipText("Zoom out");
setImageDescriptor(AntlrImages.getDescriptor(AntlrImages.ZOOM_OUT));
}
@Override
public void run() {
zoomOut();
}
}
private class ClearAction extends Action {
public ClearAction() {
setText("Clear");
setToolTipText("Clear");
setImageDescriptor(AntlrImages.getDescriptor(AntlrImages.CLEAR));
}
@Override
public void run() {
onClearGraph();
clearGraph();
}
}
private TreeViewer ruleViewer;
protected IGrammar grammar;
private SashForm control;
private Canvas canvas;
private LightweightSystem lightweightSystem;
private ScalableLayeredPane scalableLayeredPane;
private ScrollPane scrollPane;
public RuleBasedGraphViewer(Composite composite) {
createControl(composite);
}
public final String getSelectedRuleName() {
IRule rule = getSelectedRule();
return rule == null ? null : rule.getElementName();
}
public final IRule getSelectedRule() {
IStructuredSelection selection = (IStructuredSelection) ruleViewer
.getSelection();
if (selection.isEmpty())
return null;
return ((IRule) selection.getFirstElement());
}
public final void draw(IRule element) {
clearGraph();
IFigure figure = doDraw(element);
scalableLayeredPane.add(figure);
scrollPane.setContents(scalableLayeredPane);
lightweightSystem.setContents(scrollPane);
}
protected abstract IFigure doDraw(IRule rule);
protected void onClearGraph(){}
private final void clearGraph() {
try {
if (scalableLayeredPane != null) {
@SuppressWarnings("unchecked")
List<IFigure> children = scalableLayeredPane.getChildren();
if (children != null && children.size() > 0) {
IFigure root = children.get(0);
root.erase();
scalableLayeredPane.remove(root);
}
scalableLayeredPane.erase();
}
if (scrollPane != null) {
IFigure contents = scrollPane.getContents();
if (contents != null) {
contents.erase();
}
scrollPane.erase();
}
scrollPane = createScrollPane();
scalableLayeredPane = createScalableLayeredPane();
} catch (Exception ex) {
AntlrViz.error("Couldn't clear graph", ex);
}
}
private void zoomIn() {
if (scalableLayeredPane == null)
return;
double scale = scalableLayeredPane.getScale();
scale += zoomFactor();
scalableLayeredPane.setScale(scale);
}
private void zoomOut() {
if (scalableLayeredPane == null)
return;
double scale = scalableLayeredPane.getScale();
scale -= zoomFactor();
if (scale <= 0) {
return;
}
scalableLayeredPane.setScale(scale);
}
protected double zoomFactor() {
return 0.125;
}
protected ScalableLayeredPane createScalableLayeredPane() {
return new ScalableLayeredPane();
}
protected ScrollPane createScrollPane() {
ScrollPane scrollPane = new ScrollPane();
scrollPane.setViewport(new Viewport(useGraphicsTransalate()));
return scrollPane;
}
protected void createControl(Composite composite) {
GridData gd;
SashForm sashForm = new SashForm(composite, SWT.HORIZONTAL);
Composite leftPane = new Composite(sashForm, SWT.NONE);
leftPane.setLayout(new GridLayout(3, false));
Label label = new Label(leftPane, SWT.NONE);
label.setText("Rule:");
label.setToolTipText("Search Rule");
final Text ruleText = new Text(leftPane, SWT.BORDER);
gd = new GridData(GridData.FILL_HORIZONTAL);
ruleText.setLayoutData(gd);
ruleText.setToolTipText("Search Rule");
ruleText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
ruleViewer.refresh();
}
});
ToolBar bar = new ToolBar(leftPane, SWT.HORIZONTAL);
ToolItem clearFilter = new ToolItem(bar, SWT.PUSH);
clearFilter.setToolTipText("Clear");
clearFilter.setImage(AntlrImages.getImage(AntlrImages.CLEAR));
clearFilter.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
ruleText.setText("");
ruleViewer.refresh();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
ruleViewer = new TreeViewer(leftPane);
gd = new GridData(GridData.FILL_BOTH);
gd.horizontalSpan = 3;
ruleViewer.getTree().setLayoutData(gd);
ruleViewer.addFilter(new ViewerFilter() {
@Override
public boolean select(Viewer viewer, Object parentElement,
Object element) {
String ruleName = ruleText.getText().toLowerCase();
if (ruleName.length() > 0) {
boolean select = false;
if (element instanceof IRule) {
IRule rule = (IRule) element;
select = rule.getElementName().toLowerCase()
.startsWith(ruleName);
}
if (select) {
ruleViewer
.setSelection(new StructuredSelection(element));
}
return select;
}
return true;
}
});
ruleViewer.setLabelProvider(new RuleLabelProvider());
ruleViewer.setContentProvider(new RuleContentProvider());
ruleViewer.addSelectionChangedListener(new GraphSelectionListener());
Composite rightPane = new Composite(sashForm, SWT.NONE);
rightPane.setLayout(new GridLayout(2, false));
bar = new ToolBar(rightPane, SWT.FLAT | SWT.RIGHT
| SWT.HORIZONTAL);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalAlignment = SWT.END;
gd.horizontalSpan = 2;
bar.setLayoutData(gd);
// add actions
IToolBarManager barManager = new ToolBarManager(bar);
barManager.add(new ZoomInAction());
barManager.add(new ZoomOutAction());
barManager.add(new ClearAction());
fillToolBar(barManager);
barManager.update(true);
canvas = new Canvas(rightPane, SWT.BORDER);
gd = new GridData(GridData.FILL_BOTH);
gd.horizontalSpan = 2;
canvas.setLayoutData(gd);
Color color = JFaceResources.getColorRegistry().get(
AntlrPreferenceConstants.EDITOR_BACKGROUND_COLOR);
canvas.setBackground(color == null ? ColorConstants.white : color);
lightweightSystem = new LightweightSystem(canvas);
sashForm.setWeights(new int[] { 30, 70 });
control = sashForm;
}
protected void fillToolBar(IToolBarManager manager) {
}
/**
* Returns <code>true</code> if this viewport uses graphics translation.
*
* @return whether this viewport uses graphics translation
*/
protected boolean useGraphicsTransalate() {
return false;
}
@Override
public Control getControl() {
return control;
}
@Override
public Object getInput() {
return grammar;
}
@Override
public ISelection getSelection() {
return ruleViewer.getSelection();
}
@Override
public void refresh() {
}
@Override
public void setInput(Object input) {
if (grammar != input) {
grammar = (IGrammar) input;
ruleViewer.setInput(grammar.getRules());
}
}
@Override
public void setSelection(ISelection selection, boolean reveal) {
}
public void dispose() {
clearGraph();
}
private void exportAsImage(File file, int format) {
IFigure figure = (IFigure) scalableLayeredPane.getChildren().get(0);
Rectangle r = figure.getBounds();
OutputStream out = null;
Image image = null;
GC gc = null;
Graphics g = null;
try {
out = new BufferedOutputStream(new FileOutputStream(file));
image = new Image(getControl().getDisplay(), r.width, r.height);
gc = new GC(image);
g = new SWTGraphics(gc);
g.translate(r.x * -1, r.y * -1);
figure.paint(g);
ImageLoader imageLoader = new ImageLoader();
imageLoader.data = new ImageData[] { image.getImageData() };
imageLoader.save(out, format);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (g != null) {
g.dispose();
}
if (gc != null) {
gc.dispose();
}
if (image != null) {
image.dispose();
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}