diff --git a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/.ratings b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/.ratings index 740f31903cb27afedc4f8d504a10873e578dff8c..ace0e86f887263a665e62d39b97c5964de78e8ed 100644 --- a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/.ratings +++ b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/.ratings @@ -1,3 +1,5 @@ AutoLayoutMenu.java ef3b897cc2fd99cf9ce201f03cffea036555e3ac GREEN +DiagramTapeMeasure.java 72454e6fe5225dab11d3d691baad93aab7a171c0 YELLOW IAutoLayouter.java de1b11d9e202c7e23352ad85684dbf8a3fd17c7d GREEN -KielerAutoLayouter.java fae8692ca0131a6d14cff768aba446b7b35512d6 GREEN +IAutoLayouterTapeMeasure.java df186e0ba505e0ecda211b1df76cf12f3245b47e YELLOW +KielerAutoLayouter.java 2fe3bf63213245d6900c42be172347f863f2f198 YELLOW diff --git a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/DiagramTapeMeasure.java b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/DiagramTapeMeasure.java new file mode 100644 index 0000000000000000000000000000000000000000..72454e6fe5225dab11d3d691baad93aab7a171c0 --- /dev/null +++ b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/DiagramTapeMeasure.java @@ -0,0 +1,145 @@ +/*-------------------------------------------------------------------------+ +| Copyright 2018 fortiss GmbH | +| | +| Licensed under the Apache License, Version 2.0 (the "License"); | +| you may not use this file except in compliance with the License. | +| You may obtain a copy of the License at | +| | +| http://www.apache.org/licenses/LICENSE-2.0 | +| | +| Unless required by applicable law or agreed to in writing, software | +| distributed under the License is distributed on an "AS IS" BASIS, | +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | +| See the License for the specific language governing permissions and | +| limitations under the License. | ++--------------------------------------------------------------------------*/ +package org.fortiss.tooling.base.ui.layout.auto; + +import static java.lang.Math.max; +import static org.fortiss.tooling.base.layout.DefaultLayoutConstants.DEFAULT_CONNECTOR_SIZE; +import static org.fortiss.tooling.base.layout.DefaultLayoutConstants.DEFAULT_GRID_SIZE; +import static org.fortiss.tooling.base.layout.DefaultLayoutConstants.DEFAULT_SHAPE_MINIMUM_WIDTH; +import static org.fortiss.tooling.base.utils.LayoutDataUtils.getNodeSize; +import static org.fortiss.tooling.kernel.ui.util.KernelUIUtils.getName; +import static org.fortiss.tooling.kernel.utils.EcoreUtils.pickInstanceOf; + +import org.eclipse.draw2d.IFigure; +import org.eclipse.draw2d.Label; +import org.eclipse.gef.EditPartViewer; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.fortiss.tooling.base.model.base.EntryConnectorBase; +import org.fortiss.tooling.base.model.element.IConnection; +import org.fortiss.tooling.base.model.element.IConnector; +import org.fortiss.tooling.base.model.element.IHierarchicElement; +import org.fortiss.tooling.base.model.element.IModelElement; +import org.fortiss.tooling.base.model.layout.Dimension; +import org.fortiss.tooling.base.model.layout.ILayoutedModelElement; +import org.fortiss.tooling.base.ui.editor.DiagramEditorBase; +import org.fortiss.tooling.base.ui.editpart.ConnectionEditPartBase; +import org.fortiss.tooling.base.ui.editpart.ElementEditPartBase; + +/** + * {@link IAutoLayouterTapeMeasure} specialization to for automatic layout of models to be displayed + * in {@link DiagramEditorBase}-based editors. + * + * @author barner + */ +public class DiagramTapeMeasure implements IAutoLayouterTapeMeasure { + + /** {@link EditPartViewer} used to display the underlying diagram. */ + private EditPartViewer diagramEpv; + + /** Underlying GC. */ + private GC gc; + + /** Constructor. */ + public DiagramTapeMeasure(EditPartViewer epv, GC gc) { + this.diagramEpv = epv; + this.gc = gc; + } + + /** Returns the {@code Font} used by the given {@code element} (may be {@code null}). */ + private Font getFont(IModelElement element) { + if(diagramEpv == null) { + return null; + } + Object ep = diagramEpv.getEditPartRegistry().get(element); + if(ep instanceof ElementEditPartBase) { + Label label = ((ElementEditPartBase<?>)ep).createLabelFigure(); + if(label != null) { + return label.getFont(); + } + } else if(ep instanceof ConnectionEditPartBase) { + IFigure figure = ((ConnectionEditPartBase<?>)ep).getFigure(); + if(figure != null) { + return figure.getFont(); + } + } + + return null; + } + + /** Returns the text extend of the given {@code element}'s label (may be {@code null}). */ + private Point getTextExtent(IModelElement element) { + if(gc == null) { + return null; + } + + String name = getName(element); + if(name == null) { + return null; + } + + gc.setFont(getFont(element)); + Point rval = gc.textExtent(name); + + return rval; + } + + /** {@inheritDoc} */ + @Override + public int getElementWidth(IHierarchicElement element) { + Dimension dimension = getNodeSize((ILayoutedModelElement)element); + + int width = max(DEFAULT_SHAPE_MINIMUM_WIDTH, dimension.getWidth()); + Point textExtend = getTextExtent(element); + if(textExtend != null) { + width = max(width, textExtend.x + 6 * DEFAULT_GRID_SIZE); + } + + return width; + } + + /** {@inheritDoc} */ + @Override + public int getElementHeight(IHierarchicElement element) { + Dimension dimension = getNodeSize((ILayoutedModelElement)element); + int numElemConnectors = element.getConnectors().size(); + int numElemInputConnectors = + pickInstanceOf(EntryConnectorBase.class, element.getConnectors()).size(); + int numConnectors = max(numElemInputConnectors, numElemConnectors - numElemInputConnectors); + + return max((1 + 2 * numConnectors) * DEFAULT_CONNECTOR_SIZE, dimension.getHeight()); + } + + /** {@inheritDoc} */ + @Override + public int getConnectorWidth(IConnector connector) { + return 2 * DEFAULT_CONNECTOR_SIZE; + } + + /** {@inheritDoc} */ + @Override + public int getConnectorHeight(IConnector connector) { + return 2 * DEFAULT_CONNECTOR_SIZE; + } + + /** {@inheritDoc} */ + @Override + public int getConnectionWidth(IConnection connection) { + Point textExtend = getTextExtent(connection); + return textExtend != null ? textExtend.x : 0; + } +} diff --git a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/IAutoLayouterTapeMeasure.java b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/IAutoLayouterTapeMeasure.java new file mode 100644 index 0000000000000000000000000000000000000000..df186e0ba505e0ecda211b1df76cf12f3245b47e --- /dev/null +++ b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/IAutoLayouterTapeMeasure.java @@ -0,0 +1,43 @@ +/*-------------------------------------------------------------------------+ +| Copyright 2018 fortiss GmbH | +| | +| Licensed under the Apache License, Version 2.0 (the "License"); | +| you may not use this file except in compliance with the License. | +| You may obtain a copy of the License at | +| | +| http://www.apache.org/licenses/LICENSE-2.0 | +| | +| Unless required by applicable law or agreed to in writing, software | +| distributed under the License is distributed on an "AS IS" BASIS, | +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | +| See the License for the specific language governing permissions and | +| limitations under the License. | ++--------------------------------------------------------------------------*/ +package org.fortiss.tooling.base.ui.layout.auto; + +import org.fortiss.tooling.base.model.element.IConnection; +import org.fortiss.tooling.base.model.element.IConnector; +import org.fortiss.tooling.base.model.element.IHierarchicElement; + +/** + * Interface used by {@link IAutoLayouter} to estimate dimensions requirements of elements (for the + * respective editor for which the automatic layout is performed). + * + * @author barner + */ +public interface IAutoLayouterTapeMeasure { + /** Estimates the width requirements of the given element. */ + public int getElementWidth(IHierarchicElement element); + + /** Estimates the height requirements of the given element. */ + public int getElementHeight(IHierarchicElement element); + + /** Estimates the width requirements of the given connector. */ + public int getConnectorWidth(IConnector connector); + + /** Estimates the height requirements of the given connector. */ + public int getConnectorHeight(IConnector connector); + + /** Estimates the width requirements of the given connection. */ + public int getConnectionWidth(IConnection connection); +} diff --git a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/KielerAutoLayouter.java b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/KielerAutoLayouter.java index fae8692ca0131a6d14cff768aba446b7b35512d6..2fe3bf63213245d6900c42be172347f863f2f198 100644 --- a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/KielerAutoLayouter.java +++ b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/layout/auto/KielerAutoLayouter.java @@ -20,22 +20,22 @@ import static de.cau.cs.kieler.kiml.options.LayoutOptions.DIRECTION; import static de.cau.cs.kieler.kiml.options.LayoutOptions.INTERACTIVE; import static de.cau.cs.kieler.kiml.options.LayoutOptions.PORT_SIDE; import static de.cau.cs.kieler.kiml.util.KimlUtil.createInitializedEdge; +import static de.cau.cs.kieler.kiml.util.KimlUtil.createInitializedLabel; import static de.cau.cs.kieler.kiml.util.KimlUtil.createInitializedNode; import static de.cau.cs.kieler.kiml.util.KimlUtil.createInitializedPort; import static de.cau.cs.kieler.klay.layered.properties.InteractiveReferencePoint.TOP_LEFT; import static de.cau.cs.kieler.klay.layered.properties.Properties.FEEDBACK_EDGES; import static de.cau.cs.kieler.klay.layered.properties.Properties.INTERACTIVE_REFERENCE_POINT; -import static java.lang.Math.max; +import static java.lang.Thread.sleep; import static org.fortiss.tooling.base.layout.DefaultLayoutConstants.DEFAULT_CONNECTOR_SIZE; import static org.fortiss.tooling.base.layout.DefaultLayoutConstants.DEFAULT_GRID_SIZE; -import static org.fortiss.tooling.base.layout.DefaultLayoutConstants.DEFAULT_SHAPE_MINIMUM_WIDTH; import static org.fortiss.tooling.base.ui.annotation.view.AnnotationViewPartBase.isUpdateEnabled; import static org.fortiss.tooling.base.ui.annotation.view.AnnotationViewPartBase.setUpdateEnabled; import static org.fortiss.tooling.base.ui.utils.LayoutDataUIUtils.addBendPointToConnection; -import static org.fortiss.tooling.base.utils.LayoutDataUtils.getNodeSize; import static org.fortiss.tooling.base.utils.LayoutDataUtils.setNodeLayoutData; import static org.fortiss.tooling.base.utils.LayoutDataUtils.setNodePosition; import static org.fortiss.tooling.base.utils.LayoutDataUtils.setStickyConnectorLayoutData; +import static org.fortiss.tooling.kernel.utils.LoggingUtils.error; import java.util.Map.Entry; @@ -43,23 +43,30 @@ import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.BasicEMap; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.EMap; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.gef.EditPartViewer; +import org.eclipse.swt.graphics.GC; import org.fortiss.tooling.base.model.base.EntryConnectorBase; import org.fortiss.tooling.base.model.base.ExitConnectorBase; import org.fortiss.tooling.base.model.element.IConnection; import org.fortiss.tooling.base.model.element.IConnector; import org.fortiss.tooling.base.model.element.IHierarchicElement; -import org.fortiss.tooling.base.model.layout.Dimension; import org.fortiss.tooling.base.model.layout.EOrientation; import org.fortiss.tooling.base.model.layout.ILayoutData; import org.fortiss.tooling.base.model.layout.ILayoutedModelElement; import org.fortiss.tooling.base.model.layout.Points; import org.fortiss.tooling.base.model.layout.impl.PointsImpl; +import org.fortiss.tooling.base.ui.ToolingBaseUIActivator; +import org.fortiss.tooling.base.ui.editor.DiagramEditorBase; import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; import org.fortiss.tooling.kernel.service.IPersistencyService; +import org.fortiss.tooling.kernel.ui.extension.IModelEditor; +import org.fortiss.tooling.kernel.ui.service.IModelEditorBindingService; import de.cau.cs.kieler.core.alg.BasicProgressMonitor; import de.cau.cs.kieler.core.alg.IKielerProgressMonitor; import de.cau.cs.kieler.core.kgraph.KEdge; +import de.cau.cs.kieler.core.kgraph.KLabel; import de.cau.cs.kieler.core.kgraph.KNode; import de.cau.cs.kieler.core.kgraph.KPort; import de.cau.cs.kieler.kiml.AbstractLayoutProvider; @@ -278,6 +285,28 @@ public class KielerAutoLayouter implements IAutoLayouter { } } + /** + * Opens the given {@link IHierarchicElement} in an editor. Returns the editor in case it is a + * {@link DiagramEditorBase}-based, {@code null} otherwise. + */ + private EditPartViewer getDiagramEditPartViewer(IHierarchicElement element) { + IModelEditorBindingService es = IModelEditorBindingService.getInstance(); + es.openInEditor(element); + while(!es.isOpen(element)) { + try { + sleep(100); + } catch(Exception e) { + error(ToolingBaseUIActivator.getDefault(), "Error opening editor.", e); + break; + } + } + + IModelEditor<EObject> editor = es.getActiveEditor(); + return editor instanceof DiagramEditorBase ? ((DiagramEditorBase<?>)editor).getViewer() + : null; + + } + /** * Creates a KIELER {@link KNode} graph with the same structure as the given * {@link IHierarchicElement}. @@ -298,21 +327,22 @@ public class KielerAutoLayouter implements IAutoLayouter { connectionsToKEdges = new BasicEMap<IConnection, KEdge>(); undirectedConnectorsToKPorts = new BasicEMap<IConnector, KPort>(); + EditPartViewer viewer = getDiagramEditPartViewer(hierarchicElement); + GC gc = viewer != null ? new GC(viewer.getControl()) : null; + IAutoLayouterTapeMeasure tapeMeasure = new DiagramTapeMeasure(viewer, gc); + // Create nodes for(IHierarchicElement currentChild : hierarchicElement.getContainedElements()) { if(!(currentChild instanceof ILayoutedModelElement)) { continue; } - KNode kNode = createInitializedNode(); - KShapeLayout kNodeLayout = kNode.getData(KShapeLayout.class); EList<IConnector> inputConnectors = new BasicEList<IConnector>(); EList<IConnector> outputConnectors = new BasicEList<IConnector>(); EList<IConnector> undirectedConnectors = new BasicEList<IConnector>(); - for(IConnector connector : currentChild.getConnectors()) { if(connector instanceof EntryConnectorBase) { inputConnectors.add(connector); @@ -324,16 +354,14 @@ public class KielerAutoLayouter implements IAutoLayouter { } } - // Adjust size of node to number of connectors - Dimension dimension = getNodeSize((ILayoutedModelElement)currentChild); - int numConnectors = max(inputConnectors.size(), outputConnectors.size()); - kNodeLayout.setHeight(max((1 + 2 * numConnectors) * DEFAULT_CONNECTOR_SIZE, - truncateSnap2Grid(dimension.getHeight(), true))); - kNodeLayout.setWidth(max(DEFAULT_SHAPE_MINIMUM_WIDTH, - truncateSnap2Grid(dimension.getWidth(), true))); - + // Adjust size of node to number of connectors and label size + int width = tapeMeasure.getElementWidth(currentChild); + kNodeLayout.setWidth(truncateSnap2Grid(width, true)); + int height = tapeMeasure.getElementHeight(currentChild); + kNodeLayout.setHeight(truncateSnap2Grid(height, true)); kNode.setParent(rootNode); modelElementsToKNodes.put(currentChild, kNode); + for(IConnector connector : outputConnectors) { KPort k = createKPortFromIConnector(connector, kNode, outboundConnectorsToKPorts); if(undirectedConnectors.contains(connector)) { @@ -352,8 +380,8 @@ public class KielerAutoLayouter implements IAutoLayouter { for(IConnector connector : hierarchicElement.getConnectors()) { KNode kNodeVirtual = createInitializedNode(); KShapeLayout kNodeVirtualLayout = kNodeVirtual.getData(KShapeLayout.class); - kNodeVirtualLayout.setHeight(DEFAULT_CONNECTOR_SIZE); - kNodeVirtualLayout.setWidth(2 * DEFAULT_CONNECTOR_SIZE); + kNodeVirtualLayout.setWidth(tapeMeasure.getConnectorWidth(connector)); + kNodeVirtualLayout.setHeight(tapeMeasure.getConnectorHeight(connector)); kNodeVirtual.setParent(rootNode); KPort kPort = createInitializedPort(); @@ -374,6 +402,12 @@ public class KielerAutoLayouter implements IAutoLayouter { kEdge.setSource(kSourcePort.getNode()); kEdge.setSourcePort(kSourcePort); + + KLabel kLabel = createInitializedLabel(kEdge); + KShapeLayout kLabelLayout = kLabel.getData(KShapeLayout.class); + int width = tapeMeasure.getConnectionWidth(connection); + kLabelLayout.setWidth(truncateSnap2Grid(width, true)); + kSourcePort.getEdges().add(kEdge); KPort kTargetPort = inboundConnectorsToKPorts.get(connection.getTarget()); if(kTargetPort == null) { @@ -388,6 +422,10 @@ public class KielerAutoLayouter implements IAutoLayouter { connectionsToKEdges.put(connection, kEdge); } } + + if(gc != null) { + gc.dispose(); + } return rootNode; }