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

Java tutorial

Introduction

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

Source

/*******************************************************************************
 * Copyright (c) 2010, 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.Collection;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.eclipse.elk.core.options.LayoutOptions;
import org.eclipse.elk.core.service.ILayoutConfigurationStore;
import org.eclipse.elk.core.service.data.LayoutOptionData;
import org.eclipse.elk.core.service.data.LayoutOptionData.Target;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.AbstractBorderItemEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramRootEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.LabelEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.NoteEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart;
import org.eclipse.gmf.runtime.notation.NotationFactory;
import org.eclipse.gmf.runtime.notation.StringValueStyle;
import org.eclipse.gmf.runtime.notation.View;

import com.google.common.collect.Maps;

/**
 * A layout configuration that stores layout options in the notation model of GMF diagrams.
 *
 * @author msp
 * @kieler.design proposed by msp
 * @kieler.rating yellow 2013-07-01 review KI-38 by cds, uru
 */
public class GmfLayoutConfigurationStore implements ILayoutConfigurationStore {

    /** Prefix for all layout options. */
    public static final String PREFIX = "layout:";

    /** The graphical edit part used as context for this configuration store. */
    private final IGraphicalEditPart editPart;
    /** The layout manager for which this configurator was created. */
    private final GmfDiagramLayoutManager layoutManager;

    public GmfLayoutConfigurationStore(EditPart theeditPart, GmfDiagramLayoutManager manager) {
        if (theeditPart instanceof CompartmentEditPart) {
            // If the selected object is a compartment, replace it by its parent element
            this.editPart = (IGraphicalEditPart) ((CompartmentEditPart) theeditPart).getParent();
        } else if (theeditPart instanceof IGraphicalEditPart) {
            this.editPart = (IGraphicalEditPart) theeditPart;
        } else if (theeditPart instanceof DiagramRootEditPart) {
            this.editPart = (IGraphicalEditPart) ((DiagramRootEditPart) theeditPart).getContents();
        } else {
            throw new IllegalArgumentException("Not supported: " + theeditPart.toString());
        }
        this.layoutManager = manager;
    }

    /**
     * {@inheritDoc}
     */
    public Object getOptionValue(String optionId) {
        View view = editPart.getNotationView();
        if (view != null) {
            String key = PREFIX + optionId;
            for (Object obj : view.getStyles()) {
                if (obj instanceof StringValueStyle) {
                    StringValueStyle style = (StringValueStyle) obj;
                    if (key.equals(style.getName())) {
                        String result = style.getStringValue();
                        if (result != null) {
                            return result;
                        }
                    }
                }
            }
        }
        Map<String, Object> defaultOptions = getDefaultOptions();
        if (defaultOptions != null) {
            return defaultOptions.get(optionId);
        }
        return null;
    }

    /**
     * Return a map of default options. The base implementation only assigns the option
     * {@link LayoutOptions#COMMENT_BOX} to instances of {@link NoteEditPart}. More defaults can
     * be specified in subclasses.
     */
    protected Map<String, Object> getDefaultOptions() {
        Map<String, Object> result = null;
        if (editPart instanceof NoteEditPart) {
            result = Maps.newHashMapWithExpectedSize(1);
            result.put(LayoutOptions.COMMENT_BOX.getId(), true);
        }
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public void setOptionValue(final String optionId, final String value) {
        View view = editPart.getNotationView();
        if (view != null) {
            String key = PREFIX + optionId;
            if (value == null) {
                removeValue(key, view);
            } else {
                for (Object obj : view.getStyles()) {
                    if (obj instanceof StringValueStyle) {
                        StringValueStyle style = (StringValueStyle) obj;
                        if (key.equals(style.getName())) {
                            style.setStringValue(value);
                            return;
                        }
                    }
                }

                StringValueStyle style = NotationFactory.eINSTANCE.createStringValueStyle();
                style.setName(key);
                style.setStringValue(value);
                view.getStyles().add(style);
            }
        }
    }

    /**
     * Remove an option from the given notation view.
     */
    protected void removeValue(final String key, final View view) {
        Iterator<?> iter = view.getStyles().iterator();
        while (iter.hasNext()) {
            Object obj = iter.next();
            if (obj instanceof StringValueStyle && key.equals(((StringValueStyle) obj).getName())) {
                iter.remove();
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public Collection<String> getAffectedOptions() {
        Set<String> options = new HashSet<String>();
        View view = editPart.getNotationView();
        if (view != null) {
            for (Object obj : view.getStyles()) {
                if (obj instanceof StringValueStyle) {
                    StringValueStyle style = (StringValueStyle) obj;
                    String key = style.getName();
                    if (key != null && key.startsWith(PREFIX)) {
                        options.add(key.substring(PREFIX.length()));
                    }
                }
            }
        }
        Map<String, Object> defaultOptions = getDefaultOptions();
        if (defaultOptions != null) {
            options.addAll(defaultOptions.keySet());
        }
        return options;
    }

    /**
     * {@inheritDoc}
     */
    public EditingDomain getEditingDomain() {
        return editPart.getEditingDomain();
    }

    /**
     * {@inheritDoc}
     */
    public Set<Target> getOptionTargets() {
        if (editPart instanceof AbstractBorderItemEditPart) {
            // This is a border item, i.e. a port 
            return EnumSet.of(LayoutOptionData.Target.PORTS);
        } else if (editPart instanceof ShapeNodeEditPart) {
            // This is a node
            Set<LayoutOptionData.Target> partTarget = EnumSet.of(LayoutOptionData.Target.NODES);
            // Check whether the node is a parent
            if (findContainingEditPart(editPart) != null) {
                partTarget.add(LayoutOptionData.Target.PARENTS);
            }
            return partTarget;
        } else if (editPart instanceof ConnectionEditPart) {
            // This is a connection, i.e. an edge
            return EnumSet.of(LayoutOptionData.Target.EDGES);
        } else if (editPart instanceof LabelEditPart) {
            // This is a label
            return EnumSet.of(LayoutOptionData.Target.LABELS);
        } else if (editPart instanceof DiagramEditPart) {
            // This is a diagram
            return EnumSet.of(LayoutOptionData.Target.PARENTS);
        }
        return EnumSet.noneOf(LayoutOptionData.Target.class);
    }

    /**
     * Finds the edit part that contains layoutable children, if there are any. The returned
     * edit part is either the parent edit part itself or one of its compartments.
     * 
     * @param editPart a node edit part
     * @return the edit part that contains other node edit parts, or {@code null} if there is none
     */
    protected IGraphicalEditPart findContainingEditPart(final IGraphicalEditPart editPart) {
        for (Object child : editPart.getChildren()) {
            if (layoutManager.acceptPart((EditPart) child)) {
                if (child instanceof ShapeNodeEditPart) {
                    return editPart;
                } else if (child instanceof CompartmentEditPart) {
                    for (Object grandChild : ((CompartmentEditPart) child).getChildren()) {
                        if (grandChild instanceof ShapeNodeEditPart
                                && layoutManager.acceptPart((EditPart) grandChild)) {
                            return (IGraphicalEditPart) child;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * {@inheritDoc}
     */
    public ILayoutConfigurationStore getParent() {
        EditPart container = getContainer();
        if (container != null) {
            return new GmfLayoutConfigurationStore(container, layoutManager);
        }
        return null;
    }

    /**
     * Determines the container edit part representing a parent node of the context edit part.
     */
    protected EditPart getContainer() {
        if (editPart instanceof AbstractBorderItemEditPart) {
            // The container is the parent of the port's containing node
            return (IGraphicalEditPart) editPart.getParent().getParent();
        } else if (editPart instanceof ShapeNodeEditPart) {
            // This is a node
            return (IGraphicalEditPart) editPart.getParent();
        } else if (editPart instanceof ConnectionEditPart) {
            EditPart sourcePart = ((ConnectionEditPart) editPart).getSource();
            if (sourcePart instanceof AbstractBorderItemEditPart) {
                // The source element is a port
                return sourcePart.getParent().getParent();
            } else {
                // The source element is a node
                return sourcePart.getParent();
            }
        } else if (editPart instanceof LabelEditPart) {
            // This is a label
            IGraphicalEditPart containerEditPart = (IGraphicalEditPart) editPart.getParent();
            if (containerEditPart instanceof ConnectionEditPart) {
                // We have an edge label, so apply the same container rule as for edges
                EditPart sourcePart = ((ConnectionEditPart) containerEditPart).getSource();
                if (sourcePart instanceof AbstractBorderItemEditPart) {
                    return (IGraphicalEditPart) sourcePart.getParent().getParent();
                } else {
                    return (IGraphicalEditPart) sourcePart.getParent();
                }
            } else if (containerEditPart instanceof AbstractBorderItemEditPart) {
                // We have a port label, so apply the same container rule as for ports
                return (IGraphicalEditPart) containerEditPart.getParent().getParent();
            } else if (containerEditPart instanceof ShapeNodeEditPart) {
                // We have a node label
                return (IGraphicalEditPart) containerEditPart.getParent();
            }
            return containerEditPart;
        }
        return null;
    }

}