/*
* This file is part of MazeSolver.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (c) 2014 MazeSolver
* Sergio M. Afonso Fumero <theSkatrak@gmail.com>
* Kevin I. Robayna Hernández <kevinirobaynahdez@gmail.com>
*/
/**
* @file PATableWidget.java
* @date 25/9/2015
*/
package es.ull.mazesolver.gui.configuration;
import java.awt.BorderLayout;
import java.util.Enumeration;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import es.ull.mazesolver.maze.MazeCell.Vision;
import es.ull.mazesolver.util.Direction;
/**
* Panel de configuración que permite manipular una tabla de percepción-acción.
*/
public class PATableWidget extends JPanel {
private static final long serialVersionUID = 1L;
private Direction[][][][] m_table;
/**
* Crea el widget que permite especificar una tabla de percepción-acción.
*
* @param pa_table La tabla que se utilizará para rellenar inicialmente el
* widget y donde se llevarán a cabo todas las modificaciones.
*/
public PATableWidget (Direction[][][][] pa_table) {
m_table = pa_table;
PerceptionActionTableModel m_model = new PerceptionActionTableModel(pa_table);
JTable table = new JTable(m_model);
JComboBox <Direction> editor = new JComboBox<Direction>(new Direction[]{
Direction.UP, Direction.DOWN, Direction.LEFT,
Direction.RIGHT, Direction.NONE
});
Enumeration<TableColumn> c = table.getColumnModel().getColumns();
while (c.hasMoreElements())
c.nextElement().setCellEditor(new DefaultCellEditor(editor));
table.setMinimumSize(table.getPreferredSize());
setLayout(new BorderLayout());
add(table.getTableHeader(), BorderLayout.NORTH);
add(table, BorderLayout.CENTER);
}
/**
* @return La tabla de percepción-acción con la información que puede observar
* o modificar el usuario.
*/
public Direction[][][][] getTable () {
return m_table;
}
/**
* Modelo para almacenar los datos de una tabla de percepción-acción.
*/
private static class PerceptionActionTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private static final int N_FIELDS = 5; // {U|D|L|R} + {ACTION}
private static final int N_ENTRIES = 16; // 2 {EMPTY|WALL} ^ 4 {U|D|L|R}
private static final String[] COLUMN_NAMES = {"UP", "DOWN", "LEFT", "RIGHT", "ACTION"};
private Direction [][][][] m_data;
/**
* Construye el modelo de la tabla y lo rellena con los datos del agente.
*
* @param table Tabla de percepción-acción con la que se rellena el modelo.
* Sus contenidos pueden ser modificados directamente por el usuario.
*/
public PerceptionActionTableModel (Direction[][][][] table) {
m_data = table;
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#getRowCount()
*/
@Override
public int getRowCount () {
return N_ENTRIES;
}
/*
* (non-Javadoc)
*
* @see javax.swing.table.TableModel#getColumnCount()
*/
@Override
public int getColumnCount () {
return N_FIELDS;
}
/*
* (non-Javadoc)
*
* @see javax.swing.table.AbstractTableModel#getColumnName(int)
*/
@Override
public String getColumnName (int column) {
return COLUMN_NAMES[column];
}
/*
* (non-Javadoc)
*
* @see javax.swing.table.AbstractTableModel#getColumnClass(int)
*/
@Override
public Class <?> getColumnClass (int column) {
return column != N_FIELDS - 1? Vision.class : Direction.class;
}
/*
* (non-Javadoc)
*
* @see javax.swing.table.AbstractTableModel#isCellEditable(int, int)
*/
@Override
public boolean isCellEditable (int row, int column) {
return column == N_FIELDS-1;
}
/*
* (non-Javadoc)
*
* @see javax.swing.table.TableModel#getValueAt(int, int)
*/
@Override
public Object getValueAt (int row, int column) {
int[] dec = decodeRow(row);
if (column != N_FIELDS-1)
return indexToVision(dec[column]);
else
return m_data[dec[0]][dec[1]][dec[2]][dec[3]];
}
/*
* (non-Javadoc)
*
* @see javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, int, int)
*/
@Override
public void setValueAt (Object value, int row, int column) {
if (column == N_FIELDS-1) {
int[] dec = decodeRow(row);
m_data[dec[0]][dec[1]][dec[2]][dec[3]] = (Direction) value;
}
}
/**
* Calcula a partir de la fila la asignación de visiones (U,D,L,R)
* que le corresponde.
*
* @param row Fila que decodificar.
* @return Array con la asignación para cada dirección. Un valor de 1
* significa que en esa dirección se ve un obstáculo. Un 0 significa
* que en esa dirección se ve una celda vacía.
*/
private static int[] decodeRow (int row) {
int[] assignation = new int[4];
for (int column = 0; column < N_FIELDS-1; column++)
assignation[column] = (row / (1 << N_FIELDS-2 - column)) % 2;
return assignation;
}
/**
* Traduce un valor de índice en la visión asociada.
*
* @param index Índice a traducir.
* @return Visión asociada al índice.
*/
private static Vision indexToVision (int index) {
return index == 0? Vision.EMPTY : Vision.WALL;
}
}
}