/* Copyright (C) 2001, 2007 United States Government as represented by
the Administrator of the National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.layers.rpf.wizard;
import gov.nasa.worldwind.layers.Layer;
import gov.nasa.worldwind.layers.rpf.RPFTiledImageProcessor;
import gov.nasa.worldwind.layers.rpf.RPFFileIndex;
import gov.nasa.worldwind.util.Logging;
import gov.nasa.worldwind.util.wizard.DefaultPanelDescriptor;
import gov.nasa.worldwind.util.wizard.Wizard;
import gov.nasa.worldwind.util.wizard.WizardModel;
import gov.nasa.worldwind.Configuration;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author dcollins
* @version $Id: PreprocessPanelDescriptor.java 4857 2008-03-29 01:11:08Z dcollins $
*/
public class PreprocessPanelDescriptor extends DefaultPanelDescriptor
{
private ProgressPanel panelComponent;
// Preprocessor logical components.
private RPFTiledImageProcessor preprocessor;
private Thread workerThread;
// Preprocessing state display components.
private int numSteps;
private final AtomicInteger stepsTaken = new AtomicInteger(0);
private final AtomicInteger stepsWithErrors = new AtomicInteger(0);
private final ETRCalculator etrCalc = new ETRCalculator();
public static final String IDENTIFIER = "gov.nasa.worldwind.rpf.wizard.PreprocessPanel";
public static final String THREAD_POOL_SIZE = "gov.nasa.worldwind.rpf.wizard.ThreadPoolSize";
public static final String STEPS_NEEDED_FOR_ESTIMATE = "gov.nasa.worldwind.rpf.wizard.StepsNeededForEstimate";
private static final int DEFAULT_THREAD_POOL_SIZE = 3;
private static final int DEFAULT_STEPS_NEEDED_FOR_ESTIMATE = 20;
public PreprocessPanelDescriptor()
{
// Get preprocessor thread pool size, and num steps needed for ETR
// from Configuration. Provide suitable defaults if these values
// aren't specified.
int threadPoolSize = Configuration.getIntegerValue(THREAD_POOL_SIZE, DEFAULT_THREAD_POOL_SIZE);
int stepsNeededForEst = Configuration.getIntegerValue(STEPS_NEEDED_FOR_ESTIMATE,
DEFAULT_STEPS_NEEDED_FOR_ESTIMATE);
this.panelComponent = new ProgressPanel();
this.preprocessor = new RPFTiledImageProcessor();
this.preprocessor.setThreadPoolSize(threadPoolSize);
this.preprocessor.addPropertyChangeListener(new PropertyEvents());
this.etrCalc.setStepsNeededForEstimate(stepsNeededForEst);
setPanelIdentifier(IDENTIFIER);
setPanelComponent(this.panelComponent);
}
public Object getBackPanelDescriptor()
{
return null;
}
public Object getNextPanelDescriptor()
{
return Wizard.FINISH;
}
public void aboutToDisplayPanel()
{
this.panelComponent.getProgressBar().setMinimum(0);
this.panelComponent.getProgressBar().setMaximum(0);
this.panelComponent.getProgressBar().setValue(0);
this.panelComponent.setProgressDescription1(" ");
this.panelComponent.setProgressDescription2(" ");
}
public void displayingPanel()
{
WizardModel model = getWizardModel();
final Iterable<FileSet> fileSetList = RPFWizardUtil.getFileSetList(model);
final File selectedFile = RPFWizardUtil.getSelectedFile(model);
if (fileSetList != null && selectedFile != null)
{
this.panelComponent.setTitle(RPFWizardUtil.makeLarger("Importing Imagery"));
this.panelComponent.setDescription("");
this.panelComponent.getProgressBar().setVisible(true);
if (model != null)
{
model.setNextButtonEnabled(false);
}
startWorkerThread(new Runnable() {
public void run() {
List<FileSet> selectedSets = new ArrayList<FileSet>();
for (FileSet set : fileSetList) {
if (set.isSelected()) {
selectedSets.add(set);
}
}
for (int i = 0; i < selectedSets.size(); i++) {
FileSet set = selectedSets.get(i);
preprocess(selectedFile, set, i + 1, selectedSets.size());
}
finished();
}
});
}
else
{
this.panelComponent.setTitle(RPFWizardUtil.makeLarger("No Imagery to Import"));
this.panelComponent.setDescription("No Imagery");
this.panelComponent.getProgressBar().setVisible(false);
}
}
public void aboutToHidePanel()
{
Wizard wizard = getWizard();
if (wizard != null && wizard.getReturnCode() == Wizard.FINISH_RETURN_CODE)
{
// "Finish" button pressed.
}
else
{
// "<Back" or "Cancel" button pressed, or window closed.
if (this.preprocessor != null)
this.preprocessor.stop();
}
}
private void preprocess(File inFile, FileSet set, int setNumber, int numSets)
{
long startTime = System.currentTimeMillis();
RPFFileIndex fileIndex = null;
Layer layer = null;
try
{
String descr = makeDescription(set, setNumber, numSets);
if (inFile != null && set != null)
{
String subDescr = makeSubStepDescription(descr, "Processing Image Files");
this.panelComponent.setDescription(RPFWizardUtil.makeBold(subDescr));
fileIndex = this.preprocessor.makeFileIndex(inFile, set.getIdentifier(), set.getTitle(), set.getFiles());
set.setProperty("filesProcessed", this.stepsTaken.intValue());
set.setProperty("filesWithErrors", this.stepsWithErrors.intValue());
}
if (fileIndex != null)
{
String subDescr = makeSubStepDescription(descr, "Generating Overview Imagery");
this.panelComponent.setDescription(RPFWizardUtil.makeBold(subDescr));
layer = this.preprocessor.makeLayer(fileIndex);
}
}
catch (Exception e)
{
String message = "Exception while preprocessing: " + (set != null ? set.getTitle() : "null");
Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
layer = null;
}
WizardModel model = getWizardModel();
if (layer != null && model != null)
{
List<Layer> layerList = RPFWizardUtil.getLayerList(model);
if (layerList == null)
{
layerList = new ArrayList<Layer>();
RPFWizardUtil.setLayerList(model, layerList);
}
layerList.add(layer);
}
long endTime = System.currentTimeMillis();
String message = String.format("Preprocessor completed \'%s\' in %,d (millis)", (set != null ? set.getTitle() : "null"), endTime - startTime);
Logging.logger().fine(message);
}
private void finished()
{
this.panelComponent.setTitle(RPFWizardUtil.makeLarger("Finished"));
this.panelComponent.setDescription(makeFinishedDescription());
this.panelComponent.getProgressBar().setMinimum(0);
this.panelComponent.getProgressBar().setMaximum(0);
this.panelComponent.getProgressBar().setValue(0);
this.panelComponent.getProgressBar().setVisible(false);
this.panelComponent.setProgressDescription1(" ");
this.panelComponent.setProgressDescription2(" ");
WizardModel model = getWizardModel();
if (model != null)
{
model.setNextButtonEnabled(true);
}
}
private class PropertyEvents implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
if (evt != null && evt.getPropertyName() != null) {
if (evt.getPropertyName().equals(RPFTiledImageProcessor.BEGIN_SUB_TASK)) {
beginTask();
} else if (evt.getPropertyName().equals(RPFTiledImageProcessor.END_SUB_TASK)) {
endTask();
} else if (evt.getPropertyName().equals(RPFTiledImageProcessor.SUB_TASK_NUM_STEPS)) {
stepsForTask((Integer) evt.getNewValue());
} else if (evt.getPropertyName().equals(RPFTiledImageProcessor.SUB_TASK_STEP_COMPLETE)) {
stepComplete(evt.getNewValue().toString(), true);
} else if (evt.getPropertyName().equals(RPFTiledImageProcessor.SUB_TASK_STEP_FAILED)) {
stepComplete(evt.getNewValue().toString(), false);
}
}
}
}
private void beginTask()
{
this.stepsTaken.set(0);
this.stepsWithErrors.set(0);
this.etrCalc.setStartTime(System.currentTimeMillis());
}
private void endTask()
{
this.panelComponent.setProgressDescription1(" ");
this.panelComponent.setProgressDescription2(" ");
}
private void stepsForTask(int numSteps)
{
this.numSteps = numSteps;
}
private void stepComplete(String description, boolean success)
{
int n = this.stepsTaken.incrementAndGet();
if (!success)
this.stepsWithErrors.incrementAndGet();
int numFiles = this.numSteps;
this.etrCalc.setStep(n);
this.etrCalc.setNumSteps(numFiles);
long etr = this.etrCalc.getEstimatedTimeRemaining();
StringBuilder sb = new StringBuilder();
sb.append(description);
int nErrors = this.stepsWithErrors.get();
if (nErrors > 0)
{
if (sb.length() > 0)
sb.append("; ");
sb.append(formatFileCount(nErrors)).append(" with errors");
}
setProgressMessage(sb.toString());
setProgress(n, numFiles, etr);
}
private void setProgress(int progressValue, int progressRange, long remainingMillis)
{
if (progressValue >= 0 && progressValue < progressRange)
{
this.panelComponent.getProgressBar().setValue(progressValue);
this.panelComponent.getProgressBar().setMaximum(progressRange);
StringBuilder sb = new StringBuilder();
sb.append(String.format("%,d of %,d", progressValue, progressRange));
if (remainingMillis > 0)
{
TimeFormatter tf = new TimeFormatter();
if (sb.length() > 0)
sb.append(" - ");
sb.append(tf.formatEstimate(remainingMillis));
}
this.panelComponent.setProgressDescription2(sb.toString());
}
else
{
this.panelComponent.getProgressBar().setValue(0);
this.panelComponent.getProgressBar().setMaximum(0);
this.panelComponent.setProgressDescription2(" ");
}
}
private void setProgressMessage(String message)
{
this.panelComponent.setProgressDescription1(message);
}
private String formatFileCount(int n)
{
StringBuilder sb = new StringBuilder();
sb.append(String.format("%,d", n));
sb.append(" file");
if (n != 1)
sb.append("s");
return sb.toString();
}
private String makeDescription(FileSet set, int value, int max)
{
StringBuilder sb = new StringBuilder();
sb.append("Importing ");
if (set != null && set.getTitle() != null)
{
sb.append("\'");
sb.append(set.getTitle());
sb.append("\'");
}
if (max > 1)
{
sb.append(" (").append(value).append(" of ").append(max).append(")");
}
return sb.toString();
}
private String makeSubStepDescription(String description, String subDescription)
{
StringBuilder sb = new StringBuilder();
sb.append("<br>");
sb.append(description);
sb.append("<br><br><br>");
sb.append(subDescription);
return sb.toString();
}
private String makeFinishedDescription()
{
StringBuilder sb = new StringBuilder();
sb.append("<html>");
sb.append("<br>");
sb.append("<font size=\"+1\">");
sb.append("Import Imagery Complete");
sb.append("</font>");
sb.append("<br><br>");
WizardModel model = getWizardModel();
Iterable<FileSet> fileSetList = RPFWizardUtil.getFileSetList(model);
if (fileSetList != null)
{
for (FileSet set : fileSetList)
{
if (set != null && set.isSelected())
{
sb.append("<b>");
sb.append(set.getTitle());
sb.append("</b>");
Integer filesProcessed = set.getIntegerProperty("filesProcessed");
Integer filesWithErrors = set.getIntegerProperty("filesWithErrors");
if (filesProcessed != null && filesWithErrors != null)
{
int numFilesOk = filesProcessed - filesWithErrors;
sb.append("<br>");
sb.append("<font size=\"-2\">");
sb.append(formatFileCount(numFilesOk)).append(" imported");
if (filesWithErrors > 0)
{
sb.append("; ");
sb.append("<font color=#990000>");
sb.append(formatFileCount(filesWithErrors)).append(" with errors");
sb.append("</font>");
}
sb.append("</font>");
}
sb.append("<br><br>");
}
}
}
sb.append("</html>");
return sb.toString();
}
private void startWorkerThread(Runnable runnable)
{
killWorkerThread();
this.workerThread = new Thread(runnable);
this.workerThread.start();
}
private void killWorkerThread()
{
if (this.workerThread != null && this.workerThread.isAlive())
this.workerThread.interrupt();
this.workerThread = null;
}
}