org.eclipse.rap.ui.interactiondesign.layout.ElementBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.rap.ui.interactiondesign.layout.ElementBuilder.java

Source

/*******************************************************************************
* Copyright (c) 2009 EclipseSource 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:
*   EclipseSource - initial API and implementation
*******************************************************************************/
package org.eclipse.rap.ui.interactiondesign.layout;

import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.rap.ui.interactiondesign.layout.model.Layout;
import org.eclipse.rap.ui.interactiondesign.layout.model.LayoutSet;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.plugin.AbstractUIPlugin;

/**
 * A <code>ElementBuilder</code> represents the super class for all custom
 * builders. With a custom builder you can construct complex objects e.g. a
 * header, which needs nine or less images and additional information about
 * placing logos or other images.
 * <p>
 * To fit as much as possible patterns of web components we introduce this
 * <code>ElementBuilder</code>. This concept use the builder design pattern.
 * So, an instantiation can look like: <code>ElementBuilder builder = new
 * HeaderBuilder(param, param)</code>. The benefit of this technique is, that
 * you can work against a defined api and you can change the implementation
 * easily.
 * </p>
 * <p>
 * Every builder needs a <code>{@link LayoutSet}</code>, which can be
 * contributed to the <code>org.eclipse.rap.ui.layouts</code>
 * extension point.
 * </p>
 * The point is, every builder should regard, that a <code>LayoutSet</code>
 * can define more or less images depending on the contribution in the
 * extension. E.g. a header can hold nine images, but i also can hold just
 * three. So, the builder have to look that the component is build correctly.
 * </p>
 *
 * @since 1.2
 *
 * @see LayoutSet
 */
public abstract class ElementBuilder implements IAdaptable {

    private Composite parent;
    private Layout layout;
    private LayoutSet layoutSet;

    /**
     * This constructor stores the parent composite and instantiate a
     * <code>{@link LayoutSet}</code> for this instance. The <code>LayoutSet
     * </code> can be used to create images, fonts, colors or postion data.
     * This depends on what is defined for a specific builder.
     * <p>
     * Subclasses have to call this constructor because it register the object
     * in the <code>{@link LayoutRegistry}</code>
     * </p>
     *
     * @param parent the parent <code>{@link Composite}</code> for the component
     * to build.
     * @param layoutSetId the id of the <code>LayoutSet</code>, which belongs to
     * this instance.
     *
     * @see LayoutSet
     * @see LayoutRegistry#registerBuilder(ElementBuilder)
     * @see Composite
     */
    public ElementBuilder(final Composite parent, final String layoutSetId) {
        this.parent = parent;
        LayoutRegistry registry = LayoutRegistry.getInstance();
        String savedLayoutId = registry.getSavedLayoutId();
        if (!savedLayoutId.equals(IPreferenceStore.STRING_DEFAULT_DEFAULT)) {
            registry.setActiveLayout(savedLayoutId, false);
        }
        layout = registry.getActiveLayout();
        if (layout != null) {
            layoutSet = layout.getLayoutSet(layoutSetId);
            registry.registerBuilder(this);
        } else {
            String msg = "no layout registered with default "
                    + "id (LayoutRegistry.DEFAULT_LAYOUT_ID) or no layout activated " + "over branding extension.";
            throw new IllegalArgumentException(msg);
        }
    }

    /**
     * Clients can call this method to add non standard components to the builder
     * e.g. a logo placed on a label to show in a header.
     * <p>
     * So, subclasses can implement or ignore this method depending on their
     * needs.
     * </p>
     * <p>
     * Clients have to call this method before calling
     * <code>{@link #build()}</code>.
     * </p>
     *
     * @param control an instance of a <code>Cotrol</code> e.g. a <code>Composite
     * </code> containing a image.
     * @param layoutData can be any position information for the control.
     * Usually it's a instance of <code>FormData</code>.
     *
     * @see FormData
     * @see GridData
     */
    public abstract void addControl(final Control control, final Object layoutData);

    /**
     * This method do the same as <code>{@link #addControl(Control, Object)}
     * </code>. The only difference is, that the position information can be
     * loaded by the <code>{@link LayoutSet#getPosition(String)}</code>
     * method.
     *
     * @param control an instance of a <code>Control</code> e.g. a <code>Composite
     * </code> containing an image.
     * @param positionId the unique id of a position data holding by the <code>
     * LayoutSet</code> for this object.
     *
     * @see LayoutSet#getPosition(String)
     * @see LayoutSet#addPosition(String, FormData)
     */
    public abstract void addControl(final Control control, final String positionId);

    /**
     * Subclasses can implement this method and process it. E.g. if a client
     * want to add a logo for a header directly and not over the
     * <code>{@link #addControl(Control, Object)}</code> method in a
     * <code>Composite</code>.
     *
     * @param image an instance of a <code>Image</code> to add.
     * @param layoutData can be any position information for the <code>Image</code>.
     * Usually it's an instance of <code>FormData</code>.
     *
     * @see FormData
     * @see GridData
     */
    public abstract void addImage(final Image image, final Object layoutData);

    /**
     * This method do the same as <code>{@link #addImage(Image, Object)}</code>.
     * The only difference is, that the position information can be
     * loaded by the <code>{@link LayoutSet#getPosition(String)}</code>
     * method.
     *
     * @param image an instance of an <code>Image</code> to add.
     * @param positionId the unique id of a position data holding by the <code>
     * LayoutSet</code> for this object.
     *
     * @see LayoutSet#getPosition(String)
     * @see LayoutSet#addPosition(String, FormData)
     */
    public abstract void addImage(final Image image, final String positionId);

    /**
     * This is the most important method in a builder. If a client call this, the
     * builder have to build the needed component e.g. a header or footer
     * regarding the defined <code>LayoutSet</code>.
     */
    public abstract void build();

    /**
     * Subclasses can use this method to create an image by means of it's path in
     * the <code>LayoutSet</code>.
     * <p>Note that images can only be created for <code>LayoutSets</code> which
     * were contributed via extensions.</p>
     *
     * @param path the path for the image to create.
     * @return the created image.
     *
     * @see LayoutSet#addImagePath(String, String)
     * @see LayoutSet#getImagePath(String)
     */
    protected Image createImage(final String path) {
        Image result = null;
        if (path != null) {
            String id = LayoutRegistry.getPluginIdForLayoutSet(layoutSet.getId());
            if (id != null) {
                ImageDescriptor descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(id, path);
                result = descriptor.createImage();
            }
        }
        return result;
    }

    /**
     * Subclasses should dispose all created or rather added <code>Control</code>s
     * and <code>Image</code>s in this method.
     */
    public abstract void dispose();

    /**
     * Returns a <code>Color</code> object by it's id defined in the
     * <code>LayoutSet</code>
     *
     * @param colorId the id of the color.
     *
     * @return the created <code>Color</code> object.
     *
     * @see LayoutSet#addColor(String, Color)
     * @see LayoutSet#getColor(String)
     */
    public Color getColor(final String colorId) {
        return layoutSet.getColor(colorId);
    }

    /**
     * Returns a <code>FormData</code> object by it's id defines in the
     * <code>LayoutSet</code>
     * 
     * @param positionKey the key for the FormData
     * 
     * @return the created <code>FormData</code> object.
     * 
     * @see LayoutSet#addPosition(String, FormData)
     * @see LayoutSet#getPosition(String)
     * 
     * @since 1.3
     */
    public FormData getPosition(final String positionKey) {
        return layoutSet.getPosition(positionKey);
    }

    /**
     * Subclasses should implement this method to return the component,
     * which is created during the <code>{@link #build()}</code> call.
     *
     * @return the <code>{@link Control}</code> created in the
     * <code>{@link #build()}</code> method.
     */
    public abstract Control getControl();

    /**
     * Returns a <code>Font</code> object by it's id defined in the
     * <code>LayoutSet</code>
     *
     * @param fontID the id of the font.
     *
     * @return the created font object.
     *
     * @see LayoutSet#addFont(String, Font)
     * @see LayoutSet#getFont(String)
     */
    public Font getFont(final String fontID) {
        return layoutSet.getFont(fontID);
    }

    /**
     * Return the image by its id in the <code>LayoutSet</code>. This method
     * just extract the image path and call <code>{@link #createImage(String)}
     * </code>.
     *
     * @param imageId the id of the image defined in the <code>LayoutSet</code>.
     *
     * @return the created image.
     *
     * @see LayoutSet#getImagePath(String)
     * @see LayoutSet#addImagePath(String, String)
     */
    public Image getImage(final String imageId) {
        Image result = null;
        String imagePath = layoutSet.getImagePath(imageId);
        if (imagePath != null) {
            result = createImage(imagePath);
        }
        return result;
    }

    /**
     * This returns the <code>LayoutSet</code> for this builder. The layoutset
     * contains all images, fonts, formdatas and colors, which are relevant for
     * the whole builder layout.
     * @return the <code>LayoutSet</code> object
     */
    protected LayoutSet getLayoutSet() {
        return layoutSet;
    }

    /**
     * Returns the parent, which was set in <code>
     * {@link #ElementBuilder(Composite, String)}</code>.
     *
     * @return the parent <code>Composite</code>.
     */
    protected Composite getParent() {
        return parent;
    }

    /**
     * Should return the size from the representative component of the builder.
     *
     * @return the size as a Point. <code>Point.x</code> means the width and
     * <code>Point.y</code> means the height of the component.
     */
    public abstract Point getSize();

    /**
     * Subclasses may override this method to return more than one control. This
     * is necessary sometimes to get more control over the builder.
     */
    public Object getAdapter(final Class adapter) {
        return null;
    }

}