//=============================================================================
// Copyright 2006-2010 Daniel W. Dyer
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//=============================================================================
package org.uncommons.watchmaker.swing.evolutionmonitor;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import org.uncommons.watchmaker.framework.PopulationData;
import org.uncommons.watchmaker.framework.islands.IslandEvolutionObserver;
/**
* Status bar component for the evolution monitor. Can also be used separately to
* provide basic status information without having to use the full evolution monitor.
* @author Daniel Dyer
*/
public class StatusBar extends Box implements IslandEvolutionObserver<Object>
{
private final JLabel generationsLabel = new JLabel("N/A", JLabel.RIGHT);
private final JLabel timeLabel = new JLabel("N/A", JLabel.RIGHT);
private final JLabel populationLabel = new JLabel("N/A", JLabel.RIGHT);
private final JLabel elitismLabel = new JLabel("N/A", JLabel.RIGHT);
private final AtomicInteger islandPopulationSize = new AtomicInteger(-1);
private long elapsedTime;
private long epochTime;
/**
* Creates a status bar configured for non-island evolution.
*/
public StatusBar()
{
this(false);
}
/**
* @param islands Whether the status bar should be configured for updates from
* {@link org.uncommons.watchmaker.framework.islands.IslandEvolution}. Set this
* parameter to false when using a standard {@link org.uncommons.watchmaker.framework.EvolutionEngine}
*/
public StatusBar(boolean islands)
{
super(BoxLayout.X_AXIS);
add(new JLabel("Population: "));
add(populationLabel);
add(createHorizontalStrut(15));
add(new JLabel("Elitism: "));
add(elitismLabel);
add(createHorizontalStrut(15));
add(new JLabel(islands ? "Epochs: " : "Generations: "));
add(generationsLabel);
add(createHorizontalStrut(15));
add(new JLabel("Elapsed Time: "));
add(timeLabel);
setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
// Set component names for easy look-up from tests.
populationLabel.setName("Population");
elitismLabel.setName("Elitism");
generationsLabel.setName("Generations");
timeLabel.setName("Time");
}
/**
* {@inheritDoc}
*/
public void populationUpdate(final PopulationData<?> populationData)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
if (populationData.getGenerationNumber() == 0)
{
int islandSize = islandPopulationSize.get();
if (islandSize > 0)
{
int islandCount = populationData.getPopulationSize() / islandSize;
populationLabel.setText(islandCount + "x" + islandSize);
elitismLabel.setText(islandCount + "x" + populationData.getEliteCount());
}
else
{
populationLabel.setText(String.valueOf(populationData.getPopulationSize()));
elitismLabel.setText(String.valueOf(populationData.getEliteCount()));
}
}
generationsLabel.setText(String.valueOf(populationData.getGenerationNumber() + 1));
elapsedTime = populationData.getElapsedTime();
epochTime = 0;
timeLabel.setText(formatTime(elapsedTime));
}
});
}
/**
* {@inheritDoc}
*/
public void islandPopulationUpdate(int islandIndex,
final PopulationData<? extends Object> populationData)
{
islandPopulationSize.compareAndSet(-1, populationData.getPopulationSize());
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
// Only update the label if the time has advanced. Sometimes, due to threading
// variations, later updates have shorter elapsed times.
if (populationData.getElapsedTime() > epochTime)
{
epochTime = populationData.getElapsedTime();
timeLabel.setText(formatTime(elapsedTime + epochTime));
}
}
});
}
private String formatTime(long time)
{
long seconds = time / 1000;
long minutes = seconds / 60;
seconds %= 60;
long hours = minutes / 60;
minutes %= 60;
StringBuilder buffer = new StringBuilder();
if (hours < 10)
{
buffer.append('0');
}
buffer.append(hours);
buffer.append(':');
if (minutes < 10)
{
buffer.append('0');
}
buffer.append(minutes);
buffer.append(':');
if (seconds < 10)
{
buffer.append('0');
}
buffer.append(seconds);
return buffer.toString();
}
}