org.codecover.eclipse.utils.ImageProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.codecover.eclipse.utils.ImageProvider.java

Source

/******************************************************************************
 * Copyright (c) 2007 Stefan Franke, Robert Hanussek, Benjamin Keil,          *
 *                    Steffen Kie, Johannes Langauf,                         *
 *                    Christoph Marian Mller, Igor Podolskiy,                *
 *                    Tilmann Scheller, Michael Starzmann, Markus Wittlinger  *
 * 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                                  *
 ******************************************************************************/

package org.codecover.eclipse.utils;

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

import org.codecover.metrics.coverage.CoverageResult;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;

/**
 * Provides the images for the instrumentation decorator used in the package
 * explorer and the coverage indicator bars used in the Coverage view.
 * 
 * @author Markus Wittlinger, Robert Hanussek
 * @version 1.0 ($Id$)
 */
public class ImageProvider {

    private static ImageDescriptor decorator;

    private static Map<CoverageResult, Image> covIndCache = new HashMap<CoverageResult, Image>();

    private static final Object covIndCacheLock = new Object();

    private static final int covIndIconHeight = 16;

    private static final int covIndIconWidth = 16;

    //
    // private static final int covIndBarHeight = 7;
    //
    // private static final int covIndBarWidth = 16;
    //
    // private static final int covIndBarXPos = 0;
    //
    // private static final int covIndBarYPos = 5;

    private static final RGB covIndCoveredColor = new RGB(20, 210, 0);

    private static final RGB covIndUncoveredColor = new RGB(186, 0, 0);

    private static final RGB covIndUnknownColor = new RGB(238, 238, 238);

    /**
     * The number of steps of the coverage indicator bar. For each step an image
     * is created, plus the image for the 0% step.
     */
    private static final int covIndSteps = covIndIconWidth;

    /**
     * If <code>true</code> only 0% is represented by the
     * 0%-coverage-indicator and only 100% is represented by the
     * 100%-coverage-indicator. If <code>false</code>, it is possible that a
     * value which is not 0 (but close to 0) is represented by a
     * 0%-coverage-indicator depending on the number of {@link #covIndSteps}
     * 0% and 100% are interpreted relative to the number of significant
     * fraction digits for percentages, i.e. if this number is 1:
     * 100% == 100.04% and 100% == 99.95% but 100% != 100.06% and
     * 100% != 99.94%, which in turn means that 99.95% is represented by a
     * 100%-coverage-indicator but not 99.94%.
     */
    private static final boolean covIndTrueLimits = true;

    /**
     * The number of significant fraction digits when comparing the
     * <em>percentages</em> of coverage results. The percentages to compare
     * are rounded to this number of digits. 
     */
    private static final int covIndNumberOfSignificantFractionDigits = 1;

    private static final int covIndPrecision = (int) Math.pow(10, covIndNumberOfSignificantFractionDigits + 2);

    private static final float covIndMinQuotientFor100Percent = 1f - (0.5f / covIndPrecision);

    private static final float covIndMaxQuotientFor0Percent = 0f + (0.5f / covIndPrecision);

    /**
     * A coverage indicator visualizes the result of a coverage measurement by
     * displaying a green bar which represents the percentage of covered code.
     * This method creates an image of this bar from a given
     * <code>CoverageResult</code> and caches it for subsequent calls, thus the
     * returned image must not be disposed.
     * 
     * @param result
     *            the <code>CoverageResult</code> to create the coverage
     *            indicator from
     * @return  an image which represents the coverage indicator or
     *          <code>null</code> if the given <code>CoverageResult</code> is
     *          <code>null</code> or if the image could not be created
     */
    public static Image generateCoverageIndicator(CoverageResult result) {
        if (result == null) {
            return null;
        }
        CoverageResult representingCovResult = calculateRepresentingCoverageResult(result);
        Image img;
        synchronized (covIndCacheLock) {
            img = covIndCache.get(representingCovResult);
            if (img != null) {
                return img;
            } else {
                img = generateCoverageIndicator(representingCovResult.getCoveredItems(),
                        representingCovResult.getTotalItems()).createImage();
                if (img != null) {
                    covIndCache.put(representingCovResult, img);
                }
                return img;
            }
        }
    }

    private static CoverageResult calculateRepresentingCoverageResult(CoverageResult result) {
        int cov = result.getCoveredItems();
        int tot = result.getTotalItems();
        float quotient = cov / (float) tot;
        int newCov;
        if (tot > 0) {
            newCov = Math.round(cov * (covIndSteps / (float) tot));
            /*
             * make sure that only 0% is represented by the
             * 0%-representing-coverage-result and only 100% is represented by
             * the 100%-representing-coverage-result 
             */
            if (covIndTrueLimits) {
                if (newCov == 0 && quotient > covIndMaxQuotientFor0Percent) {
                    newCov = 1;
                } else if (newCov == covIndSteps && quotient < covIndMinQuotientFor100Percent) {
                    newCov = covIndSteps - 1;
                }
            }
            return new CoverageResult(newCov, covIndSteps);
        } else {
            return CoverageResult.NULL;
        }
    }

    /**
     * A coverage indicator visualizes the result of a coverage measurement by
     * displaying a green bar which represents the percentage of covered code.
     * This method creates an image of this bar from a given
     * <code>CoverageResult</code>.
     * 
     * @param coveredCount
     *            the amount of covered coverableItems
     * @param totalCount
     *            the total amount of coverableItems
     * @return an image which represents the coverage indicator.
     */
    private static ImageDescriptor generateCoverageIndicator(int coveredCount, int totalCount) {
        // Display display = Display.getCurrent();
        // Image img = new Image(display, covIndIconWidth, covIndIconHeight);
        // img.setBackground(display.getSystemColor(SWT.COLOR_RED));
        // GC gc = new GC(img);
        // // draw background
        // gc.setBackground(new Color(display, covIndUncoveredColor));
        // gc.fillRectangle(covIndBarXPos,
        // covIndBarYPos,
        // covIndBarWidth,
        // covIndBarHeight);
        // // draw bar
        // float barWidth = covIndBarWidth;
        // // if there are no items to be covered, bar width stays at 100
        // percent
        // if (totalCount > 0) {
        // barWidth *= ((float) coveredCount / totalCount);
        // gc.setBackground(new Color(display, covIndCoveredColor));
        // } else {
        // gc.setBackground(new Color(display, covIndUnknownColor));
        // }
        // gc.fillRectangle(covIndBarXPos,
        // covIndBarYPos,
        // Math.round(barWidth),
        // covIndBarHeight);
        // gc.dispose();
        // // Now let's make the indicator image transparent.
        // ImageData imgData = img.getImageData();
        // img.dispose(); // get rid of the old image
        // imgData.transparentPixel = imgData.palette.getPixel(new RGB(255,
        // 255,
        // 255));
        // return the transparent image
        // return new Image(display, imgData);
        return generateDecorator(coveredCount, totalCount, covIndIconWidth, covIndIconHeight);
    }

    private static ImageDescriptor generateDecorator(int coveredCount, int totalCount, final int covIndIconWidth,
            final int covIndIconHeight) {
        final int covBarHeight = covIndIconHeight / 2;
        final int yPosOffset = (covIndIconHeight - covBarHeight) / 2 + 1;

        ImageData imageData = new ImageData(covIndIconWidth, covIndIconHeight, 32,
                new PaletteData(0xFF0000, 0xFF00, 0xFF));

        if (totalCount <= 0) {
            for (int i = 0; i < covIndIconWidth; i++) {
                for (int a = yPosOffset; a < covIndIconHeight - yPosOffset; a++) {
                    imageData.setPixel(i, a, imageData.palette.getPixel(covIndUnknownColor));
                }
            }
        } else {
            int dividerPos = Math.round(covIndIconWidth * ((float) coveredCount / (float) totalCount));

            for (int i = 0; i < covIndIconWidth; i++) {
                for (int a = yPosOffset; a < covIndIconHeight - yPosOffset; a++) {
                    RGB rgb;
                    if (i < dividerPos) {
                        rgb = covIndCoveredColor;
                    } else {
                        rgb = covIndUncoveredColor;
                    }

                    imageData.setPixel(i, a, imageData.palette.getPixel(rgb));
                }
            }
        }

        imageData.transparentPixel = imageData.palette.getPixel(new RGB(0, 0, 0));

        return ImageDescriptor.createFromImageData(imageData);
    }

    /**
     * The image to be used in the packageExplorer as a decorator for to be
     * instrumented Items.
     * 
     * @return the {@link ImageDescriptor}
     */
    public static ImageDescriptor getDecorator() {
        if (decorator == null) {
            decorator = generateDecorator(1, 2, ImageProvider.covIndIconWidth / 2,
                    2 * ImageProvider.covIndIconHeight / 3);
        }
        return decorator;
    }

    /**
     * Disposes all provided images (provided via
     * {@link #generateCoverageIndicator(CoverageResult)}). Be sure that they
     * aren't in use anymore.
     */
    public static void dispose() {
        synchronized (covIndCacheLock) {
            for (Image img : covIndCache.values()) {
                img.dispose();
            }
            covIndCache.clear();
        }
    }
}