| /******************************************************************************* |
| * Copyright (c) 2009 Zoltan Ujhelyi and Daniel Varro. |
| * 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: |
| * Zoltan Ujhelyi - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.viatra2.visualisation.patterns; |
| |
| import java.util.ArrayList; |
| import java.util.Hashtable; |
| import java.util.List; |
| |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.IToolBarManager; |
| import org.eclipse.jface.viewers.ViewerFilter; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.layout.FillLayout; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Combo; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.ui.forms.widgets.FormToolkit; |
| import org.eclipse.ui.forms.widgets.ScrolledForm; |
| import org.eclipse.ui.forms.widgets.Section; |
| import org.eclipse.ui.views.properties.IPropertySheetPage; |
| import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor; |
| import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage; |
| import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.definitions.Machine; |
| import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.gt.GTPattern; |
| import org.eclipse.viatra2.visualisation.IVisualisationDescriptor; |
| import org.eclipse.viatra2.visualisation.ViatraColoredLabelProvider; |
| import org.eclipse.viatra2.visualisation.ViatraGraphViewer; |
| import org.eclipse.viatra2.visualisation.VisualisationPlugin; |
| import org.eclipse.viatra2.visualisation.common.extensions.FilterConfiguration; |
| import org.eclipse.viatra2.visualisation.common.extensions.NamedElement; |
| import org.eclipse.viatra2.visualisation.common.extensions.VisualisationPreset; |
| import org.eclipse.viatra2.visualisation.layouts.IViatraLayoutAlgorithm; |
| import org.eclipse.viatra2.visualisation.patterns.actions.PatternProviderGroup; |
| import org.eclipse.viatra2.visualisation.patterns.sources.PatternContentProvider; |
| import org.eclipse.viatra2.visualisation.patterns.sources.PatternLabelProvider; |
| import org.eclipse.viatra2.visualisation.view.ViatraVisualisationView; |
| import org.eclipse.zest.core.widgets.ZestStyles; |
| import org.eclipse.zest.layouts.LayoutAlgorithm; |
| import org.eclipse.zest.layouts.LayoutStyles; |
| import org.eclipse.zest.layouts.algorithms.CompositeLayoutAlgorithm; |
| import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm; |
| import org.eclipse.zest.layouts.algorithms.HorizontalShift; |
| |
| /** |
| * <p> |
| * Describes a pattern graph visualisation task. The data model of the |
| * visualisation is a {@link Machine}, and basically its patterns are displayed |
| * as graphs. |
| * </p> |
| * <p> |
| * The descriptor allows the storage of several different views of a single |
| * machine in a path (stored as a stack), and allows basic back-navigation using |
| * it. |
| * </p> |
| * @author Zoltan Ujhelyi |
| */ |
| public class PatternGraphDescriptor implements IVisualisationDescriptor, |
| ITabbedPropertySheetPageContributor { |
| |
| PatternGraphViewer gv; |
| PatternProviderGroup providers = new PatternProviderGroup(); |
| PatternContentProvider contentProvider = providers.getDefaultProvider(); |
| PatternLabelProvider labelProvider = new PatternLabelProvider(); |
| Machine machine; |
| String machineName; |
| Hashtable<String, GTPattern> patternStorage; |
| Combo list; |
| LayoutAlgorithm layout; |
| |
| ArrayList<LocationElement> locationStack = new ArrayList<LocationElement>(); |
| int locationID = 0; |
| |
| // Actions |
| Action previousViewerAction = new Action() { |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.action.Action#run() |
| */ |
| @Override |
| public void run() { |
| if (locationID > 0) popItem(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.action.Action#isEnabled() |
| */ |
| @Override |
| public boolean isEnabled() { |
| return locationID > 1; |
| } |
| |
| }; |
| private List<ViewerFilter> filters = new ArrayList<ViewerFilter>(); |
| |
| /** |
| * Initializes the pattern graph descriptor. |
| */ |
| public PatternGraphDescriptor() { |
| previousViewerAction.setText("Back"); |
| previousViewerAction.setToolTipText("Displays the previous view"); |
| previousViewerAction.setImageDescriptor(VisualisationPlugin |
| .imageDescriptorFromPlugin(VisualisationPlugin.PLUGIN_ID, |
| "icons/nav_backward.gif")); |
| previousViewerAction.setEnabled(false); |
| } |
| |
| /** |
| * Sets the machine connected to the descriptor. The machine contains a list |
| * of all elements to visualise. |
| * @param machine |
| * the {@link Machine} machine to set |
| */ |
| public void setMachine(Machine machine) { |
| this.machine = machine; |
| patternStorage = new Hashtable<String, GTPattern>(); |
| for (GTPattern pattern : machine.getGtPatternDefinitions()) { |
| patternStorage.put(pattern.getName(), pattern); |
| } |
| machineName = machine.getName(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @seeorg.eclipse.viatra2.visualisation.IVisualisationDescriptor# |
| * addMenuContributions(org.eclipse.jface.action.IMenuManager) |
| */ |
| public void addMenuContributions(IMenuManager manager) { |
| providers.fillContextMenu(manager); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @seeorg.eclipse.viatra2.visualisation.IVisualisationDescriptor# |
| * addToolbarContributions(org.eclipse.jface.action.IToolBarManager) |
| */ |
| public void addToolbarContributions(IToolBarManager manager) { |
| manager.add(previousViewerAction); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.viatra2.visualisation.IVisualisationDescriptor#clearGraphModel |
| * () |
| */ |
| public void clearGraphModel() { |
| |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.viatra2.visualisation.IVisualisationDescriptor#getAdapter |
| * (java.lang.Class) |
| */ |
| public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { |
| if (adapter == IPropertySheetPage.class) |
| return new TabbedPropertySheetPage(this); |
| return null; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.viatra2.visualisation.IVisualisationDescriptor#getViewer() |
| */ |
| public ViatraGraphViewer getViewer() { |
| return gv; |
| } |
| |
| private ViatraGraphViewer initializeViewer(Composite parent) { |
| gv = new PatternGraphViewer(parent, SWT.NONE); |
| GridLayoutAlgorithm gridLayout = new GridLayoutAlgorithm( |
| LayoutStyles.NO_LAYOUT_NODE_RESIZING |
| | LayoutStyles.ENFORCE_BOUNDS); |
| layout = new CompositeLayoutAlgorithm( |
| LayoutStyles.NO_LAYOUT_NODE_RESIZING, |
| new LayoutAlgorithm[] { |
| new GridLayoutAlgorithm( |
| LayoutStyles.NO_LAYOUT_NODE_RESIZING), |
| new HorizontalShift( |
| LayoutStyles.NO_LAYOUT_NODE_RESIZING) }); |
| gv.setCompoundLayout(layout); |
| gv.setLayoutAlgorithm(gridLayout); |
| gv.setContentProvider(contentProvider); |
| gv.setLabelProvider(labelProvider); |
| gv.setNodeStyle(ZestStyles.NODES_NO_LAYOUT_RESIZE); |
| gv.setDescriptor(this); |
| //TODO this is needed for findGraphNode to work in doubleclicklistener |
| gv.setUseHashlookup(false); |
| pushItem(machine); |
| return gv; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.viatra2.visualisation.IVisualisationDescriptor#removeSelection |
| * () |
| */ |
| public void removeSelection() { |
| |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.services.IDisposable#dispose() |
| */ |
| public void dispose() { |
| |
| } |
| |
| /** |
| * Explicitly sets the previousViewerAction item's enabled property. This |
| * call is required (it is not enough to rely on the isEnabled() method of |
| * the Action). |
| */ |
| private void setViewerActionEnabled() { |
| if (locationStack.size() > 1) { |
| previousViewerAction.setEnabled(true); |
| } else { |
| previousViewerAction.setEnabled(false); |
| } |
| } |
| |
| /** |
| * Increases the location stack of the descriptor by adding a new item to it |
| * and updates the graph viewer to represent this new location. The new item |
| * can be an item already present in the stack. |
| * @param location |
| * the new location item |
| */ |
| public void pushItem(Object location) { |
| if (locationStack.isEmpty() |
| || !locationStack.get(locationID - 1).getInputElement().equals( |
| location)) { |
| LocationElement element = new LocationElement(); |
| element.setInputElement(location); |
| locationStack.add(locationID, element); |
| locationID++; |
| } |
| gv.setInput(location); |
| gv.refresh(); |
| if (location instanceof Machine) { |
| list.setText(((Machine) location).getName()); |
| } else if (location instanceof GTPattern) { |
| list.setText(((GTPattern) location).getName()); |
| } |
| setViewerActionEnabled(); |
| } |
| |
| /** |
| * Selects the top location from the location stack and removes it. It also |
| * updates the graph viewer to represent the selected location. |
| */ |
| public void popItem() { |
| locationID--; |
| LocationElement element = locationStack.get(locationID); |
| Object location = element.getInputElement(); |
| locationStack.remove(locationID); |
| gv.setInput(location); |
| gv.refresh(); |
| if (location instanceof Machine) { |
| list.setText(((Machine) location).getName()); |
| } else if (location instanceof GTPattern) { |
| list.setText(((GTPattern) location).getName()); |
| } |
| setViewerActionEnabled(); |
| } |
| |
| public String getContributorId() { |
| return ViatraVisualisationView.viewId; |
| } |
| |
| public void createFormContributions(Composite parent) { |
| FormToolkit toolkit = new FormToolkit(parent.getDisplay()); |
| ScrolledForm form = toolkit.createScrolledForm(parent); |
| createHeaderRegion(form, toolkit); |
| FillLayout layout = new FillLayout(); |
| layout.marginHeight = 10; |
| layout.marginWidth = 4; |
| form.getBody().setLayout(layout); |
| Section section = toolkit.createSection(form.getBody(), |
| Section.NO_TITLE); |
| initializeViewer(section); |
| section.setClient(gv.getGraphControl()); |
| } |
| |
| private void createHeaderRegion(ScrolledForm form, FormToolkit toolkit) { |
| form.setText(machineName); |
| |
| Composite header = new Composite(form.getForm().getHead(), SWT.NONE); |
| GridLayout glayout = new GridLayout(); |
| glayout.marginWidth = glayout.marginHeight = 0; |
| glayout.numColumns = 2; |
| header.setLayout(glayout); |
| header.setBackgroundMode(SWT.INHERIT_DEFAULT); |
| form.setHeadClient(header); |
| |
| Label label = new Label(header, SWT.NONE); |
| label.setText("Element to visualise"); |
| list = new Combo(header, SWT.DROP_DOWN | SWT.READ_ONLY); |
| toolkit.adapt(list); |
| list.add(machineName); |
| for (GTPattern pattern : patternStorage.values()) { |
| list.add(pattern.getName()); |
| } |
| list.setText(machineName); |
| list.addSelectionListener(new SelectionAdapter() { |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse |
| * .swt.events.SelectionEvent) |
| */ |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| String text = list.getText(); |
| if (text == null) return; |
| if (text.equals(machineName)) { |
| if (!gv.getInput().equals(machine)) { |
| pushItem(machine); |
| } |
| return; |
| } |
| if (patternStorage.containsKey(text)) { |
| GTPattern pattern = patternStorage.get(text); |
| if (!gv.getInput().equals(pattern)) { |
| pushItem(pattern); |
| } |
| return; |
| } |
| } |
| |
| }); |
| GridData data = new GridData(); |
| data.widthHint = 200; |
| list.setLayoutData(data); |
| toolkit.adapt(header); |
| toolkit.decorateFormHeading(form.getForm()); |
| } |
| |
| public void setLayoutAlgorithm(IViatraLayoutAlgorithm algorithm) { |
| for (ViewerFilter filter : filters) { |
| gv.removeFilter(filter); |
| } |
| gv.setCompoundLayout(algorithm.getAlgorithm()); |
| // filters = algorithm.getFilters(); |
| for (ViewerFilter filter : filters) { |
| gv.addFilter(filter); |
| } |
| gv.applyLayout(); |
| } |
| |
| public void setVisualisationPreset(VisualisationPreset vp) { |
| for (ViewerFilter filter : filters) { |
| gv.removeFilter(filter); |
| } |
| gv.setCompoundLayout(vp.layout.element.getAlgorithm()); |
| filters.clear(); |
| for (NamedElement<ViewerFilter> _filter : vp.filters.filters) { |
| gv.addFilter(_filter.element); |
| filters.add(_filter.element); |
| } |
| // gv.setLabelProvider(vp.labelprovider.element); |
| gv.applyLayout(); |
| gv.refresh(); |
| } |
| |
| public void setLabelProvider(ViatraColoredLabelProvider provider) { |
| setLabelProvider(provider, true); |
| } |
| |
| public void setLabelProvider(ViatraColoredLabelProvider provider, boolean doRefresh) { |
| // FIXME Istvan: ignore this call for now, |
| // in order to avoid using incompatible label providers for pattern graph visualization |
| //gv.setLabelProvider(provider); |
| //gv.refresh(); |
| } |
| |
| public void setFilterConfiguration(FilterConfiguration fc) { |
| setFilterConfiguration(fc, true); |
| } |
| |
| public void setFilterConfiguration(FilterConfiguration fc, boolean doRefresh) { |
| for (ViewerFilter filter : filters) { |
| gv.removeFilter(filter); |
| } |
| filters.clear(); |
| for (NamedElement<ViewerFilter> _filter : fc.filters) { |
| gv.addFilter(_filter.element); |
| filters.add(_filter.element); |
| } |
| gv.refresh(); |
| |
| } |
| |
| @Override |
| public void refreshGraph() { |
| gv.refresh(); |
| } |
| |
| @Override |
| public void redrawGraph() { |
| gv.applyLayout(); |
| } |
| } |