/* This file is part of Eternity II Editor.
*
* Eternity II Editor is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Eternity II Editor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Eternity II Editor. If not, see <http://www.gnu.org/licenses/>.
*
* Eternity II Editor project is hosted on SourceForge:
* http://sourceforge.net/projects/eternityii/
* and maintained by Yannick Kirschhoffer <alcibiade@alcibiade.org>
*/
package org.alcibiade.eternity.editor.gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;
import org.alcibiade.eternity.editor.log.DocumentLog;
import org.alcibiade.eternity.editor.model.GridModel;
import org.alcibiade.eternity.editor.model.GridScoreRecorder;
import org.alcibiade.eternity.editor.solver.ClusterListener;
import org.alcibiade.eternity.editor.solver.ClusterManager;
import org.alcibiade.eternity.editor.solver.EternitySolver;
import org.alcibiade.eternity.editor.solver.SolverFactory;
import org.alcibiade.eternity.editor.solver.SolverObserver;
import org.alcibiade.eternity.editor.solver.UnknownSolverException;
import org.alcibiade.eternity.editor.solver.path.PathFactory;
import org.alcibiade.eternity.editor.solver.path.PathProvider;
import org.alcibiade.eternity.editor.solver.path.UnknownPathException;
public class SolverManager extends JPanel implements ActionListener, SolverObserver, ItemListener,
ClusterListener {
private static final String LABEL_GO = "Start";
private static final String LABEL_INT = "Interrupt";
private static final boolean displayGraph = false;
private static final long serialVersionUID = 1L;
private JCheckBox solverslowmotion;
private JCheckBox updateMainGrid;
private JButton button = new JButton(LABEL_GO);
private Document solLog;
private JComboBox solversCombo;
private JComboBox pathsCombo;
private ClusterManager clusterManager = null;
private EternitySolver solver = null;
private GridView gridView;
private GridModel problemGrid;
private GridModel solutionGrid;
public SolverManager(GridView gridView) {
this.gridView = gridView;
GridModel grid = gridView.getGridModel();
problemGrid = grid;
solutionGrid = new GridModel(grid.getSize());
solversCombo = new JComboBox(new SolverComboBoxModel());
pathsCombo = new JComboBox(new PathComboBoxModel());
solversCombo.addItemListener(this);
setLayout(new BorderLayout());
button.addActionListener(this);
solLog = new PlainDocument();
JTextArea ta_log = new JTextArea(solLog);
ta_log.setEditable(false);
solLog.addDocumentListener(new Autoscroller(ta_log));
JScrollPane sp_log = new JScrollPane(ta_log);
sp_log.setPreferredSize(new Dimension(100, 100));
GridView gridview = new GridView(solutionGrid);
gridview.setPreferredSize(new Dimension(300, 300));
gridview.setEditable(false);
JPanel solverbuttons = new JPanel(new GridLayout());
solverbuttons.add(button);
solverslowmotion = new JCheckBox("Slow motion", false);
solverslowmotion.addActionListener(this);
updateMainGrid = new JCheckBox("Update main grid", false);
JPanel items_north = new JPanel();
items_north.setLayout(new BoxLayout(items_north, BoxLayout.PAGE_AXIS));
JPanel items_south = new JPanel();
items_south.setLayout(new BoxLayout(items_south, BoxLayout.PAGE_AXIS));
items_north.add(gridview);
if (displayGraph) {
GridScoreRecorder recorder = new GridScoreRecorder(solutionGrid);
GridScoreGraph scoregraph = new GridScoreGraph(recorder);
scoregraph.setPreferredSize(new Dimension(300, 100));
recorder.start();
items_north.add(scoregraph);
}
JPanel switches = new JPanel(new GridLayout(1, 2));
switches.add(solverslowmotion);
switches.add(updateMainGrid);
items_north.add(solversCombo);
items_north.add(pathsCombo);
items_south.add(switches);
items_south.add(solverbuttons);
add(BorderLayout.NORTH, items_north);
add(BorderLayout.CENTER, sp_log);
add(BorderLayout.SOUTH, items_south);
setBorder(BorderFactory.createCompoundBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Solver"), BorderFactory.createEmptyBorder(15, 15,
15, 15)), getBorder()));
}
public synchronized void actionPerformed(ActionEvent e) {
Object src = e.getSource();
if (src == solverslowmotion) {
if (solver != null) {
solver.setSlowMotion(solverslowmotion.isSelected());
}
} else {
if (solver != null) {
stopSolver();
} else {
startSolver();
}
}
}
public synchronized void startSolver() {
String selectedsolver = (String) solversCombo.getSelectedItem();
String selectedPath = (String) pathsCombo.getSelectedItem();
try {
if (selectedsolver != null) {
PathProvider path = PathFactory.createPath(selectedPath);
clusterManager = new ClusterManager(new DocumentLog(solLog));
clusterManager.addClusterListener(this);
solver = SolverFactory.createSolver(selectedsolver, problemGrid, solutionGrid,
clusterManager, path);
}
gridView.setEditable(false);
button.setText(LABEL_INT);
solver.addSolverObserver(this);
solver.setSlowMotion(solverslowmotion.isSelected());
solver.start();
} catch (UnknownSolverException e) {
e.printStackTrace();
} catch (UnknownPathException e) {
e.printStackTrace();
}
}
public synchronized void stopSolver() {
solver.interrupt();
solver = null;
}
private class SolverComboBoxModel extends DefaultComboBoxModel {
private static final long serialVersionUID = 1L;
public SolverComboBoxModel() {
for (String solver : SolverFactory.getAvailableSolvers()) {
addElement(solver);
}
}
}
private class PathComboBoxModel extends DefaultComboBoxModel {
private static final long serialVersionUID = 1L;
public PathComboBoxModel() {
for (String path : PathFactory.getAvailablePaths()) {
addElement(path);
}
}
}
/*
* (non-Javadoc)
*
* @see
* org.alcibiade.eternity.editor.solver.ClusterListener#bestSolutionUpdated
* ()
*/
public void bestSolutionUpdated(int bestScore) {
if (updateMainGrid.isSelected()) {
clusterManager.getBestSolution().copyTo(problemGrid);
}
}
/*
* (non-Javadoc)
*
* @see
* org.alcibiade.eternity.editor.solver.SolverObserver#solverEnded(boolean)
*/
public void solverEnded(boolean success) {
button.setText(LABEL_GO);
solver = null;
gridView.setEditable(true);
}
/*
* (non-Javadoc)
*
* @see org.alcibiade.eternity.editor.solver.SolverObserver#solverStarted()
*/
public void solverStarted() {
// Nothing to do.
}
/*
* (non-Javadoc)
*
* @see
* java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
*/
public void itemStateChanged(ItemEvent e) {
String selectedsolver = (String) solversCombo.getSelectedItem();
pathsCombo.setEnabled(SolverFactory.isSolverPathSensitive(selectedsolver));
}
}