Coverage Report - us.daveread.basicquery.gui.FlashForeground
 
Classes in this File Line Coverage Branch Coverage Complexity
FlashForeground
97%
69/71
100%
17/17
4.75
 
 1  
 package us.daveread.basicquery.gui;
 2  
 
 3  
 import java.awt.Component;
 4  
 import java.awt.Color;
 5  
 
 6  
 import org.apache.log4j.Logger;
 7  
 
 8  
 /**
 9  
  * <p>
 10  
  * Title: Flash foreground
 11  
  * </p>
 12  
  * <p>
 13  
  * Description: Eye candy modifying the foreground color of a component
 14  
  * </p>
 15  
  * <p>
 16  
  * Copyright: Copyright (c) 2004-2014, David Read
 17  
  * </p>
 18  
  * <p>
 19  
  * This program is free software; you can redistribute it and/or modify it under
 20  
  * the terms of the GNU General Public License as published by the Free Software
 21  
  * Foundation; either version 2 of the License, or (at your option) any later
 22  
  * version.
 23  
  * </p>
 24  
  * <p>
 25  
  * This program is distributed in the hope that it will be useful, but WITHOUT
 26  
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 27  
  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 28  
  * details.
 29  
  * </p>
 30  
  * <p>
 31  
  * You should have received a copy of the GNU General Public License along with
 32  
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 33  
  * Place, Suite 330, Boston, MA 02111-1307 USA
 34  
  * </p>
 35  
  * <p>
 36  
  * </p>
 37  
  * 
 38  
  * @author David Read
 39  
  */
 40  
 
 41  
 public class FlashForeground implements Runnable {
 42  
   /**
 43  
    * Logger
 44  
    */
 45  1
   private static final Logger LOGGER = Logger.getLogger(FlashForeground.class);
 46  
 
 47  
   /**
 48  
    * The component backing this instance
 49  
    */
 50  
   private Component component;
 51  
 
 52  
   /**
 53  
    * The color to display when the flash is "on"
 54  
    */
 55  
   private Color onColor;
 56  
 
 57  
   /**
 58  
    * The color to display when the flash is "off"
 59  
    */
 60  
   private Color offColor;
 61  
 
 62  
   /**
 63  
    * Delay time when cycling the steps between "on" and "off" colors
 64  
    */
 65  
   private int msDelay;
 66  
 
 67  
   /**
 68  
    * Red color value for RGB coloring when the flash is "on"
 69  
    */
 70  
   private int redOn;
 71  
 
 72  
   /**
 73  
    * Red color value for RGB coloring when the flash is "off"
 74  
    */
 75  
   private int redOff;
 76  
 
 77  
   /**
 78  
    * Green color value for RGB coloring when the flash is "on"
 79  
    */
 80  
   private int greenOn;
 81  
 
 82  
   /**
 83  
    * Green color value for RGB coloring when the flash is "off"
 84  
    */
 85  
   private int greenOff;
 86  
 
 87  
   /**
 88  
    * Blue color value for RGB coloring when the flash is "on"
 89  
    */
 90  
   private int blueOn;
 91  
 
 92  
   /**
 93  
    * Blue color value for RGB coloring when the flash is "off"
 94  
    */
 95  
   private int blueOff;
 96  
 
 97  
   /**
 98  
    * Amount of change for the red component of the RGB color at each step in the
 99  
    * coloring cycle
 100  
    */
 101  
   private int redChange;
 102  
 
 103  
   /**
 104  
    * Amount of change for the green component of the RGB color at each step in
 105  
    * the coloring cycle
 106  
    */
 107  
   private int greenChange;
 108  
 
 109  
   /**
 110  
    * Amount of change for the blue component of the RGB color at each step in
 111  
    * the coloring cycle
 112  
    */
 113  
   private int blueChange;
 114  
 
 115  
   /**
 116  
    * Current red value in the RGB color
 117  
    */
 118  
   private int redValue;
 119  
 
 120  
   /**
 121  
    * Current green value in the RGB color
 122  
    */
 123  
   private int greenValue;
 124  
 
 125  
   /**
 126  
    * Current blue value in the RGB color
 127  
    */
 128  
   private int blueValue;
 129  
 
 130  
   /**
 131  
    * The modulus value of the iteration counter for changing the red component
 132  
    * of the RGB color
 133  
    */
 134  
   private int redModulus;
 135  
 
 136  
   /**
 137  
    * The modulus value of the iteration counter for changing the green component
 138  
    * of the RGB color
 139  
    */
 140  
   private int greenModulus;
 141  
 
 142  
   /**
 143  
    * The modulus value of the iteration counter for changing the blue component
 144  
    * of the RGB color
 145  
    */
 146  
   private int blueModulus;
 147  
 
 148  
   /**
 149  
    * The maximum range of the iteration counter to cycle through the component
 150  
    * color ranges from "on" to "off"
 151  
    */
 152  
   private int maxChange;
 153  
 
 154  
   /**
 155  
    * The current value of the iteration counter cycling through the component
 156  
    * color ranges from "on" to "off"
 157  
    */
 158  
   private int currentValue;
 159  
 
 160  
   /**
 161  
    * The current iteration direction (1=up or -1=down). Up moves from the "off"
 162  
    * color to the "on" color.
 163  
    */
 164  
   private int direction;
 165  
 
 166  
   /**
 167  
    * Create a FlashForeground instance, associated with a specific component.
 168  
    * Then the instance is notified that it should "flash" it will begin changing
 169  
    * the foreground color between the "On" and "Off" colors. When the instance
 170  
    * is notified that it should stop, the foreground color is changed to
 171  
    * the "Off" color
 172  
    * 
 173  
    * @param aComp
 174  
    *          The component whose foreground color is controlled by this
 175  
    *          instance
 176  
    * @param aOnColor
 177  
    *          The color used to indicate some activity is running.
 178  
    * @param aOffColor
 179  
    *          The default foreground color of the component.
 180  
    * @param aMSDelay
 181  
    *          The number of milliseconds between color changes. Note that
 182  
    *          the colors change by gradation, so this number should be small.
 183  
    */
 184  
   public FlashForeground(Component aComp, Color aOnColor, Color aOffColor,
 185  6
       int aMSDelay) {
 186  6
     component = aComp;
 187  6
     onColor = aOnColor;
 188  6
     offColor = aOffColor;
 189  6
     msDelay = aMSDelay;
 190  6
     computeChange();
 191  6
     direction = -1;
 192  6
     currentValue = 0;
 193  6
   }
 194  
 
 195  
   /**
 196  
    * Calculate the next color to be used for the foreground. The algorithm
 197  
    * is pretty simple, just change the RGB values between the "On" and "Off"
 198  
    * colors, incrementing based on the widest color descrepency.
 199  
    * 
 200  
    * @return The Color to be used for the foreground
 201  
    */
 202  
   private Color nextColor() {
 203  295
     if (currentValue <= 0 || currentValue >= maxChange) {
 204  5
       direction *= -1;
 205  
     }
 206  
 
 207  295
     currentValue += direction;
 208  
 
 209  295
     if (currentValue == maxChange) {
 210  2
       redValue = redOn;
 211  2
       greenValue = greenOn;
 212  2
       blueValue = blueOn;
 213  293
     } else if (currentValue == 0) {
 214  2
       redValue = redOff;
 215  2
       greenValue = greenOff;
 216  2
       blueValue = blueOff;
 217  
     } else {
 218  291
       if (currentValue % redModulus == 0) {
 219  291
         redValue += (redChange * direction) < 0 ? 1 : -1;
 220  
       }
 221  
 
 222  291
       if (currentValue % greenModulus == 0) {
 223  291
         greenValue += (greenChange * direction) < 0 ? 1 : -1;
 224  
       }
 225  
 
 226  291
       if (currentValue % blueModulus == 0) {
 227  291
         blueValue += (blueChange * direction) < 0 ? 1 : -1;
 228  
       }
 229  
     }
 230  
 
 231  295
     if (currentValue == 0 || currentValue == maxChange) {
 232  4
       LOGGER.debug("currentValue=" + currentValue);
 233  
     }
 234  
 
 235  295
     return new Color(redValue, greenValue, blueValue);
 236  
   }
 237  
 
 238  
   /**
 239  
    * Compute the RGB values for the "On" and "Off" colors. Then determine
 240  
    * the distance (numerically) between them.
 241  
    */
 242  
   private void computeChange() {
 243  6
     redOn = onColor.getRed();
 244  6
     redOff = offColor.getRed();
 245  6
     greenOn = onColor.getGreen();
 246  6
     greenOff = offColor.getGreen();
 247  6
     blueOn = onColor.getBlue();
 248  6
     blueOff = offColor.getBlue();
 249  6
     redChange = redOff - redOn;
 250  6
     greenChange = greenOff - greenOn;
 251  6
     blueChange = blueOff - blueOn;
 252  6
     maxChange = Math.abs(redChange);
 253  6
     if (Math.abs(greenChange) > maxChange) {
 254  1
       maxChange = Math.abs(greenChange);
 255  
     }
 256  6
     if (Math.abs(blueChange) > maxChange) {
 257  1
       maxChange = Math.abs(blueChange);
 258  
     }
 259  
 
 260  6
     if (redChange != 0) {
 261  5
       redModulus = maxChange / Math.abs(redChange);
 262  
       // if (redModulus < 1) {
 263  
       // redModulus = 1;
 264  
       // }
 265  
     } else {
 266  1
       redModulus = maxChange + 1;
 267  
     }
 268  
 
 269  6
     if (greenChange != 0) {
 270  5
       greenModulus = maxChange / Math.abs(greenChange);
 271  
       // if (greenModulus < 1) {
 272  
       // greenModulus = 1;
 273  
       // }
 274  
     } else {
 275  1
       greenModulus = maxChange + 1;
 276  
     }
 277  
 
 278  6
     if (blueChange != 0) {
 279  5
       blueModulus = maxChange / Math.abs(blueChange);
 280  
       // if (blueModulus < 1) {
 281  
       // blueModulus = 1;
 282  
       // }
 283  
     } else {
 284  1
       blueModulus = maxChange + 1;
 285  
     }
 286  
 
 287  6
     redValue = redOff;
 288  6
     greenValue = greenOff;
 289  6
     blueValue = blueOff;
 290  6
   }
 291  
 
 292  
   /**
 293  
    * Oscillate the component colors until an interrupt is
 294  
    * received.
 295  
    */
 296  
   public void run() {
 297  
     boolean isOn;
 298  
     boolean keepGoing;
 299  
 
 300  1
     isOn = false;
 301  1
     keepGoing = true;
 302  
 
 303  
     try {
 304  296
       while (keepGoing && !Thread.currentThread().isInterrupted()) {
 305  295
         isOn = !isOn;
 306  
         // component.setForeground(isOn ? onColor : offColor);
 307  295
         component.setForeground(nextColor());
 308  
         try {
 309  295
           Thread.sleep(msDelay);
 310  1
         } catch (InterruptedException ie) {
 311  1
           keepGoing = false;
 312  295
         }
 313  
       }
 314  0
     } catch (Throwable any) {
 315  0
       LOGGER.warn("Error when iterating through colors in a compoenent", any);
 316  
     } finally {
 317  1
       component.setForeground(offColor);
 318  1
     }
 319  1
   }
 320  
 }