/******************************************************************************* * 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.diagram.handler; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ContributionItem; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IContributionItem; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.common.CommentMetadata; import org.simantics.db.common.request.IndexRoot; import org.simantics.db.common.request.WriteRequest; import org.simantics.db.exception.DatabaseException; import org.simantics.diagram.content.ConnectionUtil; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingResources; import org.simantics.scl.commands.Command; import org.simantics.scl.commands.Commands; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.ui.contribution.DynamicMenuContribution; import org.simantics.utils.ui.AdaptionUtils; import org.simantics.utils.ui.ExceptionUtils; /** * @author Tuukka Lehtonen */ public class ConnectionRoutingMenuContribution extends DynamicMenuContribution { private static final IContributionItem[] NONE = {}; @Override protected IContributionItem[] getContributionItems(ReadGraph graph, Object[] selection) throws DatabaseException { ArrayList result = new ArrayList(4); result.addAll(getConnectionRoutingItems(graph, selection)); result.addAll(getAttachedConnectionRoutingItems(graph, selection)); return result.toArray(NONE); } public static Collection getConnectionRoutingItems(ReadGraph graph, Object[] selection) throws DatabaseException { Layer0 l0 = Layer0.getInstance(graph); DiagramResource dr = DiagramResource.getInstance(graph); final Collection routings = graph.getObjects(dr.Routing, l0.SuperrelationOf); if (routings.size() == 0) return Collections.emptyList(); final List connections = new ArrayList(); for (Object s : selection) { Resource connection = AdaptionUtils.adaptToSingle(s, Resource.class); if (connection == null) return Collections.emptyList(); if (!graph.isInstanceOf(connection, dr.Connection)) return Collections.emptyList(); // Route graph connection routing is not selected per-connection, but per-terminal. if (graph.isInstanceOf(connection, dr.RouteGraphConnection)) return Collections.emptyList(); connections.add(connection); } if (connections.isEmpty()) return Collections.emptyList(); // See if all connections have a common routing. Resource currentRoute = null; for (Resource connection : connections) { Statement currentRouting = graph.getPossibleStatement(connection, dr.Routing); if (currentRouting != null) { Resource route = currentRouting.getPredicate(); if (currentRoute == null) currentRoute = route; else if (!currentRoute.equals(route)) { currentRoute = null; break; } } } final List actions = new ArrayList(); for (Resource routing : routings) { String text = graph.adapt(routing, String.class); SetRoutingAction action = new SetRoutingAction(graph.getSession(), connections, routing, text); if (routing.equals(currentRoute)) action.setChecked(true); actions.add(action); } sort(actions); return Collections.singleton( new ContributionItem() { @Override public void fill(Menu menu, int index) { MenuItem openWith = new MenuItem(menu, SWT.CASCADE, index); openWith.setText("Connection Routing"); Menu subMenu = new Menu(menu); openWith.setMenu(subMenu); for (SetRoutingAction a : actions) { MenuItem item = new MenuItem(subMenu, SWT.CHECK); item.setText(a.getText()); item.addSelectionListener(a); item.setSelection(a.isChecked()); } } } ); } public static Collection getAttachedConnectionRoutingItems(ReadGraph graph, Object[] selection) throws DatabaseException { Layer0 l0 = Layer0.getInstance(graph); DiagramResource dr = DiagramResource.getInstance(graph); StructuralResource2 sr = StructuralResource2.getInstance(graph); ModelingResources MOD = ModelingResources.getInstance(graph); // HACK Resource ReferenceProvider = graph.getPossibleResource("http://www.apros.fi/Apros-6.1/ReferenceProvider"); // Just continuing to do stupid things as above ;) Resource connectionType = graph.getPossibleResource("http://www.simantics.org/Kcleco-5.0/FlowConnection"); final Collection routings = graph.getObjects(dr.Routing, l0.SuperrelationOf); if (routings.size() == 0) return Collections.emptyList(); final List connections = new ArrayList(); // For route graph connections final List connectors = new ArrayList(); boolean directRoutings = false; boolean straightRoutings = false; ArrayList elements = new ArrayList(); for (Object s : selection) { Resource element = AdaptionUtils.adaptToSingle(s, Resource.class); if (element == null) return Collections.emptyList(); if (!graph.isInstanceOf(element, dr.Element) || graph.isInstanceOf(element, dr.Connection)) return Collections.emptyList(); elements.add(element); for(Statement stat : graph.getStatements(element, sr.IsConnectedTo)) { Resource diagramRelation = stat.getPredicate(); Resource connectionRelation = graph.getPossibleObject(diagramRelation, MOD.DiagramConnectionRelationToConnectionRelation); if(connectionRelation == null) continue; // FIXME HACK if(ReferenceProvider != null && !graph.isInstanceOf(connectionRelation, ReferenceProvider)) continue; Resource connector = stat.getObject(); Resource connection = ConnectionUtil.tryGetConnection(graph, connector); if (connection != null) { if (graph.isInstanceOf(connection, dr.RouteGraphConnection)) { if (connectionType != null && graph.isInstanceOf(connection, connectionType)) continue; connectors.add(connector); boolean direct = Boolean.TRUE.equals( graph.getPossibleRelatedValue2(connector, dr.Connector_straight, Bindings.BOOLEAN) ); directRoutings |= direct; straightRoutings |= !direct; } else { connections.add(connection); } } } } if (connectors.isEmpty() && connections.isEmpty()) return Collections.emptyList(); // See if all connections have a common routing. Resource currentRoute = null; for (Resource connection : connections) { Statement currentRouting = graph.getPossibleStatement(connection, dr.Routing); if (currentRouting != null) { Resource route = currentRouting.getPredicate(); if (currentRoute == null) currentRoute = route; else if (!currentRoute.equals(route)) { currentRoute = null; break; } } } final List actions = new ArrayList(); if (!connections.isEmpty()) { // Handle old style connections and their routing for (Resource routing : routings) { String text = graph.adapt(routing, String.class); SetRoutingAction action = new SetRoutingAction(graph.getSession(), connections, routing, text); if (routing.equals(currentRoute)) { action.setChecked(true); } actions.add(action); } } if (!connectors.isEmpty()) { // Handle route graph connections SelectionListenerAction direct = new SetAttachedRouteGraphRoutingAction(graph.getSession(), elements, true, "Direct"); SelectionListenerAction straight = new SetAttachedRouteGraphRoutingAction(graph.getSession(), elements, false, "Straight-angled"); direct.setChecked(directRoutings); straight.setChecked(straightRoutings); actions.add(direct); actions.add(straight); } sort(actions); return Collections.singleton( new ContributionItem() { @Override public void fill(Menu menu, int index) { MenuItem openWith = new MenuItem(menu, SWT.CASCADE, index); openWith.setText("Attached Connection Routing"); Menu subMenu = new Menu(menu); openWith.setMenu(subMenu); for (SelectionListenerAction a : actions) { MenuItem item = new MenuItem(subMenu, SWT.CHECK); item.setText(a.getText()); item.addSelectionListener(a); item.setSelection(a.isChecked()); } } } ); } private static void sort(List actions) { // Sort the open with actions in string order. Collections.sort(actions, new Comparator() { @Override public int compare(IAction o1, IAction o2) { return o1.getText().compareToIgnoreCase(o2.getText()); } }); } static abstract class SelectionListenerAction extends Action implements SelectionListener { public SelectionListenerAction(String text) { super(text); } } static class SetRoutingAction extends SelectionListenerAction { Session session; Collection connections; Resource routingTag; public SetRoutingAction(Session session, Collection connections, Resource routingTag, String text) { super(text); this.session = session; this.connections = connections; this.routingTag = routingTag; } @Override public void run() { session.asyncRequest(new WriteRequest() { @Override public void perform(WriteGraph graph) throws DatabaseException { DiagramResource dr = DiagramResource.getInstance(graph); for (Resource connection : connections) { graph.deny(connection, dr.Routing); graph.claim(connection, routingTag, connection); } } }, parameter -> { if (parameter != null) ExceptionUtils.logError(parameter); }); } @Override public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } @Override public void widgetSelected(SelectionEvent e) { run(); } } static class SetAttachedRouteGraphRoutingAction extends SelectionListenerAction { Session session; Collection elements; boolean straight; public SetAttachedRouteGraphRoutingAction(Session session, Collection elements, boolean straight, String text) { super(text); this.session = session; this.elements = elements; this.straight = straight; } @Override public void run() { session.asyncRequest(new WriteRequest() { @Override public void perform(WriteGraph graph) throws DatabaseException { Command command = Commands.get(graph, "Simantics/Diagram/setStraightConnectionLines"); for(Resource element : elements) command.execute(graph, graph.syncRequest(new IndexRoot(element)), element, straight); CommentMetadata cm = graph.getMetadata(CommentMetadata.class); graph.addMetadata(cm.add("Set routing for an element.")); } }, parameter -> { if (parameter != null) ExceptionUtils.logError(parameter); }); } @Override public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } @Override public void widgetSelected(SelectionEvent e) { run(); } } }