org.uncommons.watchmaker.swing.evolutionmonitor.EvolutionMonitor.java Source code

Java tutorial

Introduction

Here is the source code for org.uncommons.watchmaker.swing.evolutionmonitor.EvolutionMonitor.java

Source

//=============================================================================
// 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.awt.BorderLayout;
import java.awt.Window;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.StandardChartTheme;
import org.uncommons.watchmaker.framework.PopulationData;
import org.uncommons.watchmaker.framework.interactive.Renderer;
import org.uncommons.watchmaker.framework.islands.IslandEvolutionObserver;
import org.uncommons.watchmaker.swing.ObjectSwingRenderer;
import org.uncommons.watchmaker.swing.SwingIslandEvolutionObserver;

/**
 * The Evolution Monitor is a component that can be attached to an
 * {@link org.uncommons.watchmaker.framework.EvolutionEngine} to provide
 * real-time information (in a Swing GUI) about the current state of the
 * evolution.
 * @param <T> The type of the evolved entities monitored by this component.
 * @author Daniel Dyer
 */
public class EvolutionMonitor<T> implements IslandEvolutionObserver<T> {
    private final List<IslandEvolutionObserver<? super T>> views = new LinkedList<IslandEvolutionObserver<? super T>>();

    private JComponent monitorComponent;
    private Window window = null;

    private final boolean islands;

    /**
     * <p>Creates an EvolutionMonitor with a single panel that graphs the fitness scores
     * of the population from generation to generation.</p>
     * <p>If you are using {@link org.uncommons.watchmaker.framework.islands.IslandEvolution},
     * use the {@link #EvolutionMonitor(boolean)} constructor instead, to enable island support.</p>
     */
    public EvolutionMonitor() {
        this(false);
    }

    /**
     * Creates an EvolutionMonitor with a single panel that graphs the fitness scores
     * of the population from generation to generation.
     * @param islands Whether the monitor should be configured for displaying data from
     * {@link org.uncommons.watchmaker.framework.islands.IslandEvolution}.  Set this
     * parameter to false when using a standard {@link org.uncommons.watchmaker.framework.EvolutionEngine}
     * or if you don't want to display island-specific data for island evolution.
     */
    public EvolutionMonitor(boolean islands) {
        this(new ObjectSwingRenderer(), islands);
    }

    /**
     * Creates an EvolutionMonitor with a second panel that displays a graphical
     * representation of the fittest candidate in the population.
     * @param renderer Renders a candidate solution as a JComponent.
     * @param islands Whether the monitor should be configured for displaying data from
     * {@link org.uncommons.watchmaker.framework.islands.IslandEvolution}.  Set this
     * parameter to false when using a standard {@link org.uncommons.watchmaker.framework.EvolutionEngine}
     */
    public EvolutionMonitor(final Renderer<? super T, JComponent> renderer, boolean islands) {
        this.islands = islands;
        if (SwingUtilities.isEventDispatchThread()) {
            init(renderer);
        } else {
            try {
                SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        init(renderer);
                    }
                });
            } catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
                throw new IllegalStateException(ex);
            } catch (InvocationTargetException ex) {
                throw new IllegalStateException(ex);
            }
        }
    }

    private void init(Renderer<? super T, JComponent> renderer) {
        // Make sure all JFreeChart charts are created with the legacy theme
        // (grey surround and white data area).
        ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());

        JTabbedPane tabs = new JTabbedPane();
        monitorComponent = new JPanel(new BorderLayout());
        monitorComponent.add(tabs, BorderLayout.CENTER);

        FittestCandidateView<T> candidateView = new FittestCandidateView<T>(renderer);
        tabs.add("Fittest Individual", candidateView);
        views.add(new SwingIslandEvolutionObserver<T>(candidateView, 300, TimeUnit.MILLISECONDS));

        PopulationFitnessView fitnessView = new PopulationFitnessView(islands);
        tabs.add(islands ? "Global Population" : "Population Fitness", fitnessView);
        views.add(fitnessView);

        if (islands) {
            IslandsView islandsView = new IslandsView();
            tabs.add("Island Populations", islandsView);
            views.add(new SwingIslandEvolutionObserver<Object>(islandsView, 300, TimeUnit.MILLISECONDS));
        }

        JVMView jvmView = new JVMView();
        tabs.add("JVM Memory", jvmView);

        StatusBar statusBar = new StatusBar(islands);
        monitorComponent.add(statusBar, BorderLayout.SOUTH);
        views.add(new SwingIslandEvolutionObserver<Object>(statusBar, 300, TimeUnit.MILLISECONDS));
    }

    /**
     * {@inheritDoc}
     */
    public void populationUpdate(PopulationData<? extends T> populationData) {
        for (IslandEvolutionObserver<? super T> view : views) {
            view.populationUpdate(populationData);
        }
    }

    /**
     * {@inheritDoc}
     */
    public void islandPopulationUpdate(int islandIndex, PopulationData<? extends T> populationData) {
        for (IslandEvolutionObserver<? super T> view : views) {
            view.islandPopulationUpdate(islandIndex, populationData);
        }
    }

    public JComponent getGUIComponent() {
        return monitorComponent;
    }

    /**
     * Displays the evolution monitor component in a new {@link JFrame}.  There is no
     * need to make sure this method is invoked from the Event Dispatch Thread, the
     * method itself ensures that the window is created and displayed from the EDT.
     * @param title The title for the new frame.
     * @param exitOnClose Whether the JVM should exit when the frame is closed.  Useful
     * if this is the only application window.
     */
    public void showInFrame(final String title, final boolean exitOnClose) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame(title);
                frame.setDefaultCloseOperation(exitOnClose ? JFrame.EXIT_ON_CLOSE : JFrame.DISPOSE_ON_CLOSE);
                showWindow(frame);
            }
        });
    }

    /**
     * Displays the evolution monitor component in a new {@link JDialog}.  There is no
     * need to make sure this method is invoked from the Event Dispatch Thread, the
     * method itself ensures that the window is created and displayed from the EDT.
     * @param owner The owning frame for the new dialog.
     * @param title The title for the new dialog.
     * @param modal Whether the 
     */
    public void showInDialog(final JFrame owner, final String title, final boolean modal) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JDialog dialog = new JDialog(owner, title, modal);
                dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                showWindow(dialog);
            }
        });
    }

    /**
     * Helper method for showing the evolution monitor in a frame or dialog.
     * @param newWindow The frame or dialog used to show the evolution monitor.
     */
    private void showWindow(Window newWindow) {
        if (window != null) {
            window.remove(getGUIComponent());
            window.setVisible(false);
            window.dispose();
            window = null;
        }
        newWindow.add(getGUIComponent(), BorderLayout.CENTER);
        newWindow.pack();
        newWindow.setVisible(true);
        this.window = newWindow;
    }
}