/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * 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: * Foster Wheeler Energia Oy - initial API and implementation *******************************************************************************/ package org.simantics.interop.test; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; 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.MenuManager; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.ListViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.window.IShellProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DropTarget; import org.eclipse.swt.dnd.DropTargetAdapter; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.HelpListener; import org.eclipse.swt.events.MenuDetectEvent; import org.eclipse.swt.events.MenuDetectListener; 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.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.part.ViewPart; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.Statement; import org.simantics.db.common.ResourceArray; import org.simantics.db.common.request.ReadRequest; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.InvalidResourceReferenceException; import org.simantics.db.exception.ServiceException; import org.simantics.db.exception.ValidationException; import org.simantics.db.request.Read; import org.simantics.db.service.SerialisationSupport; import org.simantics.layer0.Layer0; import org.simantics.ui.SimanticsUI; import org.simantics.ui.dnd.LocalObjectTransfer; import org.simantics.ui.dnd.ResourceReferenceTransfer; import org.simantics.ui.dnd.ResourceTransferUtils; import org.simantics.ui.utils.ResourceAdaptionUtils; import org.simantics.utils.datastructures.BijectionMap; import org.simantics.utils.datastructures.Pair; import org.simantics.utils.ui.ExceptionUtils; /** * Simple multiline text viewer for seeing differences in two subgraphs. * * @author Marko Luukkainen * */ public class GraphComparatorViewer extends ViewPart{ private Session session; private Composite composite; private Label resourceText1; private Label resourceText2; private Text text1; private Text text2; private List traversed = new ArrayList(); private List tested = new ArrayList(); private List strong = new ArrayList(); private List nonTraversed = new ArrayList(); private List nonTested = new ArrayList(); @Override public void createPartControl(Composite parent) { composite = new Composite(parent, SWT.NONE); composite.setLayout(new GridLayout(2, false)); session = SimanticsUI.getSession(); Composite topComposite = new Composite(composite, SWT.BORDER); topComposite.setLayout(new GridLayout(3, false)); text1 = new Text(composite, SWT.MULTI|SWT.V_SCROLL); text2 = new Text(composite, SWT.MULTI|SWT.V_SCROLL); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP).grab(true, false).span(2, 1).applyTo(topComposite); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(text1); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(text2); resourceText1 = createDropLabel(topComposite); resourceText2 = createDropLabel(topComposite); Button button = new Button(topComposite, SWT.PUSH); button.setText("Compare"); button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { compare(); } }); defaultConf(); getViewSite().getActionBars().getToolBarManager().add(new Action("Config") { @Override public void run() { ConfigurationDialog dialog = new ConfigurationDialog(getSite().getShell()); dialog.open(); } }); } private void defaultConf() { traversed.clear(); tested.clear(); strong.clear(); nonTested.clear(); nonTraversed.clear(); try { session.syncRequest(new ReadRequest() { @Override public void run(ReadGraph graph) throws DatabaseException { Layer0 l0 = Layer0.getInstance(graph); traversed.add(l0.ConsistsOf); tested.add(l0.IsWeaklyRelatedTo); } }); } catch (Exception e) { ExceptionUtils.logAndShowError(e); } } private void compare() { text1.setText(""); text2.setText(""); final Resource r1 = (Resource)resourceText1.getData(); final Resource r2 = (Resource)resourceText2.getData(); if (r1 == null || r2 == null) { if (r1 == null) text1.setText("Missing input!"); if (r2 == null) text2.setText("Missing input!"); return; } session.asyncRequest(new ReadRequest() { @Override public void run(final ReadGraph graph) throws DatabaseException { GraphComparator comparator = new GraphComparator(r1,r2); comparator.addTested(tested); comparator.addTraversed(traversed); comparator.addNonTested(nonTested); comparator.addNonTraversed(nonTraversed); comparator.addStrong(strong); comparator.test(graph); BijectionMap map = comparator.getComparableStatements(); Map indices = new HashMap(); final StringBuilder sb1 = new StringBuilder(); final StringBuilder sb2 = new StringBuilder(); int index = 0; GraphChanges changes = comparator.getChanges(); for (Pair mod : changes.getModifications()) { { String sub; try { Statement s = mod.first; sub = NameUtils.getSafeName(graph, s.getSubject()); String pre = NameUtils.getSafeName(graph, s.getPredicate()); String obj = NameUtils.getSafeName(graph, s.getObject()); if (map.containsLeft(s)) { index++; indices.put(s, index); sb1.append("["+index + "] "); } sb1.append(sub + " - " + pre + " - " + obj); sb1.append(" ["+s.getSubject().getResourceId() + " " + s.getPredicate().getResourceId() + " " + s.getObject().getResourceId()+"]"); sb1.append("\n"); } catch (ValidationException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } { String sub; try { Statement s = mod.second; sub = NameUtils.getSafeName(graph, s.getSubject()); String pre = NameUtils.getSafeName(graph, s.getPredicate()); String obj = NameUtils.getSafeName(graph, s.getObject()); if (map.containsRight(s)) { index = indices.get(map.getLeft(s)); sb2.append("["+index + "] "); } sb2.append(sub + " - " + pre + " - " + obj); sb2.append(" ["+s.getSubject().getResourceId() + " " + s.getPredicate().getResourceId() + " " + s.getObject().getResourceId()+"]"); sb2.append("\n"); } catch (ValidationException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } } for (Statement s : changes.getDeletions()) { String sub; try { sub = NameUtils.getSafeName(graph, s.getSubject()); String pre = NameUtils.getSafeName(graph, s.getPredicate()); String obj = NameUtils.getSafeName(graph, s.getObject()); if (map.containsLeft(s)) { index++; indices.put(s, index); sb1.append("["+index + "] "); } sb1.append(sub + " - " + pre + " - " + obj); sb1.append(" ["+s.getSubject().getResourceId() + " " + s.getPredicate().getResourceId() + " " + s.getObject().getResourceId()+"]"); sb1.append("\n"); } catch (ValidationException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } for (Statement s : changes.getAdditions()) { String sub; try { sub = NameUtils.getSafeName(graph, s.getSubject()); String pre = NameUtils.getSafeName(graph, s.getPredicate()); String obj = NameUtils.getSafeName(graph, s.getObject()); if (map.containsRight(s)) { index = indices.get(map.getLeft(s)); sb2.append("["+index + "] "); } sb2.append(sub + " - " + pre + " - " + obj); sb2.append(" ["+s.getSubject().getResourceId() + " " + s.getPredicate().getResourceId() + " " + s.getObject().getResourceId()+"]"); sb2.append("\n"); } catch (ValidationException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } Display.getDefault().asyncExec(new Runnable() { @Override public void run() { text1.setText(sb1.toString()); text2.setText(sb2.toString()); } }); } }); } @Override public void setFocus() { composite.setFocus(); } @Override public void dispose() { super.dispose(); } // copy-paste from GraphDebugger public Label createDropLabel(Composite parent) { final Label label = new Label(parent, SWT.BORDER); label.setAlignment(SWT.CENTER); label.setText("Drag a resource here to examine it in this debugger!"); label.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY)); GridData data = new GridData(SWT.FILL, SWT.TOP, true, false); data.heightHint = 16; label.setLayoutData(data); // Add resource id drop support to the drop-area. DropTarget dropTarget = new DropTarget(label, DND.DROP_LINK | DND.DROP_COPY); dropTarget.setTransfer(new Transfer[] { TextTransfer.getInstance(), ResourceReferenceTransfer.getInstance(), LocalObjectTransfer.getTransfer() }); dropTarget.addDropListener(new DropTargetAdapter() { @Override public void dragEnter(DropTargetEvent event) { event.detail = DND.DROP_LINK; //label.setBackground(green); return; } @Override public void dragLeave(DropTargetEvent event) { label.setBackground(null); } @Override public void drop(DropTargetEvent event) { label.setBackground(null); ResourceArray[] data = parseEventData(event); if (data == null || data.length != 1) { event.detail = DND.DROP_NONE; return; } final ResourceArray array = data[0]; final Resource r = array.resources[array.resources.length - 1]; label.setData(r); try { label.setText(session.syncRequest(new Read() { @Override public String perform(ReadGraph graph) throws DatabaseException { return NameUtils.getSafeName(graph, r); } })); } catch (DatabaseException e) { e.printStackTrace(); } } private ResourceArray[] parseEventData(DropTargetEvent event) { //System.out.println("DATA: " + event.data); if (event.data instanceof String) { try { SerialisationSupport support = session.getService(SerialisationSupport.class); return ResourceTransferUtils.readStringTransferable(support.getResourceSerializer(), (String) event.data).toResourceArrayArray(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (InvalidResourceReferenceException e) { e.printStackTrace(); } } ResourceArray[] ret = ResourceAdaptionUtils.toResourceArrays(event.data); if (ret.length > 0) return ret; return null; } }); return label; } private class ConfigurationDialog extends Dialog { protected ConfigurationDialog(Shell parentShell) { super(parentShell); } @Override protected void createButtonsForButtonBar(Composite parent) { createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); } @Override protected Control createDialogArea(Composite parent) { Composite composite = (Composite) super.createDialogArea(parent); composite.setLayout(new FillLayout(SWT.VERTICAL)); Group group = new Group(composite, SWT.NONE); group.setText("Traversed"); group.setLayout(new FillLayout()); ListViewer traversedViewer = new ListViewer(group); group = new Group(composite, SWT.NONE); group.setText("Tested"); group.setLayout(new FillLayout()); ListViewer testedViewer = new ListViewer(group); group = new Group(composite, SWT.NONE); group.setText("Strong"); group.setLayout(new FillLayout()); ListViewer strongViewer = new ListViewer(group); group = new Group(composite, SWT.NONE); group.setText("NonTraversed"); group.setLayout(new FillLayout()); ListViewer nonTraversedViewer = new ListViewer(group); group = new Group(composite, SWT.NONE); group.setText("NonTested"); group.setLayout(new FillLayout()); ListViewer nonTestedViewer = new ListViewer(group); traversedViewer.setContentProvider(new ResourceListContentProvider()); traversedViewer.setLabelProvider(new ResourceLabelProvider()); testedViewer.setContentProvider(new ResourceListContentProvider()); testedViewer.setLabelProvider(new ResourceLabelProvider()); strongViewer.setContentProvider(new ResourceListContentProvider()); strongViewer.setLabelProvider(new ResourceLabelProvider()); nonTraversedViewer.setContentProvider(new ResourceListContentProvider()); nonTraversedViewer.setLabelProvider(new ResourceLabelProvider()); nonTestedViewer.setContentProvider(new ResourceListContentProvider()); nonTestedViewer.setLabelProvider(new ResourceLabelProvider()); MenuManager strongManager = new MenuManager(); strongManager.setRemoveAllWhenShown(true); strongManager.addMenuListener(new ListPopupListener(strongViewer)); strongViewer.getControl().setMenu(strongManager.createContextMenu(strongViewer.getControl())); MenuManager nonTestedManager = new MenuManager(); nonTestedManager.setRemoveAllWhenShown(true); nonTestedManager.addMenuListener(new ListPopupListener(nonTestedViewer)); nonTestedViewer.getControl().setMenu(nonTestedManager.createContextMenu(nonTestedViewer.getControl())); MenuManager nonTraversedManager = new MenuManager(); nonTraversedManager.setRemoveAllWhenShown(true); nonTraversedManager.addMenuListener(new ListPopupListener(nonTraversedViewer)); nonTraversedViewer.getControl().setMenu(nonTraversedManager.createContextMenu(nonTraversedViewer.getControl())); MenuManager testedManager = new MenuManager(); testedManager.setRemoveAllWhenShown(true); testedManager.addMenuListener(new ListPopupListener(testedViewer)); testedViewer.getControl().setMenu(testedManager.createContextMenu(testedViewer.getControl())); MenuManager traversedManager = new MenuManager(); traversedManager.setRemoveAllWhenShown(true); traversedManager.addMenuListener(new ListPopupListener(traversedViewer)); traversedViewer.getControl().setMenu(traversedManager.createContextMenu(traversedViewer.getControl())); traversedViewer.setInput(traversed); testedViewer.setInput(tested); strongViewer.setInput(strong); nonTestedViewer.setInput(nonTested); nonTraversedViewer.setInput(nonTraversed); return composite; } } private class ListPopupListener implements IMenuListener { private ListViewer viewer; public ListPopupListener(ListViewer viewer) { this.viewer = viewer; } @Override public void menuAboutToShow(IMenuManager manager) { IStructuredSelection s = (IStructuredSelection)viewer.getSelection(); List list = (List)viewer.getInput(); manager.add(new AddAction(viewer, list)); if (!s.isEmpty()) { Object element = s.getFirstElement(); manager.add(new DeleteAction(viewer, list, element)); } } } private class DeleteAction extends Action { private Viewer viewer; private List list; private Object obj; public DeleteAction(Viewer viewer, List list, Object obj) { super("Delete"); this.list = list; this.obj = obj; this.viewer = viewer; } @Override public void run() { list.remove(obj); viewer.refresh(); } } private class AddAction extends Action { private Viewer viewer; private List list; public AddAction(Viewer viewer, List list) { super("Add"); this.list = list; this.viewer = viewer; } @Override public void run() { RelationChooseDialog dialog = new RelationChooseDialog(getSite().getShell()); if (dialog.open() == RelationChooseDialog.OK) { final String uri = dialog.getUri(); try { Resource res = session.syncRequest(new Read() { @Override public Resource perform(ReadGraph graph) throws DatabaseException { try { return graph.getResource(uri); } catch (Exception e) { return null; } } }); if (res != null) { list.add(res); viewer.refresh(); } else { MessageDialog.openError(getSite().getShell(), "Error", "Relation '" + uri + "' not found."); } } catch (Exception e) { } } } } private class RelationChooseDialog extends Dialog { private String uri = null; private Text text; public RelationChooseDialog(IShellProvider parentShell) { super(parentShell); } public RelationChooseDialog(Shell parentShell) { super(parentShell); } @Override protected Control createDialogArea(Composite parent) { Composite composite = (Composite) super.createDialogArea(parent); composite.setLayout(new GridLayout(2, false)); Label label = new Label(composite, SWT.NONE); label.setText("URI:"); text = new Text(composite, SWT.SINGLE | SWT.BORDER); text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); return composite; } @Override protected void okPressed() { uri = text.getText(); super.okPressed(); } public String getUri() { return uri; } } private class ResourceListContentProvider implements IStructuredContentProvider { @SuppressWarnings("unchecked") @Override public Object[] getElements(Object inputElement) { List list = (List)inputElement; return list.toArray(); } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public void dispose() { } } private class ResourceLabelProvider extends LabelProvider { @Override public String getText(Object element) { final Resource res = (Resource) element; try { return session.syncRequest(new Read() { @Override public String perform(ReadGraph graph) throws DatabaseException { return NameUtils.getSafeName(graph, res); } }); } catch (DatabaseException e) { return "Error: " + e.getMessage(); } } } }