/* Copyright (C) 2001, 2009 United States Government as represented by
the Administrator of the National Aeronautics and Space Administration.
All Rights Reserved.
*/
package org.geoforge.worldwind.x.examples.util;
import gov.nasa.worldwind.Configuration;
import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.WorldWindow;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.cache.BasicMemoryCache;
import gov.nasa.worldwind.cache.MemoryCache;
import gov.nasa.worldwind.util.ImageUtil;
import gov.nasa.worldwind.util.Logging;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import org.geoforge.lang.util.GfrResBundleLang;
import org.geoforge.java.lang.string.GfrUtlString;
/**
* @author dcollins
* @version $Id: SlideShowAnnotationController.java 1 2011-07-16 23:22:47Z dcollins $
*/
@SuppressWarnings(
{
"TypeParameterExplicitlyExtendsObject"
})
public class SlideShowAnnotationController extends DialogAnnotationController
{
public static final String BUFFERED_IMAGE_CACHE_SIZE = "gov.nasa.worldwind.avkey.BufferedImageCacheSize";
public static final String BUFFERED_IMAGE_CACHE_NAME = java.awt.image.BufferedImage.class.getName();
protected static final long SLIDESHOW_UPDATE_DELAY_MILLIS = 2000;
protected static final long DEFAULT_BUFFERED_IMAGE_CACHE_SIZE = 30000000;
protected static java.awt.Dimension SMALL_IMAGE_PREFERRED_SIZE = new java.awt.Dimension(320, 240);
protected static java.awt.Dimension LARGE_IMAGE_PREFERRED_SIZE = new java.awt.Dimension(600, 450);
protected int index;
protected String state;
protected java.util.List<Object> imageSources;
// Concurrent task components.
protected Thread readThread;
protected javax.swing.Timer updateTimer;
private HashMap<String, String> _mapSourceToTitle_ = null;
public SlideShowAnnotationController(
WorldWindow worldWindow,
SlideShowAnnotation annotation,
Iterable<?> imageSources,
HashMap<String, String> mapSourceToTitle) throws Exception
{
super(worldWindow, annotation);
this._mapSourceToTitle_ = mapSourceToTitle;
this.state = AVKey.STOP;
this.index = -1;
this.imageSources = new java.util.ArrayList<Object>();
if (imageSources != null)
{
for (Object source : imageSources)
{
if (source != null)
this.imageSources.add(source);
}
}
WorldWind wwd = WorldWind.getInstance();
if (wwd == null)
throw new Exception("wwd == null");
if (!wwd.getMemoryCacheSet().containsCache(BUFFERED_IMAGE_CACHE_NAME))
{
long size = Configuration.getLongValue(BUFFERED_IMAGE_CACHE_SIZE, DEFAULT_BUFFERED_IMAGE_CACHE_SIZE);
MemoryCache cache = new BasicMemoryCache((long) (0.85 * size), size);
wwd.getMemoryCacheSet().addCache(BUFFERED_IMAGE_CACHE_NAME, cache);
}
this.initializeSlideShow();
}
protected void initializeSlideShow() throws Exception
{
SlideShowAnnotation annotation = (SlideShowAnnotation) this.getAnnotation();
// Set the image preferred size.
this.setPreferredImageSize(SMALL_IMAGE_PREFERRED_SIZE);
if (this.imageSources.size() <= 1)
{
annotation.getPlayButton().getAttributes().setVisible(false);
annotation.getPreviousButton().getAttributes().setVisible(false);
annotation.getNextButton().getAttributes().setVisible(false);
annotation.getBeginButton().getAttributes().setVisible(false);
annotation.getEndButton().getAttributes().setVisible(false);
}
if (!this.imageSources.isEmpty())
{
// Load the first image.
this.doGoToImage(0);
}
}
public java.util.List<? extends Object> getImageSources()
{
return java.util.Collections.unmodifiableList(this.imageSources);
}
public void setImageSources(Iterable<? extends Object> imageSources)
{
this.imageSources.clear();
if (imageSources != null)
{
for (Object source : imageSources)
{
if (source != null)
this.imageSources.add(source);
}
}
}
public String getState()
{
return this.state;
}
public int getIndex()
{
return this.index;
}
@SuppressWarnings(
{
"StringEquality"
})
public void goToImage(int index) throws Exception
{
if (this.getAnnotation() == null)
return;
if (this.getState() == AVKey.PLAY)
{
this.stopSlideShow();
}
this.doGoToImage(index);
}
@SuppressWarnings(
{
"StringEquality"
})
public void startSlideShow()
{
if (this.getAnnotation() == null)
return;
if (this.hasNextIndex() && this.getState() == AVKey.STOP)
{
this.state = AVKey.PLAY;
SlideShowAnnotation slideShowAnnotation = (SlideShowAnnotation) this.getAnnotation();
slideShowAnnotation.setPlayButtonState(AVKey.PAUSE);
this.startSlideShowUpdate();
}
}
@SuppressWarnings(
{
"StringEquality"
})
public void stopSlideShow()
{
if (this.getAnnotation() == null)
return;
if (this.getState() == AVKey.PLAY)
{
this.state = AVKey.STOP;
SlideShowAnnotation slideShowAnnotation = (SlideShowAnnotation) this.getAnnotation();
slideShowAnnotation.setPlayButtonState(AVKey.PLAY);
this.stopSlideShowUpdate();
}
}
public void stopRetrievalTasks()
{
this.stopImageRetrieval();
}
public java.awt.Dimension getPreferredImageSize()
{
if (this.getAnnotation() == null)
return null;
SlideShowAnnotation slideShowAnnotation = (SlideShowAnnotation) this.getAnnotation();
return slideShowAnnotation.getImageAnnotation().getAttributes().getSize();
}
public void setPreferredImageSize(java.awt.Dimension size)
{
if (this.getAnnotation() == null)
return;
SlideShowAnnotation slideShowAnnotation = (SlideShowAnnotation) this.getAnnotation();
slideShowAnnotation.getImageAnnotation().getAttributes().setSize(size);
}
protected boolean hasPreviousIndex()
{
// The slide show loops, so there's always a previous index.
return true;
}
protected boolean hasNextIndex()
{
// The slide show loops, so there's always a next index.
return true;
}
protected int getPreviousIndex()
{
int maxIndex = this.imageSources.size() - 1;
return (this.index > 0) ? (this.index - 1) : maxIndex;
}
protected int getNextIndex()
{
int maxIndex = this.imageSources.size() - 1;
return (this.index < maxIndex) ? (this.index + 1) : 0;
}
protected void doGoToImage(int index) throws Exception
{
int maxIndex = this.imageSources.size() - 1;
if (index < 0 || index > maxIndex)
return;
if (index == this.index)
return;
this.retrieveAndSetImage(this.imageSources.get(index), index);
}
protected void doSetImage(PowerOfTwoPaddedImage image, int index)
{
int length = this.imageSources.size();
Object imageSource = this.imageSources.get(index);
String title = this.createTitle(imageSource);
String positionText = this.createPositionText(index, length);
this.index = index;
SlideShowAnnotation slideShowAnnotation = (SlideShowAnnotation) this.getAnnotation();
slideShowAnnotation.getTitleLabel().setText(title);
slideShowAnnotation.getPositionLabel().setText(positionText);
slideShowAnnotation.getImageAnnotation().setImageSource(image.getPowerOfTwoImage(),
image.getOriginalWidth(), image.getOriginalHeight());
// Update next and previous button states.
slideShowAnnotation.getBeginButton().setEnabled(this.hasPreviousIndex());
slideShowAnnotation.getPreviousButton().setEnabled(this.hasPreviousIndex());
slideShowAnnotation.getNextButton().setEnabled(this.hasNextIndex());
slideShowAnnotation.getEndButton().setEnabled(this.hasNextIndex());
this.getWorldWindow().redraw();
}
//**************************************************************//
//******************** Action Listener ***********************//
//**************************************************************//
@SuppressWarnings(
{
"StringEquality"
})
@Override
public void onActionPerformed(java.awt.event.ActionEvent e)
{
super.onActionPerformed(e);
try
{
if (e.getActionCommand() == AVKey.PLAY)
{
this.playPressed(e);
}
else if (e.getActionCommand() == AVKey.PREVIOUS)
{
this.previousPressed(e);
}
else if (e.getActionCommand() == AVKey.NEXT)
{
this.nextPressed(e);
}
else if (e.getActionCommand() == AVKey.BEGIN)
{
this.beginPressed(e);
}
else if (e.getActionCommand() == AVKey.END)
{
this.endPressed(e);
}
else if (e.getActionCommand() == AVKey.RESIZE)
{
this.resizePressed(e);
}
}
catch (Exception exc)
{
exc.printStackTrace();
String strWarning = exc.getMessage();
// TODO: log
//--
strWarning = GfrUtlString.s_formatExceptionMessageForDialog(strWarning);
JOptionPane.showMessageDialog(
null,
strWarning,
GfrResBundleLang.s_getInstance().getValue("word.error"),
JOptionPane.ERROR_MESSAGE);
}
}
protected void playPressed(java.awt.event.ActionEvent e)
{
if (e == null)
return;
if (this.getAnnotation() == null)
return;
this.onPlayPressed(e);
}
protected void previousPressed(java.awt.event.ActionEvent e) throws Exception
{
if (e == null)
return;
if (this.getAnnotation() == null)
return;
this.onPreviousPressed(e);
}
protected void nextPressed(java.awt.event.ActionEvent e) throws Exception
{
if (e == null)
return;
if (this.getAnnotation() == null)
return;
this.onNextPressed(e);
}
protected void beginPressed(java.awt.event.ActionEvent e) throws Exception
{
if (e == null)
return;
if (this.getAnnotation() == null)
return;
this.onBeginPressed(e);
}
protected void endPressed(java.awt.event.ActionEvent e) throws Exception
{
if (e == null)
return;
if (this.getAnnotation() == null)
return;
this.onEndPressed(e);
}
protected void resizePressed(java.awt.event.ActionEvent e)
{
if (e == null)
return;
if (this.getAnnotation() == null)
return;
this.onResizePressed(e);
}
@SuppressWarnings(
{
"UnusedDeclaration", "StringEquality"
})
protected void onPlayPressed(java.awt.event.ActionEvent e)
{
String state = this.getState();
if (state == null)
return;
if (state == AVKey.PLAY)
{
this.stopSlideShow();
}
else if (state == AVKey.STOP)
{
this.startSlideShow();
}
}
@SuppressWarnings(
{
"UnusedDeclaration"
})
protected void onPreviousPressed(java.awt.event.ActionEvent e) throws Exception
{
if (!this.hasPreviousIndex())
return;
int newIndex = this.getPreviousIndex();
this.goToImage(newIndex);
}
@SuppressWarnings(
{
"UnusedDeclaration"
})
protected void onNextPressed(java.awt.event.ActionEvent e) throws Exception
{
if (!this.hasNextIndex())
return;
int newIndex = this.getNextIndex();
this.goToImage(newIndex);
}
@SuppressWarnings(
{
"UnusedDeclaration"
})
protected void onBeginPressed(java.awt.event.ActionEvent e) throws Exception
{
this.goToImage(0);
}
@SuppressWarnings(
{
"UnusedDeclaration"
})
protected void onEndPressed(java.awt.event.ActionEvent e) throws Exception
{
int maxIndex = this.imageSources.size() - 1;
if (maxIndex < 0)
return;
this.goToImage(maxIndex);
}
@SuppressWarnings(
{
"UnusedDeclaration"
})
protected void onResizePressed(java.awt.event.ActionEvent e)
{
if (this.getAnnotation() == null)
return;
java.awt.Dimension preferredSize = this.getPreferredImageSize();
if (preferredSize.equals(SMALL_IMAGE_PREFERRED_SIZE))
{
this.setPreferredImageSize(LARGE_IMAGE_PREFERRED_SIZE);
SlideShowAnnotation slideShowAnnotation = (SlideShowAnnotation) this.getAnnotation();
slideShowAnnotation.setSizeButtonState(SlideShowAnnotation.DECREASE);
}
else
{
this.setPreferredImageSize(SMALL_IMAGE_PREFERRED_SIZE);
SlideShowAnnotation slideShowAnnotation = (SlideShowAnnotation) this.getAnnotation();
slideShowAnnotation.setSizeButtonState(SlideShowAnnotation.INCREASE);
}
}
//**************************************************************//
//******************** Image Load Thread *********************//
//**************************************************************//
protected void retrieveAndSetImage(Object source, int index) throws Exception
{
PowerOfTwoPaddedImage image = this.getImage(source);
if (image != null)
{
this.doSetImage(image, index);
return;
}
this.startImageRetrieval(source, index);
}
protected void doRetrieveAndSetImage(Object source, final int index) throws Exception
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
if (updateTimer != null)
{
updateTimer.stop();
}
getAnnotation().setBusy(true);
getWorldWindow().redraw();
}
});
final PowerOfTwoPaddedImage image = this.readImage(source);
this.putImage(source, image);
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
doSetImage(image, index);
getAnnotation().setBusy(false);
getWorldWindow().redraw();
if (updateTimer != null)
{
updateTimer.start();
}
}
});
}
protected PowerOfTwoPaddedImage readImage(Object source)
{
try
{
if (source instanceof BufferedImage)
{
return PowerOfTwoPaddedImage.fromBufferedImage((BufferedImage) source);
}
else if (source instanceof String)
{
return PowerOfTwoPaddedImage.fromPath((String) source);
}
else if (source instanceof URL)
{
return PowerOfTwoPaddedImage.fromBufferedImage(ImageIO.read((URL) source));
}
else
{
String message = Logging.getMessage("generic.UnrecognizedSourceType", source);
Logging.logger().severe(message);
}
}
catch (IOException e)
{
String message = Logging.getMessage("generic.ExceptionAttemptingToReadFrom", source);
Logging.logger().severe(message);
}
return null;
}
protected void startImageRetrieval(final Object source, final int index)
{
this.readThread = new Thread(new Runnable()
{
@Override
public void run()
{
try
{
doRetrieveAndSetImage(source, index);
}
catch (Exception exc)
{
exc.printStackTrace();
String strWarning = exc.getMessage();
// TODO: log
//--
strWarning = GfrUtlString.s_formatExceptionMessageForDialog(strWarning);
JOptionPane.showMessageDialog(
null,
strWarning,
GfrResBundleLang.s_getInstance().getValue("word.error"),
JOptionPane.ERROR_MESSAGE);
}
}
});
this.readThread.start();
}
protected void stopImageRetrieval()
{
if (this.readThread != null)
{
if (this.readThread.isAlive())
{
this.readThread.interrupt();
}
}
this.readThread = null;
}
protected PowerOfTwoPaddedImage getImage(Object source) throws Exception
{
WorldWind wwd = WorldWind.getInstance();
if (wwd == null)
throw new Exception("wwd == null");
return (PowerOfTwoPaddedImage) wwd.getMemoryCache(BUFFERED_IMAGE_CACHE_NAME).getObject(source);
}
protected boolean putImage(Object source, PowerOfTwoPaddedImage image) throws Exception
{
long sizeInBytes = ImageUtil.computeSizeInBytes(image.getPowerOfTwoImage());
WorldWind wwd = WorldWind.getInstance();
if (wwd == null)
throw new Exception("wwd == null");
MemoryCache cache = wwd.getMemoryCache(BUFFERED_IMAGE_CACHE_NAME);
boolean addToCache = (sizeInBytes < cache.getCapacity());
// If the image is too large for the cache, then do not add it to the cache.
if (addToCache)
{
cache.add(source, image, sizeInBytes);
}
return addToCache;
}
//**************************************************************//
//******************** Slideshow Update Timer *******************//
//**************************************************************//
protected boolean nextSlideShowImage() throws Exception
{
if (this.getAnnotation() == null)
return false;
if (this.hasNextIndex())
{
int newIndex = this.getNextIndex();
this.doGoToImage(newIndex);
}
return this.hasNextIndex();
}
protected void onSlideShowUpdate() throws Exception
{
if (!this.nextSlideShowImage())
{
this.stopSlideShow();
}
}
protected void startSlideShowUpdate()
{
this.updateTimer = new javax.swing.Timer((int) SLIDESHOW_UPDATE_DELAY_MILLIS,
new java.awt.event.ActionListener()
{
@Override
public void actionPerformed(java.awt.event.ActionEvent actionEvent)
{
try
{
onSlideShowUpdate();
}
catch (Exception exc)
{
exc.printStackTrace();
String strWarning = exc.getMessage();
// TODO: log
//--
strWarning = GfrUtlString.s_formatExceptionMessageForDialog(strWarning);
JOptionPane.showMessageDialog(
null,
strWarning,
GfrResBundleLang.s_getInstance().getValue("word.error"),
JOptionPane.ERROR_MESSAGE);
}
}
});
// Coalesce timer events, so that an image load delay on the timer thread does not cause slide transition
// events to bunch up.
this.updateTimer.setCoalesce(true);
this.updateTimer.start();
}
protected void stopSlideShowUpdate()
{
if (this.updateTimer != null)
{
this.updateTimer.stop();
}
this.updateTimer = null;
}
//**************************************************************//
//******************** Utilities *****************************//
//**************************************************************//
protected String createTitle(Object imageSource)
{
String strPathAbsSource = (String) imageSource;
String imageName = this._mapSourceToTitle_.get(strPathAbsSource);
//this.TO_REMOVE_getImageName(imageSource);
return (imageName != null) ? imageName : "";
}
protected String createPositionText(int position, int length)
{
if (length <= 1)
return "";
StringBuilder sb = new StringBuilder();
sb.append(position + 1).append(" of ").append(length);
return sb.toString();
}
/*protected String TO_REMOVE_getImageName(Object imageSource)
{
if (imageSource == null)
return null;
String s = imageSource.toString();
s = WWIO.stripTrailingSeparator(s);
int index = s.lastIndexOf("/");
if (index == -1)
index = s.lastIndexOf("\\");
if (index != -1 && index < s.length() - 1)
{
s = s.substring(index + 1, s.length());
}
return s;
}*/
}