package org.jactr.eclipse.production.view;
/*
* default logging
*/
import java.util.Map;
import org.antlr.runtime.tree.CommonTree;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.zest.core.viewers.AbstractZoomableViewer;
import org.eclipse.zest.core.viewers.GraphViewer;
import org.eclipse.zest.core.viewers.IZoomableWorkbenchPart;
import org.eclipse.zest.core.viewers.ZoomContributionViewItem;
import org.eclipse.zest.core.widgets.ZestStyles;
import org.eclipse.zest.layouts.LayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
import org.jactr.eclipse.core.comp.ICompilationUnit;
import org.jactr.eclipse.production.ProductionViewActivator;
import org.jactr.eclipse.production.content.AllContentProvider;
import org.jactr.eclipse.production.content.SequenceContentProvider;
import org.jactr.eclipse.production.content.TreeContentProvider;
import org.jactr.eclipse.production.filters.AmbiguousFilter;
import org.jactr.eclipse.production.filters.FilterAction;
import org.jactr.eclipse.production.filters.LayoutFilter;
import org.jactr.eclipse.production.filters.NegativeFilter;
import org.jactr.eclipse.production.filters.PositiveFilter;
import org.jactr.eclipse.production.render.ProductionSequenceViewLabelProvider;
import org.jactr.eclipse.ui.editor.ACTRModelEditor;
import org.jactr.eclipse.ui.editor.command.GoTo;
import org.jactr.io.antlr3.misc.DetailedCommonTree;
import org.jactr.tools.analysis.production.relationships.ProductionRelationships;
public class ProductionSequenceView extends ViewPart implements
IZoomableWorkbenchPart
{
/**
* Logger definition
*/
static private final transient Log LOGGER = LogFactory
.getLog(ProductionSequenceView.class);
static public final String VIEW_ID = ProductionSequenceView.class
.getName();
private GraphViewer _viewer;
private CommonTree _modelDescriptor;
private Map<CommonTree, ProductionRelationships> _relationships;
private int _depth = 2;
private int _nodeStyle = ZestStyles.NODES_FISHEYE
| ZestStyles.NODES_NO_LAYOUT_RESIZE;
private FilterAction _ambiguousFilter;
private FilterAction _negativeFilter;
private FilterAction _positiveFilter;
private ZoomContributionViewItem _zoomAction;
private Action _viewAll;
private Action _viewNext;
private Action _viewPrevious;
private Action _viewSequence;
private CommonTree _selectedProduction;
private LayoutFilter _layoutFilter;
static private final String AMBIGUOUS = "ambiguous";
static private final String POSITIVE = "positive";
static private final String NEGATIVE = "negative";
static private final String REFRESH = "refresh";
static private final String LAYOUT = "layout";
static private final String ALL = "all";
static private final String PREVIOUS = "previous";
static private final String NEXT = "next";
static private final String SEQUENCE = "sequence";
static
{
/*
* prepopulate the image registry
*/
ImageRegistry registry = ProductionViewActivator.getDefault()
.getImageRegistry();
registry.put(AMBIGUOUS, ImageDescriptor
.createFromURL(ProductionSequenceView.class.getClassLoader()
.getResource("icons/ambiguous.gif")));
registry.put(POSITIVE, ImageDescriptor
.createFromURL(ProductionSequenceView.class.getClassLoader()
.getResource("icons/positive.gif")));
registry.put(NEGATIVE, ImageDescriptor
.createFromURL(ProductionSequenceView.class.getClassLoader()
.getResource("icons/negative.gif")));
registry.put(REFRESH, ImageDescriptor
.createFromURL(ProductionSequenceView.class.getClassLoader()
.getResource("icons/refresh.gif")));
registry.put(LAYOUT, ImageDescriptor
.createFromURL(ProductionSequenceView.class.getClassLoader()
.getResource("icons/layout.gif")));
registry.put(ALL, ImageDescriptor
.createFromURL(ProductionSequenceView.class.getClassLoader()
.getResource("icons/all.gif")));
registry.put(PREVIOUS, ImageDescriptor
.createFromURL(ProductionSequenceView.class.getClassLoader()
.getResource("icons/previous.gif")));
registry.put(NEXT, ImageDescriptor
.createFromURL(ProductionSequenceView.class.getClassLoader()
.getResource("icons/follow.gif")));
registry.put(SEQUENCE, ImageDescriptor
.createFromURL(ProductionSequenceView.class.getClassLoader()
.getResource("icons/sequence.gif")));
}
@Override
public void createPartControl(Composite parent)
{
// Group group = new Group(parent, SWT.SHADOW_IN);
// _viewer = new GraphViewer(group, SWT.NONE);
_viewer = new GraphViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL);
// _viewer.addConstraintAdapter(new RelationshipConstraintAdapter());
_viewer.setNodeStyle(_nodeStyle);
// _viewer.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED);
_viewer.setLabelProvider(new ProductionSequenceViewLabelProvider(this));
parent.addControlListener(new ControlListener() {
private boolean _resizeQueued = false;
public void controlMoved(ControlEvent e)
{
}
public void controlResized(final ControlEvent e)
{
if (!_viewer.getGraphControl().isDisposed() && !_resizeQueued)
{
_resizeQueued = true;
Runnable apply = new Runnable() {
public void run()
{
if (!_viewer.getGraphControl().isDisposed())
_viewer.applyLayout();
_resizeQueued = false;
}
};
_viewer.getGraphControl().getDisplay().asyncExec(apply);
}
}
});
_viewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event)
{
Object selection = ((StructuredSelection) event.getSelection())
.getFirstElement();
if (LOGGER.isDebugEnabled()) LOGGER.debug("Selected " + selection);
if (selection instanceof CommonTree)
_selectedProduction = (CommonTree) selection;
else
_selectedProduction = null;
_viewer.refresh();
}
});
_viewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event)
{
if (LOGGER.isDebugEnabled()) LOGGER.debug("double click");
/*
* automatically do sequence view
*/
_viewSequence.run();
}
});
_viewer.getGraphControl().addMouseListener(new MouseListener() {
public void mouseDoubleClick(MouseEvent e)
{
if (LOGGER.isDebugEnabled()) LOGGER.debug("double click");
}
public void mouseDown(MouseEvent e)
{
// TODO Auto-generated method stub
}
public void mouseUp(MouseEvent e)
{
// TODO Auto-generated method stub
}
});
createActions();
}
public CommonTree getSelectedProduction()
{
return _selectedProduction;
}
public Map<CommonTree, ProductionRelationships> getInput()
{
return _relationships;
}
protected void createActions()
{
IToolBarManager toolBar = getViewSite().getActionBars().getToolBarManager();
_viewAll = new Action("View All", IAction.AS_CHECK_BOX) {
@Override
public void run()
{
ACTRModelEditor editor = ACTRModelEditor.getActiveEditor();
if (editor != null) viewAll(editor);
}
};
_viewAll.setImageDescriptor(ProductionViewActivator.getDefault()
.getImageRegistry().getDescriptor(ALL));
toolBar.add(_viewAll);
toolBar.add(new Separator());
_viewSequence = new Action("View Sequence", IAction.AS_CHECK_BOX) {
@Override
public void run()
{
ACTRModelEditor editor = ACTRModelEditor.getActiveEditor();
if (editor != null) viewSequence(editor, _selectedProduction);
}
};
_viewSequence.setImageDescriptor(ProductionViewActivator.getDefault()
.getImageRegistry().getDescriptor(SEQUENCE));
toolBar.add(_viewSequence);
_viewPrevious = new Action("View Previous", IAction.AS_CHECK_BOX) {
@Override
public void run()
{
ACTRModelEditor editor = ACTRModelEditor.getActiveEditor();
if (editor != null) viewPrevious(editor, _selectedProduction);
}
};
_viewPrevious.setImageDescriptor(ProductionViewActivator.getDefault()
.getImageRegistry().getDescriptor(PREVIOUS));
toolBar.add(_viewPrevious);
_viewNext = new Action("View Next", IAction.AS_CHECK_BOX) {
@Override
public void run()
{
ACTRModelEditor editor = ACTRModelEditor.getActiveEditor();
if (editor != null) viewNext(editor, _selectedProduction);
}
};
_viewNext.setImageDescriptor(ProductionViewActivator.getDefault()
.getImageRegistry().getDescriptor(NEXT));
toolBar.add(_viewNext);
toolBar.add(new Separator());
_positiveFilter = new FilterAction("Show Positive", new PositiveFilter(),
_viewer);
_positiveFilter.setChecked(true);
_positiveFilter.setImageDescriptor(ProductionViewActivator.getDefault()
.getImageRegistry().getDescriptor(POSITIVE));
_viewer.addFilter(_positiveFilter.getFilter());
toolBar.add(_positiveFilter);
_negativeFilter = new FilterAction("Show Negative", new NegativeFilter(),
_viewer);
_negativeFilter.setImageDescriptor(ProductionViewActivator.getDefault()
.getImageRegistry().getDescriptor(NEGATIVE));
_viewer.addFilter(_negativeFilter.getFilter());
_negativeFilter.setChecked(false);
toolBar.add(_negativeFilter);
_ambiguousFilter = new FilterAction("Show Ambiguous",
new AmbiguousFilter(), _viewer);
_ambiguousFilter.setImageDescriptor(ProductionViewActivator.getDefault()
.getImageRegistry().getDescriptor(AMBIGUOUS));
_viewer.addFilter(_ambiguousFilter.getFilter());
toolBar.add(_ambiguousFilter);
_ambiguousFilter.setChecked(false);
_layoutFilter = new LayoutFilter(_viewer, _ambiguousFilter.getFilter(),
_negativeFilter.getFilter(), _positiveFilter.getFilter());
toolBar.add(new Separator());
toolBar.add(new Action("Refresh Layout", ProductionViewActivator
.getDefault().getImageRegistry().getDescriptor(REFRESH)) {
@Override
public void run()
{
_viewer.applyLayout();
}
});
IMenuCreator menuCreator = new IMenuCreator() {
private Menu _menu;
private String[] _names = new String[] { "Spring", "Radial", "Grid",
"Tree", "Horizontal", "Horizontal Tree",
"Vertical" };
private Class[] _algorithms = new Class[] { SpringLayoutAlgorithm.class,
RadialLayoutAlgorithm.class,
GridLayoutAlgorithm.class,
TreeLayoutAlgorithm.class };
public void dispose()
{
if (_menu != null && !_menu.isDisposed()) _menu.dispose();
_menu = null;
}
public Menu getMenu(Control parent)
{
if (_menu == null || _menu.getParent() != parent)
{
if (_menu != null) dispose();
_menu = new Menu(parent);
buildMenu(_menu);
}
return _menu;
}
public Menu getMenu(Menu parent)
{
if (_menu == null || _menu.getParentMenu() != parent)
{
if (_menu != null) dispose();
_menu = new Menu(parent);
buildMenu(_menu);
}
return _menu;
}
protected void buildMenu(Menu menu)
{
for (int i = 0; i < _names.length; i++)
{
MenuItem item = new MenuItem(menu, SWT.PUSH);
item.setText(_names[i]);
item.setData(_algorithms[i]);
item.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e)
{
}
public void widgetSelected(SelectionEvent e)
{
setLayoutAlgorithm((Class) ((MenuItem) e.widget).getData());
}
});
}
}
};
Action layoutAction = new Action("Set Layout Algorithm",
IAction.AS_DROP_DOWN_MENU) {
};
layoutAction.setImageDescriptor(ProductionViewActivator.getDefault()
.getImageRegistry().getDescriptor(LAYOUT));
layoutAction.setMenuCreator(menuCreator);
toolBar.add(layoutAction);
IMenuManager root = getViewSite().getActionBars().getMenuManager();
_zoomAction = new ZoomContributionViewItem(this);
// toolBar.add(_zoomAction);
// MenuManager zoom = new MenuManager("Zoom");
// zoom.setRemoveAllWhenShown(true);
// zoom.addMenuListener(new IMenuListener(){
//
// public void menuAboutToShow(IMenuManager manager)
// {
// manager.add(_zoomAction);
// }
// });
// zoom.add(new ZoomContributionViewItem(this));
// zoom.setRemoveAllWhenShown(true);
// zoom.add(_zoomAction);
// root.add(new Separator());
// root.add(new Separator());
root.add(_zoomAction);
MenuManager menuMgr = new MenuManager();
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager mgr)
{
fillContextMenu(mgr);
}
});
// Create menu.
Menu menu = menuMgr.createContextMenu(_viewer.getControl());
_viewer.getControl().setMenu(menu);
// Register menu for extension.
getSite().registerContextMenu(menuMgr, _viewer);
}
private void fillContextMenu(IMenuManager manager)
{
manager.add(_viewAll);
if (_selectedProduction != null)
{
manager.add(new Separator());
manager.add(_viewSequence);
manager.add(new Separator());
manager.add(_viewPrevious);
manager.add(_viewNext);
manager.add(new Separator());
manager.add(new Action("Go to") {
@Override
public void run()
{
GoTo.goTo((DetailedCommonTree) getSelectedProduction());
}
});
}
}
public boolean isShowingAmbiguous()
{
return _ambiguousFilter.isChecked();
}
public boolean isShowingNegative()
{
return _negativeFilter.isChecked();
}
public boolean isShowingPositive()
{
return _positiveFilter.isChecked();
}
@Override
public void setFocus()
{
}
protected void setLayoutAlgorithm(Class clazz)
{
/*
* do we need to actually change the layout?
*/
// if (_viewer.getGraphControl().getLayoutAlgorithm() != null
// && _viewer.getGraphControl().getLayoutAlgorithm().getClass() == clazz)
// return;
try
{
final LayoutAlgorithm alg = (LayoutAlgorithm) clazz.newInstance();
// alg.setFilter(_layoutFilter);
Display.getCurrent().asyncExec(new Runnable() {
public void run()
{
_viewer.setLayoutAlgorithm(alg, true);
// _viewer.refresh();
}
});
}
catch (Exception e)
{
LOGGER.error(
"ProductionSequenceView.setLayoutAlgorithm threw Exception : ", e);
}
}
public AbstractZoomableViewer getZoomableViewer()
{
return _viewer;
}
public void viewAll(final ACTRModelEditor editor)
{
if (LOGGER.isDebugEnabled()) LOGGER.debug("Attempting to visualize all");
setLayoutAlgorithm(RadialLayoutAlgorithm.class);
Runnable runner = new Runnable() {
public void run()
{
showBusy(true);
_viewAll.setChecked(true);
_viewPrevious.setChecked(false);
_viewNext.setChecked(false);
_viewSequence.setChecked(false);
_viewer.setSelection(StructuredSelection.EMPTY);
setACTRCompilationUnit(editor.getCompilationUnit());
_viewer.setContentProvider(new AllContentProvider(
ProductionSequenceView.this));
// _viewer.refresh();
showBusy(false);
}
};
_viewer.getControl().getDisplay().asyncExec(runner);
}
public void viewPrevious(final ACTRModelEditor editor,
final CommonTree current)
{
if (current != null)
{
Runnable runner = new Runnable() {
public void run()
{
showBusy(true);
_viewAll.setChecked(false);
_viewPrevious.setChecked(true);
_viewNext.setChecked(false);
_viewSequence.setChecked(false);
_selectedProduction = current;
setLayoutAlgorithm(SpringLayoutAlgorithm.class);
_viewer.setSelection(new StructuredSelection(current));
setACTRCompilationUnit(editor.getCompilationUnit());
_viewer.setContentProvider(new TreeContentProvider(
ProductionSequenceView.this, current, false));
// _viewer.refresh();
showBusy(false);
}
};
_viewer.getControl().getDisplay().asyncExec(runner);
}
else
clear();
}
public void viewNext(final ACTRModelEditor editor,
final CommonTree nearestProduction)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("Attempting to visualize follosing");
if (nearestProduction != null)
{
Runnable runner = new Runnable() {
public void run()
{
showBusy(true);
_viewAll.setChecked(false);
_viewPrevious.setChecked(false);
_viewNext.setChecked(true);
_viewSequence.setChecked(false);
setLayoutAlgorithm(RadialLayoutAlgorithm.class);
_selectedProduction = nearestProduction;
_viewer.setSelection(new StructuredSelection(nearestProduction));
setACTRCompilationUnit(editor.getCompilationUnit());
_viewer.setContentProvider(new TreeContentProvider(
ProductionSequenceView.this, nearestProduction, true));
showBusy(false);
}
};
_viewer.getControl().getDisplay().asyncExec(runner);
}
else
clear();
}
public void viewSequence(final ACTRModelEditor editor,
final CommonTree current)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("Attempting to visualize sequence");
if (current != null)
{
Runnable runner = new Runnable() {
public void run()
{
showBusy(true);
_viewAll.setChecked(false);
_viewPrevious.setChecked(false);
_viewNext.setChecked(false);
_viewSequence.setChecked(true);
_selectedProduction = current;
setLayoutAlgorithm(SpringLayoutAlgorithm.class);
_viewer.setSelection(new StructuredSelection(current));
setACTRCompilationUnit(editor.getCompilationUnit());
_viewer.setContentProvider(new SequenceContentProvider(
ProductionSequenceView.this, current, _depth));
// _viewer.refresh();
showBusy(false);
}
};
_viewer.getControl().getDisplay().asyncExec(runner);
}
else
clear();
}
protected void clear()
{
if (LOGGER.isDebugEnabled()) LOGGER.debug("Clearing");
_viewer.setInput(null);
_viewAll.setChecked(false);
_viewPrevious.setChecked(false);
_viewNext.setChecked(false);
_viewSequence.setChecked(false);
_modelDescriptor = null;
}
protected boolean setACTRCompilationUnit(ICompilationUnit unit)
{
if (unit == null)
clear();
else if (setModelDescriptor(unit))
{
/*
* model descriptor has changed, we need to run the sequence analyzer
*/
AnalyzerJob job = new AnalyzerJob(this, _modelDescriptor);
job.schedule();
return true;
}
return false;
}
protected void setProductionRelationships(
Map<CommonTree, ProductionRelationships> relationships)
{
_relationships = relationships;
/*
* notify the graph viewer of the change
*/
_viewer.getControl().getDisplay().asyncExec(new Runnable() {
public void run()
{
showBusy(true);
if (LOGGER.isDebugEnabled()) LOGGER.debug("Setting input");
_viewer.setInput(_relationships);
showBusy(false);
}
});
}
private boolean setModelDescriptor(ICompilationUnit unit)
{
CommonTree modelDesc = unit.getModelDescriptor();
if (modelDesc != _modelDescriptor)
{
if (LOGGER.isDebugEnabled()) LOGGER.debug("Setting model descriptor");
_modelDescriptor = modelDesc;
return true;
}
return false;
}
}