001 package com.croftsoft.apps.savor; 002 003 import java.awt.*; 004 import java.awt.event.*; 005 import java.io.*; 006 import java.util.*; 007 import java.util.concurrent.*; 008 import java.util.logging.*; 009 010 import javax.imageio.ImageIO; 011 012 import org.jdesktop.jdic.screensaver.ScreensaverContext; 013 import org.jdesktop.jdic.screensaver.ScreensaverSettings; 014 import org.jdesktop.jdic.screensaver.SimpleScreensaver; 015 016 import com.croftsoft.core.awt.image.ImageLib; 017 import com.croftsoft.core.math.MathConstants; 018 019 /********************************************************************* 020 * CroftSoft Savor. 021 * 022 * @version 023 * $Id: SavorPix.java,v 1.17 2006/12/16 06:30:46 croft Exp $ 024 * @since 025 * 2006-12-09 026 * @author 027 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 028 *********************************************************************/ 029 030 public final class SavorPix 031 extends SimpleScreensaver 032 ////////////////////////////////////////////////////////////////////// 033 ////////////////////////////////////////////////////////////////////// 034 { 035 036 private static final String 037 PROPERTY_SHOW = "show", 038 PROPERTY_SPEED = "speed"; 039 040 private static final String [ ] PROPERTY_SHOW_VALUES = { 041 "off", 042 "on" }; 043 044 private static final String [ ] PROPERTY_SPEED_VALUES = { 045 "slow", 046 "medium", 047 "fast" }; 048 049 private static final int [ ] DISPLAY_TIMES = { 050 600, 051 60, 052 6 }; 053 054 private static final boolean [ ] SHOW_VALUES = { 055 false, 056 true }; 057 058 private static final long DEFAULT_DISPLAY_TIME_NANOS 059 = DISPLAY_TIMES [ 0 ] * MathConstants.NANOSECONDS_PER_SECOND; 060 061 private static final boolean DEFAULT_SHOW 062 = SHOW_VALUES [ 0 ]; 063 064 private static final int FRAME_PERIOD = 1; 065 066 // 067 068 private final Map<String, Integer> speedMap; 069 070 private final Map<String, Boolean> showMap; 071 072 private final Random random; 073 074 private final Logger logger; 075 076 // 077 078 private boolean 079 initialized, 080 show, 081 skip; 082 083 private int 084 componentWidth, 085 componentHeight; 086 087 private Image offscreenImage; 088 089 private String [ ] imageFilenames; 090 091 private long 092 displayTimeNanos, 093 lastTimeNanos; 094 095 ////////////////////////////////////////////////////////////////////// 096 ////////////////////////////////////////////////////////////////////// 097 098 public SavorPix ( ) 099 ////////////////////////////////////////////////////////////////////// 100 { 101 Logger.getLogger ( "org.jdesktop.jdic.screensaver" ).setLevel ( 102 Level.FINEST ); 103 104 logger = Logger.getLogger ( getClass ( ).getName ( ) ); 105 106 logger.setLevel ( Level.FINEST ); 107 108 // Turn this on for debugging. 109 // initLoggingToFiles ( logger ); 110 111 random = new Random ( ); 112 113 speedMap = new HashMap<String, Integer> ( ); 114 115 for ( int i = 0; i < PROPERTY_SPEED_VALUES.length; i++ ) 116 { 117 speedMap.put ( 118 PROPERTY_SPEED_VALUES [ i ], 119 new Integer ( DISPLAY_TIMES [ i ] ) ); 120 } 121 122 displayTimeNanos = DEFAULT_DISPLAY_TIME_NANOS; 123 124 showMap = new HashMap<String, Boolean> ( ); 125 126 for ( int i = 0; i < PROPERTY_SHOW_VALUES.length; i++ ) 127 { 128 showMap.put ( 129 PROPERTY_SHOW_VALUES [ i ], 130 new Boolean ( SHOW_VALUES [ i ] ) ); 131 } 132 133 show = DEFAULT_SHOW; 134 } 135 136 ////////////////////////////////////////////////////////////////////// 137 ////////////////////////////////////////////////////////////////////// 138 139 @Override 140 public synchronized void init ( ) 141 ////////////////////////////////////////////////////////////////////// 142 { 143 try 144 { 145 logger.entering ( getClass ( ).getName ( ), "init" ); 146 147 lastTimeNanos = 0; 148 149 final ScreensaverContext screensaverContext = getContext ( ); 150 151 final Component component = screensaverContext.getComponent ( ); 152 153 componentWidth = component.getWidth ( ); 154 155 componentHeight = component.getHeight ( ); 156 157 if ( ( componentWidth > 0 ) 158 && ( componentHeight > 0 ) ) 159 { 160 offscreenImage 161 = component.createImage ( componentWidth, componentHeight ); 162 } 163 164 // Might be called more than once 165 166 if ( initialized ) 167 { 168 return; 169 } 170 171 initialized = true; 172 173 // Spacebar skipping stopped working in the switch from Java 5 174 // to Java 6. I do not know why. 175 176 component.addKeyListener ( 177 new KeyAdapter ( ) 178 { 179 @Override 180 public void keyPressed ( final KeyEvent keyEvent ) 181 { 182 final int keyCode = keyEvent.getKeyCode ( ); 183 184 if ( keyCode == KeyEvent.VK_SPACE ) 185 { 186 logger.info ( "spacebar pressed" ); 187 188 skip = true; 189 } 190 } 191 } ); 192 193 component.requestFocus ( ); 194 195 final Integer displayTimeInteger 196 = ( Integer ) getPropertyValue ( PROPERTY_SPEED, speedMap ); 197 198 if ( displayTimeInteger != null ) 199 { 200 displayTimeNanos = displayTimeInteger.intValue ( ) 201 * MathConstants.NANOSECONDS_PER_SECOND; 202 } 203 204 final Boolean showBoolean 205 = ( Boolean ) getPropertyValue ( PROPERTY_SHOW, showMap ); 206 207 if ( showBoolean != null ) 208 { 209 show = showBoolean.booleanValue ( ); 210 } 211 212 final Executor executor = Executors.newSingleThreadExecutor ( ); 213 214 executor.execute ( 215 new Runnable ( ) 216 { 217 public void run ( ) 218 { 219 imageFilenames = getImageFilenames ( ); 220 } 221 } ); 222 } 223 catch ( final Throwable throwable ) 224 { 225 throwable.printStackTrace ( ); 226 227 logger.throwing ( getClass ( ).getName ( ), "init", throwable ); 228 } 229 finally 230 { 231 logger.exiting ( getClass ( ).getName ( ), "init" ); 232 } 233 } 234 235 @Override 236 public void paint ( final Graphics graphics ) 237 ////////////////////////////////////////////////////////////////////// 238 { 239 try 240 { 241 if ( ( offscreenImage == null ) 242 || ( imageFilenames == null ) 243 || ( imageFilenames.length < 1 ) ) 244 { 245 graphics.setColor ( Color.BLACK ); 246 247 graphics.fillRect ( 248 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE ); 249 250 return; 251 } 252 253 final long currentTimeNanos = System.nanoTime ( ); 254 255 final long deltaTimeNanos = currentTimeNanos - lastTimeNanos; 256 257 if ( skip 258 || ( deltaTimeNanos >= displayTimeNanos ) ) 259 { 260 logger.info ( "paint changing image" ); 261 262 skip = false; 263 264 lastTimeNanos = currentTimeNanos; 265 266 final Graphics2D offscreenGraphics2D 267 = ( Graphics2D ) offscreenImage.getGraphics ( ); 268 269 offscreenGraphics2D.setColor ( Color.BLACK ); 270 271 offscreenGraphics2D.fillRect ( 272 0, 0, componentWidth, componentHeight ); 273 274 if ( ( imageFilenames != null ) 275 && ( imageFilenames.length > 0 ) ) 276 { 277 final int imageIndex 278 = random.nextInt ( imageFilenames.length ); 279 280 final String imageFilename = imageFilenames [ imageIndex ]; 281 282 logger.info ( imageFilename ); 283 284 final File imageFile = new File ( imageFilename ); 285 286 final Image image = ImageIO.read ( imageFile ); 287 288 final Rectangle rectangle = ImageLib.shrinkToFitAndCenter ( 289 image.getWidth ( null ), 290 image.getHeight ( null ), 291 componentWidth, 292 componentHeight ); 293 294 logger.info ( rectangle.toString ( ) ); 295 296 if ( image != null ) 297 { 298 offscreenGraphics2D.drawImage ( 299 image, 300 rectangle.x, 301 rectangle.y, 302 rectangle.width, 303 rectangle.height, 304 null ); 305 } 306 else 307 { 308 logger.info ( "null image" ); 309 } 310 311 if ( show ) 312 { 313 offscreenGraphics2D.setColor ( Color.GREEN ); 314 315 offscreenGraphics2D.drawString ( imageFilename, 20, 20 ); 316 } 317 } 318 else 319 { 320 logger.info ( "no images" ); 321 322 offscreenGraphics2D.setColor ( Color.RED ); 323 324 offscreenGraphics2D.drawString ( "no images", 20, 20 ); 325 } 326 327 offscreenGraphics2D.dispose ( ); 328 329 graphics.drawImage ( offscreenImage, 0, 0, null ); 330 } 331 332 Thread.sleep ( FRAME_PERIOD ); 333 } 334 catch ( final Throwable throwable ) 335 { 336 throwable.printStackTrace ( ); 337 338 logger.throwing ( getClass ( ).getName ( ), "paint", throwable ); 339 340 graphics.setColor ( Color.RED ); 341 342 graphics.fillRect ( 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE ); 343 344 graphics.setColor ( Color.BLACK ); 345 346 graphics.drawString ( throwable.getMessage ( ), 30, 30 ); 347 } 348 } 349 350 ////////////////////////////////////////////////////////////////////// 351 // private methods 352 ////////////////////////////////////////////////////////////////////// 353 354 private String [ ] getImageFilenames ( ) 355 ////////////////////////////////////////////////////////////////////// 356 { 357 try 358 { 359 final String [ ] suffixes = ImageIO.getReaderFileSuffixes ( ); 360 361 final String userHome = System.getProperty ( "user.home" ); 362 363 if ( userHome == null ) 364 { 365 return null; 366 } 367 368 final File homeDirectory = new File ( userHome ); 369 370 if ( !homeDirectory.exists ( ) 371 || !homeDirectory.isDirectory ( ) ) 372 { 373 return null; 374 } 375 376 File picturesDirectory 377 = new File ( homeDirectory, "My Documents/My Pictures" ); 378 379 if ( !picturesDirectory.exists ( ) 380 || !picturesDirectory.isDirectory ( ) ) 381 { 382 picturesDirectory = homeDirectory; 383 } 384 385 final Set<String> imageFilenameSet = new HashSet<String> ( ); 386 387 final Stack<File> directoryStack = new Stack<File> ( ); 388 389 directoryStack.add ( picturesDirectory ); 390 391 File directory = null; 392 393 while ( !directoryStack.isEmpty ( ) ) 394 { 395 directory = directoryStack.pop ( ); 396 397 final String [ ] list = directory.list ( ); 398 399 for ( String filename : list ) 400 { 401 final File file = new File ( directory, filename ); 402 403 if ( file.isDirectory ( ) ) 404 { 405 directoryStack.add ( file ); 406 407 continue; 408 } 409 410 filename = filename.toLowerCase ( ); 411 412 for ( final String suffix : suffixes ) 413 { 414 if ( filename.endsWith ( "." + suffix ) ) 415 { 416 filename = file.getCanonicalPath ( ); 417 418 imageFilenameSet.add ( filename ); 419 420 break; 421 } 422 } 423 } 424 } 425 426 return imageFilenameSet.toArray ( new String [ 0 ] ); 427 } 428 catch ( final Exception ex ) 429 { 430 ex.printStackTrace ( ); 431 } 432 433 return null; 434 } 435 436 private Object getPropertyValue ( 437 final String propertyName, 438 final Map propertyMap ) 439 ////////////////////////////////////////////////////////////////////// 440 { 441 final ScreensaverContext screensaverContext = getContext ( ); 442 443 final ScreensaverSettings screensaverSettings 444 = screensaverContext.getSettings ( ); 445 446 String propertyValue 447 = screensaverSettings.getProperty ( propertyName ); 448 449 if ( propertyValue == null ) 450 { 451 return null; 452 } 453 454 propertyValue = propertyValue.trim ( ).toLowerCase ( ); 455 456 return propertyMap.get ( propertyValue ); 457 } 458 459 private static void initLoggingToFiles ( final Logger logger ) 460 ////////////////////////////////////////////////////////////////////// 461 { 462 try 463 { 464 final String userHome = System.getProperty ( "user.home" ); 465 466 if ( userHome == null ) 467 { 468 return; 469 } 470 471 final File homeDirectory = new File ( userHome ); 472 473 if ( !homeDirectory.exists ( ) 474 || !homeDirectory.isDirectory ( ) ) 475 { 476 return; 477 } 478 479 final File logDirectory 480 = new File ( homeDirectory, ".croftsoft/savor" ); 481 482 logDirectory.mkdirs ( ); 483 484 final FileHandler fileHandler = new FileHandler ( 485 "%h/.croftsoft/savor/savor%g.log", 486 10000, 487 2, 488 false ); 489 490 Logger.getLogger ( "org.jdesktop.jdic.screensaver" ).addHandler ( 491 fileHandler ); 492 493 logger.addHandler ( fileHandler ); 494 } 495 catch ( final Exception ex ) 496 { 497 ex.printStackTrace ( ); 498 } 499 } 500 501 ////////////////////////////////////////////////////////////////////// 502 ////////////////////////////////////////////////////////////////////// 503 }