/******************************************************************************* * Copyright Technophobia Ltd 2012 * * This file is part of the Substeps Eclipse Plugin. * * The Substeps Eclipse Plugin is free software: you can redistribute it and/or modify * it under the terms of the Eclipse Public License v1.0. * * The Substeps Eclipse Plugin 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 * Eclipse Public License for more details. * * You should have received a copy of the Eclipse Public License * along with the Substeps Eclipse Plugin. If not, see <http://www.eclipse.org/legal/epl-v10.html>. ******************************************************************************/ package com.technophobia.substeps.junit.ui.progress; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import com.technophobia.substeps.junit.ui.component.ProgressBar; public class SubstepsProgressBar extends Canvas implements ProgressBar { private static final int DEFAULT_WIDTH = 160; private static final int DEFAULT_HEIGHT = 18; private int currentTickCount = 0; private int maxTickCount = 0; private int colorBarWidth = 0; private final Color okColor; private final Color failureColor; private final Color stoppedColor; private boolean error; private boolean stopped = false; public SubstepsProgressBar(final Composite parent) { super(parent, SWT.NONE); addControlListener(new ControlAdapter() { @Override public void controlResized(final ControlEvent e) { colorBarWidth = scale(currentTickCount); redraw(); } }); addPaintListener(new PaintListener() { @Override public void paintControl(final PaintEvent e) { paint(e); } }); addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(final DisposeEvent e) { failureColor.dispose(); okColor.dispose(); stoppedColor.dispose(); } }); final Display display = parent.getDisplay(); this.failureColor = new Color(display, 159, 63, 63); this.okColor = new Color(display, 95, 191, 95); this.stoppedColor = new Color(display, 120, 120, 120); } public void setMaximum(final int max) { this.maxTickCount = max; } public void reset() { this.error = false; this.stopped = false; this.currentTickCount = 0; this.maxTickCount = 0; this.colorBarWidth = 0; redraw(); } @Override public void reset(final boolean hasErrors, final boolean hasStopped, final int ticksDone, final int maximum) { final boolean noChange = this.error == hasErrors && hasStopped == this.stopped && this.currentTickCount == ticksDone && this.maxTickCount == maximum; this.error = hasErrors; this.stopped = hasStopped; this.currentTickCount = ticksDone; this.maxTickCount = maximum; this.colorBarWidth = scale(ticksDone); if (!noChange) redraw(); } private void paintStep(final int startX, final int endX) { final GC gc = new GC(this); setStatusColor(gc); final Rectangle rect = getClientArea(); final int sanitisedStartX = Math.max(1, startX); gc.fillRectangle(sanitisedStartX, 1, endX - sanitisedStartX, rect.height - 2); gc.dispose(); } private void setStatusColor(final GC gc) { if (stopped) gc.setBackground(stoppedColor); else if (error) gc.setBackground(failureColor); else gc.setBackground(okColor); } public void stopped() { stopped = true; redraw(); } private int scale(final int value) { if (maxTickCount > 0) { final Rectangle r = getClientArea(); if (r.width != 0) return Math.max(0, value * (r.width - 2) / maxTickCount); } return value; } private void drawBevelRect(final GC gc, final int x, final int y, final int w, final int h, final Color topleft, final Color bottomright) { gc.setForeground(topleft); gc.drawLine(x, y, x + w - 1, y); gc.drawLine(x, y, x, y + h - 1); gc.setForeground(bottomright); gc.drawLine(x + w, y, x + w, y + h); gc.drawLine(x, y + h, x + w, y + h); } private void paint(final PaintEvent event) { final GC gc = event.gc; final Display disp = getDisplay(); final Rectangle rect = getClientArea(); gc.fillRectangle(rect); drawBevelRect(gc, rect.x, rect.y, rect.width - 1, rect.height - 1, disp.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW), disp.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW)); setStatusColor(gc); colorBarWidth = Math.min(rect.width - 2, colorBarWidth); gc.fillRectangle(1, 1, colorBarWidth, rect.height - 2); } @Override public Point computeSize(final int wHint, final int hHint, final boolean changed) { checkWidget(); final Point size = new Point(DEFAULT_WIDTH, DEFAULT_HEIGHT); if (wHint != SWT.DEFAULT) size.x = wHint; if (hHint != SWT.DEFAULT) size.y = hHint; return size; } public void step(final int failures) { currentTickCount++; int x = colorBarWidth; colorBarWidth = scale(currentTickCount); if (!error && failures > 0) { error = true; x = 1; } if (currentTickCount == maxTickCount) colorBarWidth = getClientArea().width - 1; paintStep(x, colorBarWidth); } public void refresh(final boolean hasErrors) { error = hasErrors; redraw(); } }