org.eclipse.elk.gmf.ElkLayoutProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.elk.gmf.ElkLayoutProvider.java

Source

/*******************************************************************************
 * Copyright (c) 2012, 2015 Kiel University and others.
 * 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:
 *     Kiel University - initial API and implementation
 *******************************************************************************/
package org.eclipse.elk.gmf;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.elk.core.service.DiagramLayoutEngine;
import org.eclipse.gmf.runtime.common.core.service.AbstractProvider;
import org.eclipse.gmf.runtime.common.core.service.IOperation;
import org.eclipse.gmf.runtime.diagram.ui.editparts.AbstractBorderItemEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.render.editparts.AbstractImageEditPart;
import org.eclipse.gmf.runtime.diagram.ui.services.layout.ILayoutNode;
import org.eclipse.gmf.runtime.diagram.ui.services.layout.ILayoutNodeOperation;
import org.eclipse.gmf.runtime.diagram.ui.services.layout.ILayoutNodeProvider;
import org.eclipse.gmf.runtime.notation.Node;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;

/**
 * GMF layout provider that executes ELK layout. This enables the execution of ELK layout
 * using the default "Arrange All" button.
 *
 * @author msp
 * @author chsch
 */
public class ElkLayoutProvider extends AbstractProvider implements ILayoutNodeProvider {

    /**
     * {@inheritDoc}
     */
    public boolean provides(final IOperation operation) {
        return operation instanceof ILayoutNodeOperation;
    }

    /**
     * {@inheritDoc}<br>
     * <br>
     * This method returns <code>true</code> only for {@link IGraphicalEditPart IGraphicalEditParts}
     * whose figures are visible and that contain at least a {@link ShapeNodeEditPart}, which is not
     * an {@link AbstractBorderItemEditPart} or an {@link AbstractImageEditPart}.<br>
     * <br>
     * In short, returns only true if the provided edit part contains children that can be layouted.
     */
    @SuppressWarnings("rawtypes")
    public boolean canLayoutNodes(final List layoutNodes, final boolean shouldOffsetFromBoundingBox,
            final IAdaptable layoutHint) {
        Object o = layoutHint.getAdapter(IGraphicalEditPart.class);

        if (!(o instanceof IGraphicalEditPart)) {
            return false;
        }
        final IGraphicalEditPart parent = (IGraphicalEditPart) o;

        // check the availability of children that can be arranged
        //  computing layout on the element wouldn't make sense otherwise
        if (layoutNodes.isEmpty()) {
            return Iterables.any((List<?>) parent.getChildren(), new Predicate<Object>() {
                public boolean apply(final Object o) {
                    return o instanceof ShapeNodeEditPart && !(o instanceof AbstractBorderItemEditPart)
                            && !(o instanceof AbstractImageEditPart);
                }
            });
        } else {
            return Iterables.any((List<?>) layoutNodes, new Predicate<Object>() {
                public boolean apply(final Object o) {
                    ILayoutNode layoutNode = (ILayoutNode) o;
                    IGraphicalEditPart editPart = findEditPart(parent, layoutNode.getNode());
                    return editPart instanceof ShapeNodeEditPart
                            && !(editPart instanceof AbstractBorderItemEditPart)
                            && !(editPart instanceof AbstractImageEditPart);
                }
            });
        }
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("rawtypes")
    public Runnable layoutLayoutNodes(final List layoutNodes, final boolean offsetFromBoundingBox,
            final IAdaptable layoutHint) {
        // fetch general settings from preferences
        final boolean zoomToFit = Platform.getPreferencesService().getBoolean("org.eclipse.elk.core.ui",
                "org.eclipse.elk.zoomToFit", false, null);
        final boolean progressDialog = Platform.getPreferencesService().getBoolean("org.eclipse.elk.core.ui",
                "org.eclipse.elk.progressDialog", false, null);

        // determine the elements to process
        final Object diagramPart;
        if (layoutNodes.isEmpty()) {
            diagramPart = layoutHint.getAdapter(IGraphicalEditPart.class);
        } else {
            List<IGraphicalEditPart> partList = new ArrayList<IGraphicalEditPart>(layoutNodes.size());
            IGraphicalEditPart parent = (IGraphicalEditPart) layoutHint.getAdapter(IGraphicalEditPart.class);
            if (parent != null) {
                Iterator<?> nodeIter = layoutNodes.iterator();
                while (nodeIter.hasNext()) {
                    ILayoutNode layoutNode = (ILayoutNode) nodeIter.next();
                    IGraphicalEditPart editPart = findEditPart(parent, layoutNode.getNode());
                    if (editPart != null) {
                        partList.add(editPart);
                    }
                }
            }
            diagramPart = partList;
        }

        return new Runnable() {
            public void run() {
                DiagramLayoutEngine.INSTANCE.layout(null, diagramPart, false, progressDialog, false, zoomToFit);
            }
        };
    }

    /**
     * Find an edit part with the given notation node.
     * 
     * @param parent the parent edit part to start the search
     * @param notationNode a notation node
     * @return the corresponding edit part
     */
    @SuppressWarnings("unchecked")
    private static IGraphicalEditPart findEditPart(final IGraphicalEditPart parent, final Node notationNode) {
        LinkedList<IGraphicalEditPart> editPartQueue = new LinkedList<IGraphicalEditPart>();
        editPartQueue.add(parent);
        do {
            IGraphicalEditPart editPart = editPartQueue.removeFirst();
            if (notationNode.equals(editPart.getNotationView())) {
                return editPart;
            }
            editPartQueue.addAll(editPart.getChildren());
        } while (!editPartQueue.isEmpty());
        return null;
    }

}