Layer Factory


The layer container delegates the creation of layers to a layer factory, which needs to implement the ILayerFactory interface. A default factory is included and will be sufficient for most applications. However, there are reasons why an application might choose to provide its own factory: to have a single point in the application where layers get configured, to use subclasses of the built-in layers or to use custom layers.

The following steps need to be taken to implement and use a custom layer factory that creates a custom layer.
  1. Implement the ILayerFactory interface or subclass DefaultLayerFactory
  2. Implement the IComponentFactory interface or subclass DefaultComponentFactory
  3. Create a Gantt chart model that adds one or more custom layers
  4. Create your Gantt chart using the custom component factory
The following code examples add a custom layer to a Gantt chart. The purpose of this custom layer is to add a watermark to the Gantt chart. Such a watermark might be used to indicate to the users that they are using a demo / trial version of a software product.

/**
* Copyright 2006, 2007
* Dirk Lemmermann Software & Consulting
* http://www.dlsc.com
*/
package com.dlsc.flexgantt.manual;

import com.dlsc.flexgantt.model.gantt.ILayer;
import com.dlsc.flexgantt.swing.layer.AbstractCustomLayer;
import com.dlsc.flexgantt.swing.layer.DefaultLayerFactory;
import com.dlsc.flexgantt.swing.layer.LayerContainer;

/**
* A custom layer factory that gets used instead of the default layer factory so
* that a custom layer gets created when it finds a model layer named 'watermark'.
*/
public class WatermarkLayerFactory extends DefaultLayerFactory {

    /*
     * The singleton instance.
     */
    private static WatermarkLayerFactory instance;

    /**
     * Private constructor as part of singleton pattern implementation.
     */
    private WatermarkLayerFactory() {
    }

    public static synchronized WatermarkLayerFactory getInstance() {
        if (instance == null) {
            instance = new WatermarkLayerFactory();
        }
        return instance;
    }

    /**
     * The default implementation of the factory method for creating custom
     * layers does nothing. In order to add custom layers it is necessary to
     * create a custom factory and then return custom layer implementations
     * whenever a model layer's 'custom layer' flag indicates that the layer
     * requires it.
     */
    @Override
    public AbstractCustomLayer createCustomLayer(LayerContainer lc, ILayer layer) {
        if (layer.getObjectName().equals("watermark")) {
            return new WatermarkLayer(lc);
        } else {
            return super.createCustomLayer(lc, layer);
        }
    }
}



The following code is the implementation of the custom watermark layer.

/**
* Copyright 2006, 2007
* Dirk Lemmermann Software & Consulting
* http://www.dlsc.com
*/
package com.dlsc.flexgantt.manual;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import java.net.URL;

import javax.swing.ImageIcon;

import com.dlsc.flexgantt.swing.layer.AbstractCustomLayer;
import com.dlsc.flexgantt.swing.layer.LayerContainer;

/**
* The watermark layer is a custom layer implementation. It will be created and
* added to a layer container if one of the model layers is a custom layer and
* the layer's name equals 'watermark'.
*
* @author Dirk Lemmermann
*/
public class WatermarkLayer extends AbstractCustomLayer {
    
    /*
     * Stores the texture paint that will be drawn as tiles in the background
     * of the layer (container).
     */
    private TexturePaint texturePaint;
    
    /**
     * Constructs a new watermark layer.
     *
     * @param lc the layer container to which the layer will belong
     */
    public WatermarkLayer(LayerContainer lc) {
        super("Watermark", lc);
        
        //
        // Load an image and create a texture paint
        // object with it. This paint object can then
        // be used in the paintLayer() method to fill
        // the background with the watermark image.
        //
        URL url = getClass().getResource("watermark.png");
        ImageIcon icon = new ImageIcon(url);
        Image texture = icon.getImage();
        BufferedImage buffer = new BufferedImage(texture
                .getWidth(layerContainer), texture
                .getHeight(layerContainer), BufferedImage.TYPE_INT_RGB);
        Graphics2D bg = buffer.createGraphics();
        bg.drawImage(texture, 0, 0, layerContainer);
        texturePaint = new TexturePaint(buffer, new Rectangle(0, 0, buffer
                .getWidth(), buffer.getHeight()));

    }
    
    protected void paintLayer(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        Rectangle clip = g.getClipBounds();
        g2d.setPaint(texturePaint);
        g2d.fillRect(clip.x, clip.y, clip.width, clip.height);
    }
}



A Gantt chart model that wants the watermark layer to be shown then needs to add a custom model layer with the name 'watermark'.

/**
* Copyright 2006, 2007
* Dirk Lemmermann Software & Consulting
* http://www.dlsc.com
*/
package com.dlsc.flexgantt.manual;

import com.dlsc.flexgantt.model.gantt.DefaultGanttChartModel;
import com.dlsc.flexgantt.model.gantt.DefaultGanttChartNode;
import com.dlsc.flexgantt.model.gantt.Layer;

/**
* A specialization of the default Gantt chart model. It adds a custom layer
* named 'watermark'. This model needs to get used in combination with a layer
* factory that knows how to create a watermark layer.
*
* @author Dirk Lemmermann
*/
@SuppressWarnings("serial")
public class WatermarkGanttChartModel extends DefaultGanttChartModel {

    /**
     * Constructs a new Gantt chart model.
     */
    @SuppressWarnings("unchecked")
    public WatermarkGanttChartModel() {
        super(new DefaultGanttChartNode());
        Layer layer = new Layer("watermark");
        layer.setCustomLayer(true);
        addLayer(layer);
    }
}



The last thing needed is a component factory that creates a layer container with the watermark layer factory. This company factory then needs to be passed to the constructor of the Gantt chart.

/**
* Copyright 2006, 2007
* Dirk Lemmermann Software & Consulting
* http://www.dlsc.com
*/
package com.dlsc.flexgantt.manual;

import com.dlsc.flexgantt.model.gantt.IGanttChartModel;
import com.dlsc.flexgantt.swing.AbstractGanttChart;
import com.dlsc.flexgantt.swing.DefaultComponentFactory;
import com.dlsc.flexgantt.swing.layer.LayerContainer;
import com.dlsc.flexgantt.swing.treetable.TreeTable;

public class WatermarkComponentFactory extends DefaultComponentFactory {

    /**
     * Creates a layer container that uses the watermark layer factory.
     */
    @Override
    public LayerContainer createLayerContainer(AbstractGanttChart gc,
            TreeTable table, IGanttChartModel model) {
        return new LayerContainer(gc, model, table, WatermarkLayerFactory
                .getInstance());
    }
}