org.kalypso.ogc.gml.outline.nodes.NodeLegendBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.ogc.gml.outline.nodes.NodeLegendBuilder.java

Source

/*----------------    FILE HEADER KALYPSO ------------------------------------------
 *
 *  This file is part of kalypso.
 *  Copyright (C) 2004 by:
 *
 *  Technical University Hamburg-Harburg (TUHH)
 *  Institute of River and coastal engineering
 *  Denickestrae 22
 *  21073 Hamburg, Germany
 *  http://www.tuhh.de/wb
 *
 *  and
 *
 *  Bjoernsen Consulting Engineers (BCE)
 *  Maria Trost 3
 *  56070 Koblenz, Germany
 *  http://www.bjoernsen.de
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Contact:
 *
 *  E-Mail:
 *  belger@bjoernsen.de
 *  schlienger@bjoernsen.de
 *  v.doemming@tuhh.de
 *
 *  ---------------------------------------------------------------------------*/
package org.kalypso.ogc.gml.outline.nodes;

import java.awt.Insets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Transform;
import org.kalypso.contribs.eclipse.ui.progress.ProgressUtilities;
import org.kalypso.ogc.gml.IKalypsoTheme;
import org.kalypso.ogc.gml.map.themes.KalypsoLegendTheme;
import org.kalypso.ui.internal.i18n.Messages;

/**
 * Builds a legend from a {@link org.kalypso.ogc.gml.outline.nodes.IThemeNode}.
 * 
 * @author Gernot Belger
 */
public class NodeLegendBuilder {
    private static final Insets DEFAULT_INSETS = new Insets(5, 5, 5, 5);

    private static final RGB TRANSPARENT_BG = new RGB(0xfe, 0xff, 0xff);

    private static final int DEFAULT_FONT_SIZE = 10;

    private final Set<String> m_whiteList = new HashSet<>();

    private Point m_fixedSize = new Point(-1, -1);

    private RGB m_background = TRANSPARENT_BG;

    private Insets m_insets = DEFAULT_INSETS;

    private final boolean m_onlyVisible;

    private int m_fontSize = DEFAULT_FONT_SIZE;

    public NodeLegendBuilder(final String[] themeWhiteList, final boolean onlyVisible) {
        if (themeWhiteList != null)
            m_whiteList.addAll(Arrays.asList(themeWhiteList));

        m_onlyVisible = onlyVisible;
    }

    /**
     * Creates a legend image for the given node.<br/>
     * The caller is responsible to dispose the returned image.
     */
    public Image createLegend(final IThemeNode[] nodes, final Device device, final IProgressMonitor monitor) {
        /* All elements in this theme. */
        final LegendElement[] elements = collectElements(nodes);
        if (elements.length == 0)
            return null;

        /* Monitor. */
        final SubMonitor progress = SubMonitor.convert(monitor,
                Messages.getString("org.kalypso.ogc.gml.map.utilities.MapUtilities.0"), elements.length); //$NON-NLS-1$

        GC gc = null;
        Font font = null;
        Color bgColor = null;
        Transform shift = null;
        Image image = null;

        try {
            font = new Font(device, JFaceResources.DIALOG_FONT, m_fontSize, SWT.NORMAL);

            /* Compute the size for the image. */
            final Point computeSize = computeSize(elements, font);

            /* Create the image. */
            // HM: quite complicated to create a transparent image; any other ideas?
            final ImageData id = new ImageData(computeSize.x, computeSize.y, 32,
                    new PaletteData(0xFF, 0xFF00, 0xFF0000));
            id.transparentPixel = 0xfffffe;
            image = new Image(device, id);

            /* Need a graphical context. */
            gc = new GC(image);

            /* Set the background color. */
            bgColor = new Color(device, m_background);
            gc.setBackground(bgColor);
            gc.fillRectangle(image.getBounds());

            /* Set the font. */
            gc.setFont(font);

            /* Change the color. */
            gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_BLACK));

            shift = new Transform(device);
            shift.translate(m_insets.left, m_insets.top);
            gc.setTransform(shift);

            for (final LegendElement legendElement : elements) {
                /* Monitor. */
                progress.subTask(Messages.getString("org.kalypso.ogc.gml.map.utilities.MapUtilities.2", //$NON-NLS-1$
                        legendElement.getText()));

                final Point size = legendElement.getSize(font);

                legendElement.paintLegend(gc);

                shift.translate(0, size.y + LegendElement.GAP);
                gc.setTransform(shift);

                // FIXME: resources not disposed on exception!
                ProgressUtilities.worked(progress, 1);
            }

            return image;
        } catch (final Throwable e) {
            if (image != null)
                image.dispose();

            throw e;
        } finally {
            for (final LegendElement legendElement : elements)
                legendElement.dispose();

            if (bgColor != null)
                bgColor.dispose();

            if (shift != null)
                shift.dispose();

            if (gc != null)
                gc.dispose();
            if (font != null)
                font.dispose();
        }
    }

    /**
     * This function returns true, if the current theme is allowed by the white list. Otherwise it will return false.
     * 
     * @param whiteList
     *          The list of ids of allowed themes.
     * @return True, if the current theme is allowed. False otherwise.
     */
    private boolean checkWhiteList(final IThemeNode node) {
        if (m_whiteList.isEmpty())
            return true;

        final Object element = node.getElement();
        if (!(element instanceof IKalypsoTheme))
            return true;

        final IKalypsoTheme theme = (IKalypsoTheme) element;

        /* Only show themes in the white list. */
        final String id = theme.getId();
        if (StringUtils.isBlank(id))
            return true;

        if (!m_whiteList.contains(id))
            return false;

        return true;
    }

    /**
     * This function collects all elements, contained in the theme.
     * 
     * @param font
     *          The font, to use.
     * @return A list, containing all elements.
     */
    private LegendElement[] collectElements(final IThemeNode[] nodes) {
        /* Memory for the elements. */
        final List<LegendElement> elements = new ArrayList<>();

        for (final IThemeNode node : nodes)
            collect(node, elements, 0);

        return elements.toArray(new LegendElement[elements.size()]);
    }

    /**
     * This function collects all elements in an one level array.
     * 
     * @param contentProvider
     *          The content provider, with which the elements can be retrieved.
     * @param font
     *          The font, to use.
     * @param startElement
     *          The element, where the search begins.
     * @param elements
     *          Every element will be added to this list.
     * @param level
     *          The level of recursion.
     */
    private void collect(final IThemeNode node, final List<LegendElement> elements, final int level) {
        if (m_onlyVisible && !node.isChecked(node))
            return;

        /* Legend themes should not provide itself for a legend. */
        if (node.getElement() instanceof KalypsoLegendTheme)
            return;

        // // FIXME: bad check here
        // if( node instanceof WMSLayerNode )
        // return;

        /* Check, if this theme is allowed. */
        if (!checkWhiteList(node))
            return;

        /* Add tis element */
        elements.add(new LegendElement(level, node));

        /* recurse into compact children */
        final IThemeNode[] children = node.getChildrenCompact();
        for (final IThemeNode childNode : children)
            collect(childNode, elements, level + 1);
    }

    /**
     * This function computes the size for an image with the given elements and the given font.
     * 
     * @param elements
     *          The list of elements.
     */
    private Point computeSize(final LegendElement[] elements, final Font font) {
        final Point size = new Point(0, 0);

        /* Memory for storing the longest width so far temporarily. */
        int maxWidth = 0;

        /* Memory for the highest level. */
        int maxLevel = 0;

        /* Loop for finding the longest width and for summarizing the height. */
        for (final LegendElement legendElement : elements) {
            /* Get the size of the element. */
            final Point elementSize = legendElement.getSize(font);

            maxWidth = Math.max(maxWidth, elementSize.x);
            maxLevel = Math.max(maxLevel, legendElement.getLevel());

            /* Add the height and a small space. */
            size.y += elementSize.y + LegendElement.GAP;
        }

        /* Store the longest width. */
        size.x += maxWidth;

        /* After the last image, there is no need for a gap. */
        size.y -= LegendElement.GAP;

        /* apply insets */
        size.x += m_insets.left + m_insets.right;
        size.y += m_insets.top + m_insets.bottom;

        /* Apply fixed sizes */
        size.x = m_fixedSize.x > 0 ? m_fixedSize.x : size.x;
        size.y = m_fixedSize.y > 0 ? m_fixedSize.y : size.y;

        return size;
    }

    public void setFixedSize(final Point fixedWidth) {
        Assert.isNotNull(fixedWidth);

        m_fixedSize = fixedWidth;
    }

    public void setBackground(final RGB background) {
        if (background == null)
            m_background = TRANSPARENT_BG;
        else
            m_background = background;
    }

    public void setInsets(final Insets insets) {
        if (insets == null)
            m_insets = DEFAULT_INSETS;
        else
            m_insets = insets;
    }

    public void setFontSize(final int fontSize) {
        if (fontSize <= 0)
            m_fontSize = DEFAULT_FONT_SIZE;
        else
            m_fontSize = fontSize;
    }
}