/******************************************************************************* * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.modeling.ui.diagramEditor.handlers; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.function.Consumer; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.PartInitException; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.ResourceArray; import org.simantics.db.common.request.ReadRequest; import org.simantics.db.common.utils.OrderedSetUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.management.ISessionContext; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant; import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency; import org.simantics.g2d.diagram.DiagramHints; import org.simantics.g2d.diagram.IDiagram; import org.simantics.g2d.diagram.handler.DataElementMap; import org.simantics.g2d.diagram.participant.Selection; import org.simantics.g2d.element.ElementHints; import org.simantics.g2d.element.ElementUtils; import org.simantics.g2d.element.IElement; import org.simantics.g2d.participant.CanvasBoundsParticipant; import org.simantics.g2d.participant.TransformUtil; import org.simantics.g2d.utils.GeometryUtils; import org.simantics.modeling.ModelingResources; import org.simantics.modeling.ui.diagramEditor.DiagramViewer; import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDoubleClickedEvent; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.ui.workbench.ResourceEditorInput; import org.simantics.utils.page.MarginUtils; import org.simantics.utils.threads.ThreadUtils; import org.simantics.utils.ui.ErrorLogger; import org.simantics.utils.ui.workbench.WorkbenchUtils; /** * StructuralBrowsingHandler supports visual browsing into subcomponents through * mouse events. * * @author Tuukka Lehtonen */ public class LinkBrowsingHandler extends AbstractCanvasParticipant { @Dependency CanvasBoundsParticipant canvasBounds; @Dependency Selection selection; IWorkbenchPartSite site; DiagramViewer viewer; ISessionContext sessionContext; public LinkBrowsingHandler(IWorkbenchPartSite site, DiagramViewer viewer, ISessionContext context) { assert site != null; // System.out.println("LinkBrowsingHandler " + viewer + " " + viewer.structuralPath); this.site = site; this.viewer = viewer; this.sessionContext = context; } public static Runnable editorActivator(final IEditorPart part, final ResourceArray input, final Consumer successCallback) { String sourcePartId = part.getSite().getId(); return editorActivator(sourcePartId, input, successCallback); } public Runnable elementSelectorZoomer(final ICanvasContext canvas, final Collection elementObjects, final boolean keepZoom) { return new Runnable() { @Override public void run() { IDiagram diagram = canvas.getHintStack().getHint(DiagramHints.KEY_DIAGRAM); assert diagram != null; if (!zoomToSelection(canvas, diagram, selectElement(canvas, diagram, elementObjects), keepZoom)) { // Reschedule for later. ThreadUtils.asyncExec(canvas.getThreadAccess(), this); } } }; } public static Set selectElement(final ICanvasContext canvas, final IDiagram diagram, final Collection elementObjects) { // Select element Set selection = new HashSet(); DataElementMap dataMap = diagram.getDiagramClass().getSingleItem(DataElementMap.class); for (Object obj : elementObjects) { IElement element = dataMap.getElement(diagram, obj); if (element == null) { ErrorLogger.defaultLogWarning("No element to select for object " + obj, new Exception()); } else { selection.add(element); } } for (Selection s : canvas.getItemsByClass(Selection.class)) { s.setSelection(0, selection); } return selection; } public boolean zoomToSelection(final ICanvasContext canvas, final IDiagram diagram, Set selection, boolean keepZoom) { TransformUtil util = canvas.getSingleItem(TransformUtil.class); Rectangle2D controlBounds = canvasBounds.getControlBounds(); if (controlBounds == null) return false; Shape shp = ElementUtils.getElementBoundsOnDiagram(selection); if (shp == null) return false; Rectangle2D diagramRect = shp.getBounds2D(); if (keepZoom) { double scaleFactor = GeometryUtils.getScale(util.getTransform()); double cwh = controlBounds.getWidth() / (scaleFactor*2); double chh = controlBounds.getHeight() / (scaleFactor*2); AffineTransform view = new AffineTransform(); view.scale(scaleFactor, scaleFactor); view.translate(-diagramRect.getCenterX()+cwh, -diagramRect.getCenterY()+chh); util.setTransform(view); } else { MarginUtils.Margin margin = MarginUtils.marginOf(40, 0, 0); MarginUtils.Margins margins = new MarginUtils.Margins(margin, margin, margin, margin); util.fitArea(controlBounds, diagramRect, margins); } return true; } public static Runnable editorActivator(String editorPartId, ResourceArray input, Consumer successCallback) { return new Runnable() { @Override public void run() { try { // open and activate new editor IEditorPart newPart = WorkbenchUtils.openEditor(editorPartId, new ResourceEditorInput(editorPartId, input)); newPart.getSite().getPage().activate(newPart); successCallback.accept(newPart); } catch (PartInitException e) { // TODO: handle properly e.printStackTrace(); } } }; } public static Resource getOwnerList(ReadGraph g, Resource listElement) throws DatabaseException { return OrderedSetUtils.getSingleOwnerList(g, listElement, DiagramResource.getInstance(g).Composite); } @EventHandler(priority = 0) public boolean handleDoubleClick(MouseDoubleClickedEvent me) { //System.out.println("LinkBrowsingHandler"); if (sessionContext == null) return false; Set sel = selection.getSelection(0); if (sel.size() == 1) { IElement e = sel.iterator().next(); Object data = e.getHint(ElementHints.KEY_OBJECT); if (data instanceof Resource) { final Resource element = (Resource) data; sessionContext.getSession().asyncRequest(new ReadRequest() { @Override public void run(ReadGraph graph) throws DatabaseException { //System.out.println("LinkBrowsingHandler0"); ModelingResources mr = ModelingResources.getInstance(graph); DiagramResource dr = DiagramResource.getInstance(graph); StructuralResource2 sr = StructuralResource2.getInstance(graph); if (graph.isInstanceOf(element, dr.UpwardLink)) { // Resource component = viewer.structuralPath.resources[0]; // Resource element = graph.getPossibleObject(component, mr.ComponentToElement); // Resource diagram = getOwnerList(graph, element); // // IEditorPart thisEditor = (IEditorPart) site.getPart(); // site.getWorkbenchWindow().getShell().getDisplay().asyncExec( // editorActivator(thisEditor, viewer.structuralPath.removeFromBeginning(1).prepended(diagram), new Callback() { // @Override // public void run(IEditorPart part) { // } // })); } else if (graph.isInstanceOf(element, dr.Link)) { //System.out.println("LinkBrowsingHandler2"); // ContextMap parameters = new ContextMap(); // parameters.put(ModelingOperationConstants.WORKBENCH_WINDOW, site.getWorkbenchWindow()); // parameters.put(ModelingOperationConstants.WORKBENCH_PART, site.getPart()); // parameters.put(IOperation.SUBJECT, element); Resource thisDiagram = getOwnerList(graph, element); if (thisDiagram == null) return; final Resource target = graph.getPossibleObject(element, dr.HasLinkTarget); if (target == null) return; final Resource otherDiagram = getOwnerList(graph, target); if (otherDiagram == null) return; final Resource component = graph.getPossibleObject(target, mr.ElementToComponent); if (component == null) return; Resource type = graph.getSingleType(component, sr.Component); if (type == null) return; Resource definedBy = graph.getPossibleObject(type, sr.IsDefinedBy); if (definedBy == null) return; final Resource diagram = graph.getPossibleObject(definedBy, mr.CompositeToDiagram); if (diagram == null) return; // PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { // @Override // public void run() { // try { // WorkbenchUtils.openEditor(site.getId(), new ResourceEditorInput(site.getId(), parentStructuralPath.prepended(diagram, component))); // } catch (PartInitException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // } // }); // IEditorPart thisEditor = (IEditorPart) site.getPart(); // ResourceArray input = viewer.structuralPath.prepended(diagram, component); // System.out.println("Browsing link " + input); // site.getWorkbenchWindow().getShell().getDisplay().asyncExec( // editorActivator(thisEditor, input, new Callback() { // @Override // public void run(IEditorPart part) { //// final ICanvasContext openedCanvas = (ICanvasContext) part.getAdapter(ICanvasContext.class); //// assert openedCanvas != null; //// IDiagram diagram = (IDiagram) part.getAdapter(IDiagram.class); //// assert diagram != null; // // Disable automatic-zoom-to-fit //// diagram.removeHint(DiagramHints.KEY_INITIAL_ZOOM_TO_FIT); //// ThreadUtils.asyncExec(openedCanvas.getThreadAccess(), //// elementSelectorZoomer(openedCanvas, Collections.singleton((Object) target), false)); // } // })); // System.out.println("LinkBrowsingHandler3"); // // if (!thisDiagram.equals(otherDiagram)) { // // System.out.println("LinkBrowsingHandler4"); // // // Find the structural path // Resource ownerComposite = graph.getPossibleObject(otherDiagram, mr.DiagramToComposite); // if (ownerComposite == null) // return; // // Collection inputs = ComponentUtils.formInputs(graph, ownerComposite); // // // for (final ResourceArray input : inputs) { // } // } // return; } return; } }); } } return false; } }