de.jaret.util.ui.timebars.swt.renderer.DefaultHierarchyRenderer.java Source code

Java tutorial

Introduction

Here is the source code for de.jaret.util.ui.timebars.swt.renderer.DefaultHierarchyRenderer.java

Source

/*
 *  File: DefaultHierarchyRenderer.java 
 *  Copyright (c) 2004-2007  Peter Kliem (Peter.Kliem@jaret.de)
 *  A commercial license is available, see http://www.jaret.de.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package de.jaret.util.ui.timebars.swt.renderer;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.printing.Printer;
import org.eclipse.swt.widgets.Display;

import de.jaret.util.ui.ResourceImageDescriptor;
import de.jaret.util.ui.timebars.TimeBarViewerDelegate;
import de.jaret.util.ui.timebars.TimeBarViewerInterface;
import de.jaret.util.ui.timebars.model.StdHierarchicalTimeBarModel;
import de.jaret.util.ui.timebars.model.TimeBarNode;
import de.jaret.util.ui.timebars.model.TimeBarRow;
import de.jaret.util.ui.timebars.swt.TimeBarViewer;

/**
 * Default implementation of a HierarchyRenderer. Can draw +/-/o for nodes or any configured image. Uses label providers
 * (regsiters for row implementing class) for labels and icons (icons replace standard node symbol).
 * 
 * @author Peter Kliem
 * @version $Id: DefaultHierarchyRenderer.java 800 2008-12-27 22:27:33Z kliem $
 */
public class DefaultHierarchyRenderer extends RendererBase implements HierarchyRenderer {
    /** size of the plus/minus signs. */
    protected static final int DEFAULT_SIZE = 12;

    /** insets for painting the +/. symbol. */
    protected static final int SYMBOLINSETS = 3;

    /** defaut level width. */
    protected static final int DEFAULT_LEVEL_WIDTH = 16;

    /** gap between tree and the label/icon provided by a label provider. */
    protected static final int LABELGAP = 4;

    /** actual size of the symbols. */
    protected int _size = DEFAULT_SIZE;

    /** actual value for the signinstes. */
    protected int _signInsets = SYMBOLINSETS;

    /** if true, tree lines will be drawn. */
    protected boolean _drawTreeLines = true;

    /** level width for fixed level width drawing. */
    protected int _levelWidth = DEFAULT_LEVEL_WIDTH;

    /** if true the level indentation is fixed. */
    protected boolean _fixedLevelWidth = false;

    /** true for enabling drawing of icons. */
    protected boolean _drawIcons = false;

    /** true for enabling label drawing. */
    protected boolean _drawLabels = false;

    /** label providers for labels and icons. */
    protected Map<Class<? extends TimeBarRow>, ILabelProvider> _labelProviderMap = new HashMap<Class<? extends TimeBarRow>, ILabelProvider>();

    /** key for image registry. */
    protected static final String PLUS = "plus";
    /** key for image registry. */
    protected static final String MINUS = "minus";
    /** key for image registry. */
    protected static final String LEAF = "leaf";

    /** image registry for holding the images. */
    private ImageRegistry _imageRegistry;

    /** path of the plus image ressource. */
    protected String _plusRscName;
    /** path of the minus image ressource. */
    protected String _minusRscName;
    /** path of the leaf image ressource. */
    protected String _leafRscName;

    /**
     * Create for a printer.
     * 
     * @param printer printer device
     */
    public DefaultHierarchyRenderer(Printer printer) {
        super(printer);
        _size = scaleX(DEFAULT_SIZE);
        _signInsets = scaleX(_signInsets);
        _levelWidth = scaleX(_levelWidth);
    }

    /**
     * Default constructor.
     */
    public DefaultHierarchyRenderer() {
        super(null);
    }

    /**
     * {@inheritDoc}
     */
    public void draw(GC gc, Rectangle drawingArea, TimeBarViewerDelegate tbv, TimeBarRow row, boolean selected,
            boolean expanded, boolean leaf, int level, int depth, boolean printing) {

        int offx;
        if (!_fixedLevelWidth && depth > 0) {
            offx = (drawingArea.width - _size) / (depth + 1);
        } else {
            offx = scaleX(_levelWidth);
        }

        int x = drawingArea.x + offx * level + _size / 2;

        int y = drawingArea.y + (drawingArea.height - _size) / 2;

        if (leaf && !_drawIcons) {
            drawLeafSymbol(gc, _size, x, y);
        } else if (expanded && !leaf) {
            drawExpanded(gc, _size, x, y);
        } else if (!leaf) {
            drawCollapsed(gc, _size, x, y);
        }
        x += _size + LABELGAP;

        ILabelProvider labelProvider = getLabelProvider(row.getClass());

        if (labelProvider != null && (_drawIcons || _drawLabels)) {
            int labelx = x;
            if (_drawIcons) {
                Image img = labelProvider.getImage(row);
                if (img != null) {
                    if (!printing) {
                        gc.drawImage(img, x, y);
                        labelx += img.getBounds().width;
                    } else {
                        gc.drawImage(img, 0, 0, img.getBounds().width, img.getBounds().height, x, y,
                                scaleX(img.getBounds().width), scaleY(img.getBounds().height));
                        labelx += scaleX(img.getBounds().width);
                    }
                }
            }
            if (_drawLabels) {
                String label = labelProvider.getText(row);
                if (label != null) {
                    if (!printing && selected) {
                        Color bg = gc.getBackground();
                        gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE));
                        gc.drawString(label, labelx, y);
                        gc.setBackground(bg);
                    } else {
                        gc.drawString(label, labelx, y);
                    }
                }
            }

        }

        // draw tree connections
        if (_drawTreeLines) {
            TimeBarNode node = (TimeBarNode) row;
            if (printing) {
                gc.setLineWidth(getDefaultLineWidth());
            }
            gc.setLineStyle(SWT.LINE_DOT);
            int midy = drawingArea.y + ((drawingArea.height - _size) / 2) + _size / 2;
            int icoy = drawingArea.y + ((drawingArea.height - _size) / 2) + _size;
            int icox = drawingArea.x + offx * (level) + _size - _size / 2;
            int midx = drawingArea.x + +offx * (level) + _size;
            int beginx = drawingArea.x + offx * (level - 1) + _size;
            // int endx = drawingArea.x + offx * (level + 1) + _size;

            // connection
            gc.drawLine(beginx, midy, icox, midy);

            // uplink
            gc.drawLine(beginx, drawingArea.y, beginx, midy);

            // downlink
            if ((!leaf && expanded)) {
                gc.drawLine(midx, icoy, midx, drawingArea.y + drawingArea.height);
            }

            // level lines
            if (tbv.getModel() instanceof StdHierarchicalTimeBarModel) {
                StdHierarchicalTimeBarModel model = (StdHierarchicalTimeBarModel) tbv.getModel();
                for (int i = 0; i < level; i++) {
                    if (model.moreSiblings(node, i)) {
                        x = drawingArea.x + offx * i + _size;
                        gc.drawLine(x, drawingArea.y, x, drawingArea.y + drawingArea.height);
                    }
                }
            }

            gc.setLineStyle(SWT.LINE_SOLID);
            gc.setLineWidth(1);
        }
    }

    /**
     * Draw the collapsed symbol.
     * 
     * @param gc GC
     * @param size size
     * @param x left x
     * @param y upper y
     */
    protected void drawCollapsed(GC gc, int size, int x, int y) {
        if (_plusRscName != null) {
            ImageRegistry registry = getImageRegistry();
            Image img = registry.get(PLUS);
            if (img != null) {
                gc.drawImage(img, 0, 0, img.getBounds().width, img.getBounds().height, x, y, size, size);
            }
        } else {
            drawPlus(gc, size, x, y);
        }
    }

    /**
     * Draw the expanded symbol.
     * 
     * @param gc GC
     * @param size size
     * @param x left x
     * @param y upper y
     */
    protected void drawExpanded(GC gc, int size, int x, int y) {
        if (_minusRscName != null) {
            ImageRegistry registry = getImageRegistry();
            Image img = registry.get(MINUS);
            if (img != null) {
                gc.drawImage(img, 0, 0, img.getBounds().width, img.getBounds().height, x, y, size, size);
            }
        } else {
            drawMinus(gc, size, x, y);
        }
    }

    /**
     * Draw the leaf symbol.
     * 
     * @param gc GC
     * @param size size
     * @param x left x
     * @param y upper y
     */
    protected void drawLeafSymbol(GC gc, int size, int x, int y) {
        if (_leafRscName != null) {
            ImageRegistry registry = getImageRegistry();
            Image img = registry.get(LEAF);
            if (img != null) {
                gc.drawImage(img, 0, 0, img.getBounds().width, img.getBounds().height, x, y, size, size);
            }
        } else {
            drawLeaf(gc, size, x, y);
        }
    }

    /**
     * Draw the plus sign.
     * 
     * @param gc GC
     * @param size size
     * @param x left x
     * @param y upper y
     */
    protected void drawPlus(GC gc, int size, int x, int y) {
        gc.drawLine(x + _signInsets, y + size / 2, x + size - _signInsets, y + size / 2);
        gc.drawLine(x + size / 2, y + _signInsets, x + size / 2, y + size - _signInsets);
        gc.drawRectangle(x, y, size, size);
    }

    /**
     * Draw the minus sign.
     * 
     * @param gc GC
     * @param size size
     * @param x left x
     * @param y upper y
     */
    protected void drawMinus(GC gc, int size, int x, int y) {
        gc.drawLine(x + _signInsets, y + size / 2, x + size - _signInsets, y + size / 2);
        gc.drawRectangle(x, y, size, size);
    }

    /**
     * Draw the leaf symbol.
     * 
     * @param gc GC
     * @param size size
     * @param x left x
     * @param y upper y
     */
    protected void drawLeaf(GC gc, int size, int x, int y) {
        Color bg = gc.getBackground();
        gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
        gc.fillOval(x + size / 2, y + size / 2, size / 2, size / 2);
        gc.setBackground(bg);
    }

    /**
     * {@inheritDoc}
     */
    public String getToolTipText(TimeBarNode node, Rectangle drawingArea, int x, int y) {
        if (node != null) {
            return node.getRowHeader().getLabel();
        }
        return null;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isInToggleArea(TimeBarViewerInterface tbv, TimeBarNode node, Rectangle drawingArea, int xx,
            int yy) {
        int depth = tbv.getHierarchicalModel().getDepth();
        int offx;
        if (!_fixedLevelWidth && depth > 0) {
            offx = (drawingArea.width - _size) / (depth + 1);
        } else {
            offx = scaleX(_levelWidth);
        }
        int level = node.getLevel();

        int x = drawingArea.x + offx * level + _size / 2;
        int y = drawingArea.y + (drawingArea.height - _size) / 2;

        return x <= xx && xx <= x + _size && y <= yy && yy <= y + _size;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isInHierarchySelectionArea(TimeBarViewer tbv, TimeBarNode node, Rectangle drawingArea, int xx,
            int yy) {
        int depth = tbv.getHierarchicalModel().getDepth();
        int offx;
        if (!_fixedLevelWidth && depth > 0) {
            offx = (drawingArea.width - _size) / (depth + 1);
        } else {
            offx = scaleX(_levelWidth);
        }
        int level = node.getLevel();

        int x = drawingArea.x + offx * level + _size / 2;
        int y = drawingArea.y + (drawingArea.height - _size) / 2;

        x += _size + LABELGAP;

        ILabelProvider labelProvider = getLabelProvider(node.getClass());

        if (labelProvider != null && (_drawIcons || _drawLabels)) {
            Rectangle selRect = new Rectangle(x, y, 0, 0);
            if (_drawIcons) {
                Image img = labelProvider.getImage(node);
                if (img != null) {
                    selRect.width += img.getBounds().width;
                    selRect.height += img.getBounds().height;
                }
            }
            if (_drawLabels) {
                String label = labelProvider.getText(node);
                if (label != null) {
                    selRect.width += drawingArea.width - selRect.x; // selection
                    // to end of
                    // hierarchy
                    // rendering
                    selRect.height = Math.max(selRect.height, 16); // 16 pixel
                    // minimium
                    // height
                }
            }
            return selRect.contains(xx, yy);

        }
        return false;

    }

    /**
     * {@inheritDoc}
     */
    public int getPreferredWidth() {
        return scaleX(_size + LABELGAP);
    }

    /**
     * {@inheritDoc}
     */
    public void dispose() {
        if (_imageRegistry != null) {
            _imageRegistry.dispose();
        }
    }

    /**
     * Retrieve whether level indentation is done with a fixed width or variable.
     * 
     * @return true if the renderer uses a fixed width for the level indentation
     */
    public boolean getFixedLevelWidth() {
        return _fixedLevelWidth;
    }

    /**
     * Set method of level indentation.
     * 
     * @param fixedLevelWidth true for the use of a fixed indent for the levels
     */
    public void setFixedLevelWidth(boolean fixedLevelWidth) {
        _fixedLevelWidth = fixedLevelWidth;
    }

    /**
     * Get the default label provider to use for label texts and icons (TimeBarRow.class).
     * 
     * @return Returns the labelProvider.
     */
    public ILabelProvider getLabelProvider() {
        return getLabelProvider(TimeBarRow.class);
    }

    /**
     * Set the default label provider to use for label texts and icons (TimeBarRow.class).
     * 
     * @param labelProvider The labelProvider to set.
     */
    public void setLabelProvider(ILabelProvider labelProvider) {
        registerLabelProvider(TimeBarRow.class, labelProvider);
    }

    /**
     * Register a label provider for a class.
     * 
     * @param clazz time bar row implementing clas or extendin ginterface
     * @param labelProvider label provider
     */
    public void registerLabelProvider(Class<? extends TimeBarRow> clazz, ILabelProvider labelProvider) {
        _labelProviderMap.put(clazz, labelProvider);
    }

    /**
     * Set the complete label provider map (internal use).
     * 
     * @param map map of the label providers
     */
    protected void setLabelProviderMap(Map<Class<? extends TimeBarRow>, ILabelProvider> map) {
        _labelProviderMap = map;
    }

    /**
     * Retrieve a label provider for a given class. Checks all interfaces and all superclasses.
     * 
     * @param clazz class in question
     * @return label provider or null
     */
    protected ILabelProvider getLabelProvider(Class<? extends TimeBarRow> clazz) {
        ILabelProvider result = null;
        result = _labelProviderMap.get(clazz);
        if (result != null) {
            return result;
        }

        // direct interfaces
        Class<?>[] interfaces = clazz.getInterfaces();
        for (Class<?> c : interfaces) {
            result = _labelProviderMap.get(c);
            if (result != null) {
                return result;
            }
        }

        // superclasses
        Class<?> sc = clazz.getSuperclass();

        while (sc != null) {
            result = _labelProviderMap.get(sc);
            if (result != null) {
                return result;
            }
            // interfaces of the superclass
            Class<?>[] scinterfaces = sc.getInterfaces();
            for (Class<?> c : scinterfaces) {
                result = _labelProviderMap.get(c);
                if (result != null) {
                    return result;
                }
            }
            sc = sc.getSuperclass();
        }

        return result;
    }

    /**
     * Retrieve the width for each level (only applicable if fixed level width is used).
     * 
     * @return Returns the levelWidth.
     */
    public int getLevelWidth() {
        return _levelWidth;
    }

    /**
     * @param levelWidth The levelWidth to set.
     */
    public void setLevelWidth(int levelWidth) {
        _levelWidth = levelWidth;
    }

    /**
     * @return Returns the drawIcons.
     */
    public boolean getDrawIcons() {
        return _drawIcons;
    }

    /**
     * @param drawIcons The drawIcons to set.
     */
    public void setDrawIcons(boolean drawIcons) {
        this._drawIcons = drawIcons;
    }

    /**
     * @return Returns the drawLabels.
     */
    public boolean getDrawLabels() {
        return _drawLabels;
    }

    /**
     * @param drawLabels The drawLabels to set.
     */
    public void setDrawLabels(boolean drawLabels) {
        this._drawLabels = drawLabels;
    }

    /**
     * {@inheritDoc}
     */
    public HierarchyRenderer createPrintRenderer(Printer printer) {
        DefaultHierarchyRenderer r = new DefaultHierarchyRenderer(printer);
        r.setDrawIcons(_drawIcons);
        r.setDrawLabels(_drawLabels);
        r.setFixedLevelWidth(_fixedLevelWidth);
        r.setLevelWidth(_levelWidth);
        r.setLabelProviderMap(_labelProviderMap);
        r.setRscNames(_plusRscName, _minusRscName, _leafRscName);
        return r;
    }

    /**
     * Set the paths for images to use a symbols. If set the will be used instead of the generic +/-/o symbols. Please
     * note that the resources are loaded bay getResourceAsStream whicj can be problematic when using it in a multi
     * class loader environment like eclipse rcp. Use the setImageDescriptors method instead.
     * 
     * @param plusRscPath ressource path for the collapsed symbol
     * @param minusRscPath ressource path for the expanded symbol
     * @param leafRscPath ressource path for the leaf symbol
     */
    public void setRscNames(String plusRscPath, String minusRscPath, String leafRscPath) {
        if (_imageRegistry != null) {
            _imageRegistry.dispose();
            _imageRegistry = null;
        }
        _plusRscName = plusRscPath;
        _minusRscName = minusRscPath;
        _leafRscName = leafRscPath;
    }

    /**
     * Set image descriptors for the symbols.
     * 
     * @param plus image descriptor for the plus sign
     * @param minus image descriptor for the minus sign
     * @param leaf image descriptor for the leaf sign
     */
    public void setImageDescriptors(ImageDescriptor plus, ImageDescriptor minus, ImageDescriptor leaf) {
        if (_imageRegistry != null) {
            _imageRegistry.dispose();
        }
        _imageRegistry = new ImageRegistry();
        _imageRegistry.put(PLUS, plus);
        _imageRegistry.put(MINUS, minus);
        _imageRegistry.put(LEAF, leaf);
        _plusRscName = "plusRscPath";
        _minusRscName = "minusRscPath";
        _leafRscName = "leafRscPath";
    }

    /**
     * Retrieve initialized image registry.
     * 
     * @return initialized registry
     */
    private ImageRegistry getImageRegistry() {
        if (_imageRegistry == null) {
            _imageRegistry = new ImageRegistry();
            ImageDescriptor imgDesc = new ResourceImageDescriptor(_plusRscName, this.getClass());
            _imageRegistry.put(PLUS, imgDesc.createImage());
            imgDesc = new ResourceImageDescriptor(_minusRscName, this.getClass());
            _imageRegistry.put(MINUS, imgDesc.createImage());
            imgDesc = new ResourceImageDescriptor(_leafRscName, this.getClass());
            _imageRegistry.put(LEAF, imgDesc.createImage());
        }
        return _imageRegistry;
    }

    /**
     * Retrieve the squae size of the symbols. Images will be scaled.
     * 
     * @return size
     */
    public int getSize() {
        return _size;
    }

    /**
     * Set the size of the symbols.
     * 
     * @param size size in pixel
     */
    public void setSize(int size) {
        _size = size;
    }

    /**
     * Retrieve whether tree lines shoul dbe drawn.
     * 
     * @return true if the tree lines should be drawn
     */
    public boolean getDrawTreeLines() {
        return _drawTreeLines;
    }

    /**
     * Set whether connecting lines in the tree should be drawn.
     * 
     * @param drawTreeLines true if tree lines should be drawn
     */
    public void setDrawTreeLines(boolean drawTreeLines) {
        _drawTreeLines = drawTreeLines;
    }

}