org.eclipse.bpel.ui.editparts.borders.CollapsableBorder.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.bpel.ui.editparts.borders.CollapsableBorder.java

Source

/*******************************************************************************
 * Copyright (c) 2005 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.bpel.ui.editparts.borders;

import org.eclipse.bpel.ui.BPELUIPlugin;
import org.eclipse.bpel.ui.IBPELUIConstants;
import org.eclipse.core.resources.IMarker;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.ImageFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.graphics.Image;

/**
 * This border knows about collapsability. Specifically, it has icons for expand
 * and collapse, does hit testing for these icons, has an image and label to use
 * when collapsed, and does complete rendering when collapsed to look similar to
 * a leaf border (except with the addition of an expand icon).
 * 
 * It does not do rendering for the expanded state. The rationale is that things
 * should look similar when collapsed (like a leaf node) but may have different
 * appearances when expanded.
 */
public abstract class CollapsableBorder extends GradientBorder {

    // Whether or not we are collapsed.
    private boolean collapsed = false;
    // The location of the collapsed image (+).
    protected Rectangle rectCollapsed;
    // The images for collapsed (+) and expanded (-).
    protected Image collapsedImage, expandedImage;
    // The width and height of the expanded image. Collapsed should be the same.
    protected int expandedWidth, expandedHeight;
    // The label to use when collapsed. Subclasses may also use it when expanded.
    protected Label collapsedNameLabel = null;
    // The image to use when collapsed. Subclasses may also use it when expanded.
    protected Image image;
    // The label containing the image.
    protected ImageFigure imageLabel = null;
    // Our parent figure. Used for relative location calculation.
    protected IFigure parentFigure;
    // The calculated rectangle for the collapsed border. This is null
    // when not collapsed, so subclasses shouldn't assume it's there.
    protected Rectangle collapsedBounds;
    // The calculated location of the top and bottom drawer images as well as
    // the top and bottom drawers themselves.
    protected Point topImageLocation = new Point(), bottomImageLocation = new Point();
    protected Point topDrawerLocation = new Point(), bottomDrawerLocation = new Point();
    // The calculated bounds of the rectangle to draw when collapsed
    protected Rectangle collapsedRectangle;

    public CollapsableBorder(boolean isVertical, int arcWidth, IFigure parentFigure, String labelText,
            Image image) {
        super(isVertical, arcWidth);
        this.parentFigure = parentFigure;

        this.image = image;
        this.imageLabel = new ImageFigure(image);

        this.collapsedImage = BPELUIPlugin.INSTANCE.getImage(IBPELUIConstants.ICON_FIGURE_COLLAPSED);
        this.expandedImage = BPELUIPlugin.INSTANCE.getImage(IBPELUIConstants.ICON_FIGURE_EXPANDED);
        this.expandedHeight = expandedImage.getBounds().height;
        this.expandedWidth = expandedImage.getBounds().width;

        this.collapsedNameLabel = new Label(labelText);
        this.collapsedNameLabel.setFont(JFaceResources.getFontRegistry().get(JFaceResources.DEFAULT_FONT));
    }

    /**
     * Tests whether the given point is inside the collapsed image.
     * The superclass only knows where the collapsed image is located; if subclasses
     * want to do hit testing on the expanded image, they may override but may want
     * to call super if we are collapsed.
     */
    public boolean isPointInCollapseImage(int x, int y) {
        if (!isCollapsed())
            return false;
        Point p = new Point(x, y);
        parentFigure.translateToRelative(p);
        Rectangle rect = rectCollapsed.getCopy();
        rect.expand(new Insets(1, 1, 1, 1));
        return rect.contains(p);
    }

    public boolean isCollapsed() {
        return collapsed;
    }

    public void setCollapsed(boolean showCollapse) {
        this.collapsed = showCollapse;
    }

    /**
     * Throw away computed values that determine the layout
     */
    public void invalidate() {
        // rectCollapsed = null;
        collapsedBounds = null;
    }

    public Label getLabel() {
        return collapsedNameLabel;
    }

    public void setName(String name) {
        collapsedNameLabel.setText(name);
    }

    protected void calculate(IFigure figure) {
        // Calculate the coordinates for collapsed state, even though
        // we may currently be expanded.
        if (collapsedBounds == null) {
            collapsedBounds = figure.getBounds().getCopy();
            this.collapsedRectangle = collapsedBounds.getCopy();

            // Leave room on the left and right for the drawer.
            collapsedRectangle.x += DRAWER_WIDTH;
            collapsedRectangle.width -= DRAWER_WIDTH * 2;

            // area for collapsed button
            rectCollapsed = new Rectangle(collapsedBounds.x + collapsedBounds.width / 2 - expandedWidth / 2,
                    collapsedBounds.y + collapsedBounds.height - expandedHeight, expandedWidth, expandedHeight);
        }
    }

    /**
     * This method first invalidates and recalculates any bounds, and then
     * paints the top and bottom drawers, as well as any markers contained within them.
     */
    @Override
    public final void paint(IFigure figure, Graphics graphics, Insets insets) {
        invalidate();
        calculate(figure);
        doPaint(figure, graphics, insets);
    }

    /**
     * Subclasses should call this paint method unless there is a very good
     * reason for overriding its behaviour. To affect where various things
     * appear, override the calculate() method.
     */
    protected void doPaint(IFigure figure, Graphics graphics, Insets insets) {
        // Remember the clipping rectangle
        Rectangle oldClip = new Rectangle();
        oldClip = graphics.getClip(oldClip);

        IMarker topMarker = getTopMarker();
        IMarker bottomMarker = getBottomMarker();
        if (topMarker != null || bottomMarker != null) {
            ColorRegistry registry = BPELUIPlugin.INSTANCE.getColorRegistry();
            graphics.setForegroundColor(registry.get(IBPELUIConstants.COLOR_ACTIVITY_BORDER));
            Rectangle clippingRect;
            if (bottomMarker == null) {
                clippingRect = new Rectangle(topDrawerLocation.x, topDrawerLocation.y, DRAWER_WIDTH,
                        DRAWER_HALF_HEIGHT + 1);
            } else if (topMarker == null) {
                clippingRect = new Rectangle(bottomDrawerLocation.x, bottomDrawerLocation.y, DRAWER_WIDTH,
                        DRAWER_HALF_HEIGHT + 1);
            } else {
                clippingRect = new Rectangle(topDrawerLocation.x, topDrawerLocation.y, DRAWER_WIDTH,
                        DRAWER_HEIGHT + 1);
            }
            graphics.setClip(clippingRect);
            // -1 due to GEF
            graphics.drawRoundRectangle(new Rectangle(topDrawerLocation.x + DRAWER_INSET, topDrawerLocation.y,
                    DRAWER_WIDTH * 2, DRAWER_HEIGHT - 1), IBPELUIConstants.ARC_WIDTH, IBPELUIConstants.ARC_WIDTH);
            graphics.setClip(oldClip);
            if (bottomMarker == null || topMarker == null) {
                graphics.drawLine(topDrawerLocation.x + DRAWER_INSET, topDrawerLocation.y + DRAWER_HALF_HEIGHT,
                        topDrawerLocation.x + DRAWER_WIDTH, topDrawerLocation.y + DRAWER_HALF_HEIGHT);
            }

        }

        // Draw the actual breakpoints
        Image topImage = getTopImage();
        if (topImage != null) {
            graphics.drawImage(topImage, topImageLocation);
        }
        Image bottomImage = getBottomImage();
        if (bottomImage != null) {
            graphics.drawImage(bottomImage, bottomImageLocation);
        }
    }

    /**
     * We only know about the gradient rectangle when we are collapsed.
     * TODO: Do we need a gradient rectangle when collapsed?
     */
    @Override
    protected Rectangle getGradientRect() {
        return new Rectangle(0, 0, 0, 0);
    }

    @Override
    public boolean isPointInTopDrawer(int x, int y) {
        if (getTopMarker() == null)
            return false;
        Point p = new Point(x, y);
        Image image = getTopImage();
        org.eclipse.swt.graphics.Rectangle imageSize = image.getBounds();
        Rectangle imageBounds = new Rectangle(topImageLocation.x, topImageLocation.y, imageSize.width,
                imageSize.height);
        return imageBounds.contains(p);
    }

    @Override
    public boolean isPointInBottomDrawer(int x, int y) {
        if (getBottomMarker() == null)
            return false;
        Point p = new Point(x, y);
        Image image = getBottomImage();
        org.eclipse.swt.graphics.Rectangle imageSize = image.getBounds();
        Rectangle imageBounds = new Rectangle(bottomImageLocation.x, bottomImageLocation.y, imageSize.width,
                imageSize.height);
        return imageBounds.contains(p);
    }

    /**
     * Calculate the insets when in the collapsed state. In expanded state, we don't
     * know how to answer. Insets don't matter in the collapsed state because there
     * are no children.
     */
    @Override
    public Insets getInsets(IFigure figure) {
        return new Insets(0, 0, 0, 0);
    }
}