it.unibo.alchemist.boundary.gui.Perspective.java Source code

Java tutorial

Introduction

Here is the source code for it.unibo.alchemist.boundary.gui.Perspective.java

Source

/*
 * Copyright (C) 2010-2014, Danilo Pianini and contributors
 * listed in the project's pom.xml file.
 * 
 * This file is part of Alchemist, and is distributed under the terms of
 * the GNU General Public License, with a linking exception, as described
 * in the file LICENSE in the Alchemist distribution's top directory.
 */
package it.unibo.alchemist.boundary.gui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import it.unibo.alchemist.boundary.gui.UpperBar.Commands;
import it.unibo.alchemist.boundary.gui.effects.JEffectsTab;
import it.unibo.alchemist.boundary.gui.util.GraphicalMonitorFactory;
import it.unibo.alchemist.boundary.interfaces.GraphicalOutputMonitor;
import it.unibo.alchemist.boundary.monitors.Generic2DDisplay;
import it.unibo.alchemist.boundary.monitors.TimeStepMonitor;
import it.unibo.alchemist.core.implementations.Engine;
import it.unibo.alchemist.core.interfaces.Simulation;
import it.unibo.alchemist.core.interfaces.Status;
import org.apache.commons.math3.random.RandomGenerator;
import it.unibo.alchemist.language.EnvironmentBuilder;
import it.unibo.alchemist.language.EnvironmentBuilder.Result;
import it.unibo.alchemist.loader.Loader;
import it.unibo.alchemist.loader.YamlLoader;
import it.unibo.alchemist.model.implementations.times.DoubleTime;
import it.unibo.alchemist.model.interfaces.Environment;

import static it.unibo.alchemist.boundary.l10n.R.getString;

/**
 * @param <T>
 */
public class Perspective<T> extends JPanel implements ChangeListener, ActionListener {

    private static final long serialVersionUID = -6074331788924400019L;
    private static final FileFilter FILE_FILTER = new FileNameExtensionFilter(getString("alchemist_xml"), "xml",
            "yml", "yaml", "YML", "YAML");
    private static final Logger L = LoggerFactory.getLogger(Perspective.class);
    private static final String FILE_NOT_VALID = getString("file_not_valid");
    private static final String RANDOM_REINIT_SUCCESS = getString("random_reinit_success");
    private static final String RANDOM_REINIT_FAILURE = getString("random_reinit_failure");
    private static final String NOT_AN_INTEGER = getString("not_an_integer");
    private static final String NOT_INITIALIZED_YET = getString("not_initialized_yet");

    private final UpperBar bar;

    private File currentDirectory = new File(System.getProperty("user.home"));
    private GraphicalOutputMonitor<T> main;
    @SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "All the random engines provided by Apache are Serializable")
    private RandomGenerator rand;
    private final SimControlPanel scp = SimControlPanel.createControlPanel(null);
    private JEffectsTab<T> effectsTab;
    private transient Simulation<T> sim;
    private final StatusBar status;
    private File fileToLoad;

    /**
     * Builds a new SAPERE perspective.
     */
    public Perspective() {
        super();
        setLayout(new BorderLayout());
        bar = new UpperBar(scp);
        add(bar, BorderLayout.NORTH);
        bar.addActionListener(this);
        bar.addChangeListener(this);
        status = new StatusBar();
        status.setText(getString("perspective"));
        add(status, BorderLayout.SOUTH);
        setMainDisplay(new Generic2DDisplay<T>());
    }

    private void makeEffects() {
        final JEffectsTab<T> effects = new JEffectsTab<>(main, true);
        if (effectsTab != null) {
            bar.deregisterTab(effectsTab);
            effects.setEffects(effectsTab.getEffects());
            effects.setEnabled(effectsTab.isEnabled());
        } else {
            effects.setEnabled(false);
        }
        effectsTab = effects;
        bar.registerTab(effectsTab);
    }

    private void dispose() {
        if (main != null) {
            if (sim != null) {
                sim.removeOutputMonitor(main);
            }
            remove((Component) main);
        }
        main = null;
        sim = null;
        effectsTab = null;
    }

    @Override
    public void actionPerformed(final ActionEvent e) {
        if (Commands.OPEN.equalsToString(e.getActionCommand())) {
            openFile();
        } else if (Commands.PARALLEL.equalsToString(e.getActionCommand())) {
            process(true);
        } else if (Commands.PROCESS.equalsToString(e.getActionCommand())) {
            process(false);
        } else if (Commands.DICE.equalsToString(e.getActionCommand())) {
            setRandom();
        } else if (SimControlCommand.PLAY.equalsToString(e.getActionCommand())) {
            sim.addCommand(new Engine.StateCommand<T>().run().build());
            bar.setPlay(true);
        } else if (SimControlCommand.PAUSE.equalsToString(e.getActionCommand())) {
            sim.addCommand(new Engine.StateCommand<T>().pause().build());
            bar.setPlay(false);
        } else if (SimControlCommand.STEP.equalsToString(e.getActionCommand())) {
            sim.addCommand(new Engine.StateCommand<T>().run().build());
            sim.addCommand(new Engine.StateCommand<T>().pause().build());
        } else if (SimControlCommand.STOP.equalsToString(e.getActionCommand())) {
            sim.addCommand(new Engine.StateCommand<T>().stop().build());
            bar.setFileOK(true);
        } else if (Commands.REACTIVITY.equalsToString(e.getActionCommand())) {
            switch (bar.getReactivityStatus()) {
            case MAX_REACTIVITY:
                main.setStep(1);
                main.setRealTime(false);
                break;
            case REAL_TIME:
                main.setRealTime(true);
                main.setStep(1);
                break;
            case USER_SELECTED:
                main.setStep(bar.getReactivity());
                main.setRealTime(false);
                break;
            default:
                break;
            }
        } else {
            dispose();
        }
    }

    private void createMonitor() {
        final GraphicalOutputMonitor<T> display = GraphicalMonitorFactory.createMonitor(sim,
                e -> L.error("Cannot create monitor", e));
        setMainDisplay(display);
    }

    private void openFile() {
        final JFileChooser fc = new JFileChooser();
        fc.setMultiSelectionEnabled(false);
        fc.setFileFilter(FILE_FILTER);
        fc.setCurrentDirectory(currentDirectory);
        final int returnVal = fc.showOpenDialog(null);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            fileToLoad = fc.getSelectedFile();
            currentDirectory = fc.getSelectedFile().getParentFile();
            if (fileToLoad.exists()) {
                status.setText(getString("ready_to_process") + " " + fileToLoad.getAbsolutePath());
                status.setOK();
                if (sim != null) {
                    sim.addCommand(new Engine.StateCommand<T>().stop().build());
                }
                bar.setFileOK(true);
            } else {
                status.setText(FILE_NOT_VALID + " " + fileToLoad.getAbsolutePath());
                status.setNo();
                bar.setFileOK(false);
            }
        }
    }

    private void process(final boolean parallel) {
        if (sim != null) {
            sim.addCommand(new Engine.StateCommand<T>().stop().build());
            sim.waitFor(Status.STOPPED, 0, TimeUnit.MILLISECONDS);
        }
        try {
            sim = null;
            final Environment<T> env;
            if (fileToLoad.getName().toLowerCase().endsWith("xml")) {
                final Future<Result<T>> fenv = EnvironmentBuilder.build(new FileInputStream(fileToLoad));
                env = fenv.get().getEnvironment();
                rand = fenv.get().getRandomGenerator();
            } else {
                rand = null;
                final Loader loader = new YamlLoader(new FileInputStream(fileToLoad));
                env = loader.getDefault();
            }
            sim = new Engine<>(env, new DoubleTime(Double.POSITIVE_INFINITY), parallel);
            bar.setSimulation(sim);
            scp.setSimulation(sim);
            final Thread simThread = new Thread(sim);
            createMonitor();
            simThread.start();
            final TimeStepMonitor<T> tm = bar.getTimeMonitor();
            sim.addOutputMonitor(tm);
            bar.setFileOK(true);
            bar.setProcessOK(true);
            effectsTab.setEnabled(true);
            status.setOK();
            status.setText(getString("file_processed") + ": " + fileToLoad.getAbsolutePath());
        } catch (Exception e) {
            processError(e);
        }
    }

    private void processError(final Throwable e) {
        SwingUtilities.invokeLater(() -> {
            bar.setFileOK(false);
            bar.setProcessOK(false);
            status.setText(FILE_NOT_VALID + " " + fileToLoad.getAbsolutePath());
            status.setNo();
            L.error("Process error", e);
        });
    }

    private void setMainDisplay(final GraphicalOutputMonitor<T> gom) {
        if (!(gom instanceof Component)) {
            throw new IllegalArgumentException("Java Swing can not load a " + gom);
        }
        final Component gomComp = (Component) gom;
        if (main != null) {
            sim.removeOutputMonitor(main);
            gom.setStep(main.getStep());
            gom.setRealTime(main.isRealTime());
            final Component mainComp = (Component) main;
            gomComp.setSize(mainComp.getSize());
            remove(mainComp);
        } else {
            gomComp.setSize(getSize());
        }
        main = gom;
        add(gomComp, BorderLayout.CENTER);
        revalidate();
        makeEffects();
        if (sim != null) {
            new Thread(() -> sim.addOutputMonitor(main)).start();
        }
    }

    private void setRandom() {
        if (rand != null) {
            try {
                rand.setSeed(bar.getRandomText());
                status.setOK();
                status.setText(RANDOM_REINIT_SUCCESS);
            } catch (final NumberFormatException e) {
                status.setNo();
                status.setText(RANDOM_REINIT_FAILURE + ": " + NOT_AN_INTEGER);
            }
        } else {
            status.setNo();
            status.setText(RANDOM_REINIT_FAILURE + ": RandomGenerator " + NOT_INITIALIZED_YET);
        }
    }

    @Override
    public void stateChanged(final ChangeEvent e) {
        if (bar.getReactivityStatus()
                .equals(it.unibo.alchemist.boundary.gui.ReactivityPanel.Status.USER_SELECTED)) {
            main.setStep(bar.getReactivity());
        }
    }

    @Override
    protected void finalize() throws Throwable {
        if (sim != null) {
            sim.addCommand(new Engine.StateCommand<T>().stop().build());
        }
        super.finalize();
    }

}