org.kalypso.contribs.eclipse.jobs.BufferPaintJob.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.contribs.eclipse.jobs.BufferPaintJob.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.contribs.eclipse.jobs;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.kalypso.contribs.eclipse.core.runtime.StatusUtilities;
import org.kalypso.contribs.eclipse.internal.EclipseRCPContributionsPlugin;
import org.kalypso.contribs.eclipse.ui.progress.ProgressUtilities;

/**
 * A {@link Job} that paints a IPaintable onto a {@link BufferedImage}.<br>
 * Its own paint method, paints the current state of the {@link BufferedImage}.<br>
 * 
 * @author Gernot Belger
 */
public class BufferPaintJob extends Job {
    /**
     * Call-back interface for the thing that really gets painted by this buffer-painter.
     */
    public static interface IPaintable {
        Point getSize();

        void paint(Graphics2D g, IProgressMonitor monitor) throws CoreException;
    }

    private final IPaintable m_paintable;

    private BufferedImage m_image = null;

    private final ImageCache m_imageCache;

    public BufferPaintJob(final IPaintable paintable, final ImageCache imageCache) {
        super(StringUtils.EMPTY);

        m_paintable = paintable;
        m_imageCache = imageCache;

        if (m_paintable != null)
            setName(m_paintable.toString());
    }

    /**
     * Needed because we use {@link java.lang.ref.SoftReference}'s.
     */
    @Override
    protected void finalize() throws Throwable {
        dispose();
    }

    /**
     * Cancels the job and releases the buffered image.
     */
    public void dispose() {
        cancel();

        synchronized (this) {
            if (m_image != null) {
                m_imageCache.release(m_image);
                m_image = null;
            }
        }
    }

    public IPaintable getPaintable() {
        return m_paintable;
    }

    /**
     * Returns the current state of the buffered image.
     * 
     * @return The buffered image; <code>null</code>, if the job has not yet started.
     */
    public synchronized BufferedImage getImage() {
        return m_image;
    }

    @Override
    public IStatus run(final IProgressMonitor monitor) {
        // System.out.println("Paint job running");

        if (m_paintable == null) {
            // System.out.println("BufferPaintJob: paintable was null");
            return Status.OK_STATUS;
        }

        final SubMonitor progress = SubMonitor.convert(monitor, "Painting buffer", 100); //$NON-NLS-1$

        Graphics2D gr = null;
        try {
            progress.subTask("Initializing buffer-image");

            final Point size = m_paintable.getSize();
            if (size.x > 0 && size.y > 0) {
                gr = createGraphics(size);
                // if image is null, workbench is probably shutting down,
                // just return without comment
                if (gr == null) {
                    // System.out.println("BufferPaintJob: image was null");
                    return Status.OK_STATUS;
                }

                ProgressUtilities.worked(progress, 10);

                m_paintable.paint(gr, progress.newChild(90, SubMonitor.SUPPRESS_NONE));
            }
        } catch (final CoreException ce) {
            final IStatus status = ce.getStatus();
            if (status.matches(IStatus.CANCEL))
                return status;

            EclipseRCPContributionsPlugin.getDefault().getLog().log(ce.getStatus());

            // REMARK: We translate every error to an warning, to avoid the error-dlg popup.
            // Especially for buffered layers this is needed, as we can have multiple thread running at once, producing lots
            // of error output
            if (status.matches(IStatus.ERROR))
                return StatusUtilities.cloneStatus(status, IStatus.WARNING);

            return ce.getStatus();
        } catch (final OperationCanceledException e) {
            return Status.CANCEL_STATUS;
        } catch (final Throwable t) {
            return new Status(IStatus.ERROR, EclipseRCPContributionsPlugin.ID, "Failed to paint buffer image", t); //$NON-NLS-1$
        } finally {
            if (gr != null)
                gr.dispose();

            monitor.done();
        }

        return Status.OK_STATUS;
    }

    private synchronized Graphics2D createGraphics(final Point size) {
        /* Only recreate image, if width/height does not fit any more */
        if (m_image != null && m_image.getWidth() != size.x && m_image.getHeight() != size.y) {
            m_imageCache.release(m_image);
            m_image = null;
        }

        if (m_image == null)
            ceateImage(size);

        final Graphics2D gr = m_image.createGraphics();
        if (gr == null)
            return null;

        configureGraphics(gr);

        return gr;
    }

    private void ceateImage(final Point size) {
        m_image = m_imageCache.akquire(size);
    }

    /**
     * Configures the graphics-context before actual painting is started (i.e. {@link IPaintable#paint(Graphics2D, IProgressMonitor)} is called).<br>
     * Default behaviour is to set activate anti-aliasing (normal and text).<br>
     * Overwrite to change.
     */
    private void configureGraphics(final Graphics2D gr) {
        gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        gr.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    }
}