// Copyright (c) 2008 James A. Wilson All rights reserved. Use is // subject to license terms. // This file is part of CruiseSaver. // // CruiseSaver 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. // // CruiseSaver 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 CruiseSaver; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA package status; import java.awt.Component; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Exchanger; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; import org.jdesktop.jdic.screensaver.ScreensaverSettings; import org.jdesktop.jdic.screensaver.SimpleScreensaver; import status.collisions.ParticleParty; import status.concurrent.StatusExecutor; import status.logging.LogUtil; /** * CruiseControl status screen saver built from CCStatus screensaver by James * Wilson * * @author James Wilson, Nate Young */ public class CCCollidingStatus extends SimpleScreensaver { Logger logger = LogUtil.getLogger(CCCollidingStatus.class); static final String CONFIG_ERROR_PREFIX = "configuration error:\n "; private Image offScreen; private Graphics offScreenGraphics; // private StatusTimerTask statusTimerTask; private Exchanger<List<Project>> exchanger; private List<Project> lastProjectsPainted; private CCSettings ccSettings; private ParticleParty simulation; private final ProjectRenderer projectRenderer = new ProjectRenderer(); final MessageRenderer messageRenderer = new MessageRenderer(); @Override public void init() { super.init(); exchanger = new Exchanger<List<Project>>(); ScreensaverSettings settings = getContext().getSettings(); ccSettings = new CCSettings(settings); projectRenderer.setBallSize(ccSettings.getBallSize()); lastProjectsPainted = Collections.emptyList(); ; List<Project> projects = Collections.emptyList(); try { new StatusExecutor(ccSettings.getBuildStatus(), ccSettings.getUpdateDelaySeconds(), exchanger); } catch (IllegalArgumentException e) { logger.log(Level.SEVERE, "settings are messed up.", e); messageRenderer.setMessage(CONFIG_ERROR_PREFIX + e.getMessage()); } int width = getContext().getComponent().getWidth(); int height = getContext().getComponent().getHeight(); simulation = new ParticleParty(projects.size(), width, height); simulation.setRadius(ccSettings.getBallSize()); } @Override public void paint(Graphics g) { Component c = getContext().getComponent(); // double buffered graphics if ((offScreen == null) || (offScreen.getWidth(null) != c.getWidth()) || (offScreen.getHeight(null) != c.getHeight())) { logger.fine("creating new offscreen graphic sized: " + c.getWidth() + "," + c.getHeight()); if (offScreen != null) { logger.fine("dispose of old offscreen graphic sized: " + c.getWidth() + "," + c.getHeight()); offScreenGraphics.dispose(); } offScreen = c.createImage(c.getWidth(), c.getHeight()); offScreenGraphics = offScreen.getGraphics(); offScreenGraphics.setColor(c.getBackground()); offScreenGraphics.fillRect(0, 0, c.getWidth(), c.getHeight()); Font priorFont = offScreenGraphics.getFont(); Font newFont = new Font(priorFont.getName(), priorFont.getStyle(), ccSettings .getFontSize()); offScreenGraphics.setFont(newFont); messageRenderer.setHeight(offScreen.getHeight(null)); } try { renderToGraphics((Graphics2D) offScreenGraphics); } catch (RuntimeException e) { logger.log(Level.SEVERE, "exception during renderToGraphics: ", e); } g.drawImage(offScreen, 0, 0, null); } private void renderToGraphics(Graphics2D g) { Component c = getContext().getComponent(); // Erase the old g.setColor(c.getBackground()); g.fillRect(0, 0, c.getWidth(), c.getHeight()); simulation.next(); lastProjectsPainted = getProjects(); if (!lastProjectsPainted.isEmpty()) { for (int i = 0; i < lastProjectsPainted.size(); i++) { Project project = lastProjectsPainted.get(i); projectRenderer.render(g, project.getLabel(), project.getBuildStatus(), simulation .getOrb(i)); } } // this code won't do anything if cruise control is working normally // otherwise it'll render an error message to the screen g.setColor(c.getBackground()); if ((lastProjectsPainted == null || lastProjectsPainted.isEmpty()) && messageRenderer.getMessage() == null) { messageRenderer.setMessage("fetching projects from " + ccSettings.getHostName()); } messageRenderer.render(g); } private List<Project> getProjects() { List<Project> updatedProjects = new ArrayList<Project>(); List<Project> projects = lastProjectsPainted; try { projects = exchanger.exchange(updatedProjects, 1, TimeUnit.NANOSECONDS); logger.fine("exchanged project list of size " + projects.size()); if (projects.size() != lastProjectsPainted.size()) { simulation.setNumberOfOrbs(projects.size()); messageRenderer.setMessage(null); } } catch (InterruptedException e) { logger.log(Level.WARNING, "oops", e); } catch (TimeoutException ignore) { // logger.log(Level.FINE, "oops", e); } return projects; } }