fr.lip6.move.coloane.core.ui.editpart.AttributeEditPart.java Source code

Java tutorial

Introduction

Here is the source code for fr.lip6.move.coloane.core.ui.editpart.AttributeEditPart.java

Source

/**
 * Copyright (c) 2006-2010 MoVe - Laboratoire d'Informatique de Paris 6 (LIP6).
 * 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:
 *   Jean-Baptiste VORON (LIP6) - Project Head / Initial contributor
 *   Clment DMOULINS (LIP6) - Project Manager
 *
 * Official contacts:
 *   coloane@lip6.fr
 *   http://coloane.lip6.fr
 */
package fr.lip6.move.coloane.core.ui.editpart;

import fr.lip6.move.coloane.core.model.AbstractPropertyChange;
import fr.lip6.move.coloane.core.model.AttributeModel;
import fr.lip6.move.coloane.core.model.interfaces.ISpecialState;
import fr.lip6.move.coloane.interfaces.model.IArc;
import fr.lip6.move.coloane.interfaces.model.IAttribute;
import fr.lip6.move.coloane.interfaces.model.IGraph;
import fr.lip6.move.coloane.interfaces.model.ILocationInfo;
import fr.lip6.move.coloane.interfaces.model.INode;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.logging.Logger;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartListener;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.editpolicies.SelectionEditPolicy;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.graphics.Font;

/**
 * This EditPart is in charge of managing attributes.<br>
 * All attributes are attached to the Graph EditPart because they have to be displayed in the graph drawing space.
 *
 * @author Jean-Baptiste Voron
 */
public class AttributeEditPart extends AbstractGraphicalEditPart
        implements ISelectionEditPartListener, PropertyChangeListener {
    /** Core Logger */
    private static final Logger LOGGER = Logger.getLogger("fr.lip6.move.coloane.core"); //$NON-NLS-1$

    // Default spacing between attributes and their parent when displayed
    private static final int GAP = 20;
    // Default extra space needed to handle correctly some italic fonts (under MacOS)
    private static final int EXTRA_SPACE = 2;

    private boolean select = false;
    private boolean elementSelect = false;
    private boolean highlight = false;
    private boolean special = false;

    private Font font;

    /**
     * Listening state modification from the attribute's parent.
     */
    private EditPartListener editPartListener = new EditPartListener.Stub() {

        // When the state of current attribute's parent has changed...
        @Override
        public void selectedStateChanged(EditPart part) {
            switch (part.getSelected()) {
            case EditPart.SELECTED:
            case EditPart.SELECTED_PRIMARY:
                elementSelect = true;
                break;
            case EditPart.SELECTED_NONE:
                elementSelect = false;
                break;
            case ISelectionEditPartListener.HIGHLIGHT:
                highlight = true;
                break;
            case ISelectionEditPartListener.HIGHLIGHT_NONE:
                highlight = false;
                break;
            default:
                break;
            }
            // Need to refresh visuals (perhaps some graphical attributes has been changed) !
            refreshVisuals();
        }
    };

    /**
     * Creates the associated figure.
     * For the attributes, the figure is, in fact, a <b>label</b>.
     * @return IFigure the associated figure.
     */
    @Override
    protected final IFigure createFigure() {
        Label figure = new Label();
        figure.setOpaque(true); // Opacity (!)

        // Fetch the associated attribute model object
        IAttribute attribute = (IAttribute) getModel();

        // Compute the visibility of the attribute
        figure.setVisible(computeVisibility(attribute));

        // Compute the location of the label (try to avoid overlaps)
        Point attributeLocation = computeLocation(attribute);

        // Store graphical location and set the figure position into the editor
        attribute.getGraphicInfo().setLocation(attributeLocation);
        figure.setLocation(attributeLocation);
        return figure;
    }

    /**
     * If the attribute value matches its default value, the attribute should not be displayed (hidden).
     * But, the formalism can specify exceptions! In that case, the defaultValueDrawable status has to be checked too.
     * @param attribute the attribute to query
     * @return <code>true</code> if the attribute has to be displayed; <code>false</code> otherwise
     */
    private boolean computeVisibility(IAttribute attribute) {
        // Check the current value and the default value
        if (attribute.getAttributeFormalism().getDefaultValue().equals(attribute.getValue())) {
            if (!attribute.getAttributeFormalism().isDefaultValueDrawable()) {
                return false;
            }
        }
        return true;
    }

    /**
     * Compute the location of an attribute considering its parent type (arc, node or graph...).<br>
     * If the attribute has already some location information, they have to be used instead !
     * @param attribute the attribute to query
     * @return the better location (try to avoid overlaps between attributes)
     */
    private Point computeLocation(IAttribute attribute) {

        Point attributePosition;

        // If the attribute parent is a node, the attribute if moved
        if (attribute.getReference() instanceof INode) {

            // If the attribute has no location information yet
            if ((attribute.getGraphicInfo().getLocation().x <= 0)
                    && (attribute.getGraphicInfo().getLocation().y <= 0)) {
                Point refLocation = ((INode) attribute.getReference()).getGraphicInfo().getLocation();

                // Check if a deltaLocation is specified
                Point deltaLocation = attribute.getAttributeFormalism().getDeltaLocation();
                if (!deltaLocation.equals(Point.SINGLETON.setLocation(0, 0))) {
                    // Compute a new location given the default GAP according to the node position
                    attributePosition = new Point(refLocation.x + deltaLocation.x, refLocation.y + deltaLocation.y);

                    // If not, just use the GAP constant to locate attributes near their parent object
                } else {
                    attributePosition = new Point(refLocation.x + GAP, refLocation.y - GAP);
                }

                // If the attribute has some location information
            } else {
                // Just put the attribute where it must be
                attributePosition = new Point(attribute.getGraphicInfo().getLocation().x,
                        attribute.getGraphicInfo().getLocation().y);
            }

            // It the attribute parent is an arc
        } else if (attribute.getReference() instanceof IArc) {
            // If the attribute has no location information yet
            if ((attribute.getGraphicInfo().getLocation().x <= 0)
                    && (attribute.getGraphicInfo().getLocation().y <= 0)) {
                attributePosition = ((IArc) attribute.getReference()).getGraphicInfo().findMiddlePoint();

                //If the attribute has already some location information
            } else {
                attributePosition = new Point(attribute.getGraphicInfo().getLocation().x,
                        attribute.getGraphicInfo().getLocation().y);
            }

            // If the attribute parent is the graph itself
        } else if (attribute.getReference() instanceof IGraph) {
            attributePosition = new Point(attribute.getGraphicInfo().getLocation().x,
                    attribute.getGraphicInfo().getLocation().y);

            // In any other cases, the attribute position is set to (0,0)
            // It means that the attribute is attached to something strange... (TODO: Is the situation really possible ?)
        } else {
            attributePosition = new Point(0, 0);
        }

        return attributePosition;
    }

    /**
     * Refresh view side according model information.
     */
    @Override
    protected final void refreshVisuals() {
        IAttribute attribut = (IAttribute) getModel();
        Label attributeFigure = (Label) getFigure();

        // Update graphical representation
        getFigure().setForegroundColor(attribut.getGraphicInfo().getForeground());
        getFigure().setBackgroundColor(attribut.getGraphicInfo().getBackground());

        // Select state (attribute only or parent ?)
        // TODO: Should be set in a property page
        if (this.select || this.elementSelect) {
            getFigure().setForegroundColor(ColorConstants.blue);
        }
        // Highlight state (mouseover event)
        // TODO: Should be set in a property page
        if (this.highlight) {
            getFigure().setBackgroundColor(ColorConstants.lightGray);
        }
        // Special state (coming from problem view)
        if (special) {
            getFigure().setForegroundColor(ColorConstants.red);
        }

        // Font update
        if (this.font == null || this.font.isDisposed()) {
            this.font = JFaceResources.getDefaultFont();
            if (attribut.getAttributeFormalism().isBold()) {
                this.font = JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT);
            }
            if (attribut.getAttributeFormalism().isItalic()) {
                this.font = JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT);
            }
            attributeFigure.setFont(this.font);
        }

        // The label is filled with the attribute value !
        attributeFigure.setText(attribut.getValue());

        // Graphical space (i.e. bounds) for the attribute is set here.
        Rectangle bounds = new Rectangle(attribut.getGraphicInfo().getLocation(), new Dimension(
                attributeFigure.getTextBounds().width + EXTRA_SPACE, attributeFigure.getTextBounds().height));
        if (getParent() != null) {
            ((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), bounds);
        }
    }

    /**
     * Some policies (behaviors) applying to the object
     */
    @Override
    protected final void createEditPolicies() {
        // Allow the edition of the attribute value directly on the editor (only for standard attributes)
        installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE, new AttributeDirectEditPolicy());

        // All rules about select state
        installEditPolicy(EditPolicy.SELECTION_FEEDBACK_ROLE, new SelectionEditPolicy() {
            @Override
            protected void hideSelection() {
                select = false;
                refreshVisuals();
            }

            @Override
            protected void showSelection() {
                select = true;
                setSelected(EditPart.SELECTED);
                refreshVisuals();
            }
        });
    }

    /** {@inheritDoc} */
    @Override
    public final boolean isSelectable() {
        return true;
    }

    /** {@inheritDoc} */
    @Override
    public final void activate() {
        if (!isActive()) {
            super.activate();
            ((AbstractPropertyChange) getModel()).addPropertyChangeListener(this);
            if (getParent() instanceof GraphEditPart) {
                GraphEditPart graphEditPart = (GraphEditPart) getParent();
                EditPart parent = graphEditPart.getParentAttributeEditPart(this);
                if (parent != null) {
                    addEditPartListener(((ISelectionEditPartListener) parent).getSelectionEditPartListener());
                    parent.addEditPartListener(editPartListener);
                }
            }
        }
    }

    /** {@inheritDoc} */
    @Override
    public final void deactivate() {
        if (isActive()) {
            super.deactivate();
            ((AbstractPropertyChange) getModel()).removePropertyChangeListener(this);
            if (getParent() instanceof GraphEditPart) {
                GraphEditPart graphEditPart = (GraphEditPart) getParent();
                EditPart parent = graphEditPart.getParentAttributeEditPart(this);
                if (parent != null) {
                    setSelected(EditPart.SELECTED_NONE);
                    removeEditPartListener(((ISelectionEditPartListener) parent).getSelectionEditPartListener());
                    parent.removeEditPartListener(editPartListener);
                }
            }
        }
    }

    /**
     * Draw a rectangle useful to edit the attribute value
     * @see #createEditPolicies()
     */
    private void performDirectEdit() {
        Label label = (Label) getFigure();
        IAttribute model = (IAttribute) getModel();
        new AttributeEditManager(this, model, new AttributeCellEditorLocator(label)).show();
    }

    /** {@inheritDoc} */
    @Override
    public final void performRequest(Request request) {
        if (request.getType() == RequestConstants.REQ_DIRECT_EDIT) {
            // Editing is allowed only for standard attributes
            if (getModel() instanceof AttributeModel) {
                performDirectEdit();
            } else {
                LOGGER.finer("This attribute cannot be edited since it is computed from several attributes value"); //$NON-NLS-1$
            }
        }
    }

    /** {@inheritDoc} */
    @Override
    public final void propertyChange(PropertyChangeEvent event) {
        String prop = event.getPropertyName();

        // When the value of the attribute is modified somewhere
        if (IAttribute.VALUE_PROP.equals(prop)) {
            IAttribute attribute = (IAttribute) getModel();

            // Compute the visibility of the attribute
            getFigure().setVisible(computeVisibility(attribute));
            // Compute new location
            // attribute.getGraphicInfo().setLocation(computeLocation(attribute));

            refreshVisuals();

            // When the attribute is moved
        } else if (ILocationInfo.LOCATION_PROP.equals(prop)) {

            // Deal with the special case where the location of the attribute has been reseted (-1,-1).
            // In that case a new location has to be computed again.
            Point newLocation = (Point) event.getNewValue();
            if (newLocation.equals(Point.SINGLETON.setLocation(-1, -1))) {
                IAttribute attribute = (IAttribute) getModel();
                attribute.getGraphicInfo().setLocation(computeLocation(attribute));
            }
            // In all cases, the view must be refreshed
            refreshVisuals();
        } else if (ISpecialState.SPECIAL_STATE_CHANGE.equals(prop)) {
            special = (Boolean) event.getNewValue();
            refreshVisuals();
        }
    }

    /** {@inheritDoc} */
    @Override
    public final EditPartListener getSelectionEditPartListener() {
        return editPartListener;
    }
}