package view;
import boardGenerator.Pair;
import controllers.SudokuController;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import org.netbeans.lib.awtextra.AbsoluteConstraints;
import org.netbeans.lib.awtextra.AbsoluteLayout;
/**
* Clase vista Principal
*/
public class MainView extends IMainView {
private JFrame jfWindow;
private Celda[][] matriz;
private JLabel time;
private JLabel puntos;
private JLabel numRestantes;
private Color color1 = Color.GRAY;
private Color color2 = Color.LIGHT_GRAY;
private Color fontColor = Color.WHITE;
private Color wrongCell = Color.RED;
private Color fontColorNoEditable = Color.DARK_GRAY;
private Color correctColor = Color.GREEN;
private Color selectedColor = Color.YELLOW;
private Color caretColor = selectedColor;
private Color fontColorPista = Color.magenta;
private JButton butStart;
private JButton butSolve;
private JButton butHint;
private JButton butCheck;
private JButton butReset;
private JButton butTopTen;
private JButton butStop;
private JButton butRules;
private JButton butWeb;
private JRadioButton radHard;
private JRadioButton radModerate;
private JRadioButton radEasy;
private JTextField player;
private JButton butView;
/*Listener Para el movimiento y las teclas*/
private KeyListener keyList1 = new KeyAdapter() {public void keyTyped(KeyEvent evt) {Teclea(evt);}};
private KeyListener keyList2 = new KeyAdapter() {public void keyPressed(KeyEvent evt) {Mover(evt);}};
private FocusListener focusList1 = new FocusAdapter() {public void focusGained(FocusEvent evt) {textFieldFocusGained(evt);}};
private FocusListener focusList2 = new FocusAdapter() {public void focusLost(FocusEvent evt) {textFieldFocusLost(evt);}};
private MouseListener mouseList1 = new MouseAdapter() {public void mouseClicked(MouseEvent evt) {formMouseClicked(evt);}};
/**
* Constructor de la vista principal
* inicializa los componentes
*/
public MainView(){
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e){
e.printStackTrace();
}
jfWindow = new JFrame();
jfWindow.setMinimumSize(new Dimension(420,420));
//Segun la dimension de la pantalla (resolucion) tamaño y posicion de la ventana default
Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
Point framePos=new Point((int)(screenSize.width)/2-350,(int)(screenSize.height)/2-300);
jfWindow.setLocation(framePos);
//Dimension frameSize = new Dimension((int)(screenSize.width),(int)(screenSize.height));
//jfWindow.setBounds(0,0,frameSize.width,frameSize.height);
jfWindow.setIconImage(Toolkit.getDefaultToolkit().getImage(IMainView.class.getResource("/resources/sudoku-icon.png")));
//Renombro el cartel
jfWindow.setTitle("BigSudoku");
//Configuro los Contenedores de la Ventana
Container container = jfWindow.getContentPane();
setupMainContainer(container);
//Configuro las caracteristicas de la Ventana
jfWindow.pack();
jfWindow.setVisible(true);
jfWindow.setResizable(false);
jfWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
for (Component comp :jfWindow.getComponents()){
comp.addMouseListener(new MouseAdapter() {public void mouseClicked(MouseEvent evt) {formMouseClicked(evt);}});
}
}
/**
* Inicializa el contenedor principal del JFrame
* @param container
*/
private void setupMainContainer(Container container){
/*Panel izquierdo*/
JPanel tmp = new JPanel();
tmp.setLayout(new AbsoluteLayout());
tmp.add(informacion(),new AbsoluteConstraints(10, 10, -1, -1));
tmp.add(jugador(),new AbsoluteConstraints(10, 95, -1, -1));
tmp.add(dificultad(),new AbsoluteConstraints(10, 150, -1, -1));
tmp.add(botones(),new AbsoluteConstraints(50, 245, -1, -1));
container.setLayout(new BorderLayout());
container.add(tmp,BorderLayout.LINE_END);
container.add(tablero(),BorderLayout.CENTER);
}
/**
* Crea el panel de informacion del juego actual
* @return
*/
private JPanel informacion(){
JPanel info = new JPanel();
JPanel datos = new JPanel();
datos.setLayout(new GridLayout(3,2,2,2));
datos.setPreferredSize(new Dimension(160, 80));
datos.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Partida", TitledBorder.CENTER, TitledBorder.TOP, null, null));
JLabel timeText = new JLabel("Tiempo: ");
time = new JLabel();
time.setText("00:00:00");
timeText.setHorizontalAlignment(JLabel.RIGHT);
datos.add(timeText);
datos.add(time);
JLabel numText = new JLabel("Faltan: ");
numRestantes = new JLabel();
numRestantes.setText("81");
numText.setHorizontalAlignment(JLabel.RIGHT);
datos.add(numText);
datos.add(numRestantes);
JLabel puntText = new JLabel("Puntuacion: ");
puntos = new JLabel();
puntos.setText("0");
puntText.setHorizontalAlignment(JLabel.RIGHT);
datos.add(puntText);
datos.add(puntos);
info.add(datos);
return info;
}
/**
* Crea el panel de botones del juego
* @return
*/
private JPanel botones(){
JPanel info = new JPanel();
info.setLayout(new GridLayout(10,0,3,3));
info.setSize(50, 50);
/**
* Boton iniciar Juego
*/
butStart = new JButton();
butStart.addActionListener(SudokuController.getInstance());
butStart.setActionCommand("START_GAME");
butStart.setText("Nuevo");
butStart.setSize(20, 20);
butStart.setEnabled(true);
info.add(butStart);
/**
* Boton Resolver Juego
*/
butSolve = new JButton();
butSolve.addActionListener(SudokuController.getInstance());
butSolve.setActionCommand("SOLVE_GAME");
butSolve.setText("Resolver");
butSolve.setEnabled(false);
info.add(butSolve);
/**
* Boton Verificar juego
*/
butCheck = new JButton();
butCheck.addActionListener(SudokuController.getInstance());
butCheck.setActionCommand("CHECK_GAME");
butCheck.setText("Verificar");
butCheck.setEnabled(false);
info.add(butCheck);
/**
* Boton Obtener Pista
*/
butHint = new JButton();
butHint.addActionListener(SudokuController.getInstance());
butHint.setActionCommand("GET_HINT");
butHint.setText("Pista");
butHint.setEnabled(false);
info.add(butHint);
/**
* Boton Resetear Partida
*/
butReset = new JButton();
butReset.addActionListener(SudokuController.getInstance());
butReset.setActionCommand("RESET_GAME");
butReset.setText("Reiniciar");
butReset.setEnabled(false);
info.add(butReset);
/**
* Boton detener Partida
*/
butStop = new JButton();
butStop.addActionListener(SudokuController.getInstance());
butStop.setActionCommand("STOP_GAME");
butStop.setText("Finalizar");
butStop.setEnabled(false);
info.add(butStop);
/**
* Boton top10
*/
butTopTen = new JButton();
butTopTen.addActionListener(SudokuController.getInstance());
butTopTen.setActionCommand("TOP_TEN");
butTopTen.setText("Top Ten");
butTopTen.setEnabled(true);
info.add(butTopTen);
/**
* Boton sudokuonline
*/
butWeb = new JButton();
butWeb.addActionListener(SudokuController.getInstance());
butWeb.setActionCommand("SUDOKU_WEB");
butWeb.setText("Sudoku Online");
butWeb.setEnabled(true);
info.add(butWeb);
/**
* Boton Reglas Sudoku
*/
butRules = new JButton();
butRules.addActionListener(SudokuController.getInstance());
butRules.setActionCommand("RULES");
butRules.setText("Reglas Sudoku");
butRules.setEnabled(true);
info.add(butRules);
/**
* Boton cambiar interfaz
*/
butView = new JButton();
butView.addActionListener(SudokuController.getInstance());
butView.setActionCommand("OTHER_VIEW");
butView.setText("Cambiar Vista");
butView.setEnabled(true);
info.add(butView);
return info;
}
/**
* Crea el panel selector de dificultad
* @return
*/
private JPanel dificultad(){
JPanel info = new JPanel();
/**
* Botones Radio Mutuamente Excluyentes
*/
radHard = new JRadioButton();
radModerate = new JRadioButton();
radEasy = new JRadioButton();
radHard.setText("Dificil");
radModerate.setText("Moderado");
radEasy.setText("Facil");
radHard.setActionCommand("DIF_HARD");
radModerate.setActionCommand("DIF_MODERATE");
radEasy.setActionCommand("DIF_EASY");
radHard.addActionListener(SudokuController.getInstance());
radModerate.addActionListener(SudokuController.getInstance());
radEasy.addActionListener(SudokuController.getInstance());
radHard.setEnabled(true);
radModerate.setEnabled(true);
radEasy.setEnabled(true);
ButtonGroup group = new ButtonGroup();
group.add(radHard);
group.add(radModerate);
group.add(radEasy);
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(160, 80));
panel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Dificultad", TitledBorder.CENTER, TitledBorder.TOP, null, null));
panel.setLayout(new GridLayout(0, 1, 0, 0));
panel.add(radEasy);
panel.add(radModerate);
panel.add(radHard);
String diff = SudokuController.getInstance().getConfiguration().getDifficulty().toString();
switch (diff){
case "EASY": radEasy.setSelected(true); break;
case "HARD":radHard.setSelected(true);break;
case "MODERATE":radModerate.setSelected(true);break;
}
info.add(panel);
return info;
}
/**
* Panel Nombre de Jugador
* @return
*/
private JPanel jugador(){
JPanel info = new JPanel();
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(160, 50));
panel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Jugador", TitledBorder.CENTER, TitledBorder.TOP, null, null));
player = new JTextField(17);
player.setText(SudokuController.getInstance().getConfiguration().getNamePlayer());
panel.add(player);
info.add(panel);
return info;
}
/**
* Panel tablero Sudoku
* @return
*/
private JPanel tablero(){
JPanel superior = new JPanel();
superior.setLayout(new AbsoluteLayout());
JPanel tablero = new JPanel();
Dimension dim = new Dimension(500,500);
tablero.setMaximumSize(dim);
tablero.setPreferredSize(dim);
tablero.setSize(dim);
tablero.setLayout(new GridLayout(9,9,2,2));
crearMatriz();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
tablero.add(matriz[i][j]);
}
}
superior.add(tablero,new AbsoluteConstraints(10, 10, -1, -1));
return superior;
}
/**
* Crea la matriz de Celdas JTextField del juego
*/
private void crearMatriz(){
matriz = new Celda[9][9];
Celda tmp;
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
tmp = new Celda();
tmp.setColumns(1);
tmp.setFont(new java.awt.Font("Tahoma", 0, 18));
tmp.setForeground(fontColor);
tmp.setHorizontalAlignment(javax.swing.JTextField.CENTER);
tmp.setBorder(javax.swing.BorderFactory.createEtchedBorder());
tmp.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
tmp.setMargin(new java.awt.Insets(0, 0, 0, 0));
tmp.setMaximumSize(new java.awt.Dimension(4, 4));
tmp.setMinimumSize(new java.awt.Dimension(4, 4));
tmp.setPreferredSize(new java.awt.Dimension(4, 4));
tmp.setSize(4,4);
tmp.setInputVerifier(new IntegerInput());
tmp.setEditable(false);
tmp.setEnabled(false);
tmp.setCursor(new Cursor(Cursor.HAND_CURSOR));
tmp.setCaretColor(caretColor);
tmp.setKeymap(null);
tmp.setFil(i);
tmp.setCol(j);
if (((i<3 || i>5)&&(j<3||j>5)) || (i>2 && i<6 && j>2 && j<6)){
tmp.setNormalColor(color2);
} else {
tmp.setNormalColor(color1);
}
tmp.setWrong(false);
matriz[i][j] = tmp;
}
}
}
/**
* Habilita los controles del juego (botones de interaccion)
* @param var
*/
public void habilitarControles(boolean var){
this.butStart.setEnabled(!var);
this.radHard.setEnabled(!var);
this.radModerate.setEnabled(!var);
this.radEasy.setEnabled(!var);
this.butCheck.setEnabled(var);
this.butHint.setEnabled(var);
this.butSolve.setEnabled(var);
this.butReset.setEnabled(var);
this.butStop.setEnabled(var);
this.butView.setEnabled(!var);
this.butTopTen.setEnabled(!var);
this.butWeb.setEnabled(!var);
this.butRules.setEnabled(!var);
}
/**
* Habilita la interaccion con el tablero
*/
public void habilitarTablero(){
this.normalizeBoard();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
Celda tmp = matriz[i][j];
tmp.setEditable(true);
tmp.setEnabled(true);
tmp.addKeyListener(this.keyList1);
tmp.addKeyListener(this.keyList2);
tmp.addFocusListener(this.focusList1);
tmp.addFocusListener(this.focusList2);
tmp.addMouseListener(this.mouseList1);
}
}
}
/**
* Deshablita la interaccion con el tablero
*/
public void deshabilitarTablero(){
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++){
Celda tmp = matriz[i][j];
tmp.setEditable(false);
tmp.setEnabled(false);
tmp.removeKeyListener(this.keyList1);
tmp.removeKeyListener(this.keyList2);
tmp.removeFocusListener(this.focusList1);
tmp.removeFocusListener(this.focusList2);
tmp.removeMouseListener(this.mouseList1);
}
}
}
/**
* Actualiza el contador de tiempo
* @param time
*/
public void refreshTime(String time){
this.time.setText(time);
}
/**
* Actualiza el contador de puntuacion
* @param punt
*/
public void refreshPuntuacion(String punt){
this.puntos.setText(punt);
}
/**
* Actualiza el contador de numeros restantes
* @param num
*/
public void refreshContador(String num){
this.numRestantes.setText(num);
}
/**
* Establece la matriz del tablero
* @param param matriz de enteros de 9x9
*/
public void setMatriz(int[][] param){
this.normalizeBoard();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
setNum(i,j,param[i][j]);
}
}
}
/**
* Obtiene toda la Matriz del Tablero
* @return matriz de enteros de 9x9
*/
public int[][] getMatriz(){
int[][] result = new int[9][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
result[i][j] = getNum(i,j);
}
}
return result;
}
/**
* Establece un valor para una celda del tablero dado
* @pre -1<fil<9 and -1<col<9
* @param fil pos de fila
* @param col pos de columna
* @param value valor
*/
public void setNum(int fil,int col,int value){
if (value == 0){
matriz[fil][col].setText("");
matriz[fil][col].setEnabled(true);
matriz[fil][col].setEditable(true);
matriz[fil][col].setFont(new java.awt.Font("Tahoma", 1, 20));
} else {
matriz[fil][col].setText(String.valueOf(value));
matriz[fil][col].setEnabled(false);
matriz[fil][col].setEditable(false);
matriz[fil][col].setFont(new java.awt.Font("Tahoma", 2, 18));
matriz[fil][col].setDisabledTextColor(fontColorNoEditable);
}
}
/**
* Pone un valor en el tablero como si fuese
* una pista, en otro color y no editable
* @param fil posicicon fila
* @param col posicion columna
* @param value numero a ingresar
*/
public void setPista(int fil,int col,int value){
matriz[fil][col].setText(String.valueOf(value));
matriz[fil][col].setEnabled(false);
matriz[fil][col].setEditable(false);
matriz[fil][col].setDisabledTextColor(fontColorPista);
}
/**
* Establece una celda como incorrecta
* @param fil
* @param col
*/
public void setWrong(int fil,int col){
matriz[fil][col].setBackground(wrongCell);
matriz[fil][col].setWrong(true);
}
/**
* Establece una celda como normal
* @param fil
* @param col
*/
public void setNormal(int fil,int col){
matriz[fil][col].setBackground(matriz[fil][col].getNormalColor());
matriz[fil][col].setWrong(false);
}
/**
* Establece una celda como correcta
* @param fil
* @param col
*/
public void setCorrect(int fil,int col){
matriz[fil][col].setForeground(correctColor);
}
/**
* Obtiene el valor de una celda. Si este valor no es
* numerico devuelve un -1
* @pre -1<fil<9 and -1<col<9
* @param fil pos de fila
* @param col pos de columna
* @return
*/
public int getNum(int fil,int col){
try {
return Integer.valueOf(matriz[fil][col].getText());
} catch (Exception e){
return 0;
}
}
/**
* Obtiene el nombre del jugador actual *
* @return string con el nombre
*/
public String getPlayerName(){
return this.player.getText();
}
/**
* Establece el nombre del jugador actual
* @param nombre
*/
public void setPlayerName(String nomb){
this.player.setText(nomb);
}
/**
* Muestra un mensage de advertencia por pantalla
*/
public void showWarningMessage(String msg){
JOptionPane.showMessageDialog(null,msg," Advertencia",JOptionPane.WARNING_MESSAGE);
}
/**
* Muesta un mensage de informacion por pantalla
*/
public void showInfoMessage(String msg){
JOptionPane.showMessageDialog(null,msg," Informacion",JOptionPane.INFORMATION_MESSAGE);
}
/**
* Muestra un mensaje de confirmacion por pantalla
* @return true/false segun desicion
*/
public boolean showConfirmationMessage(String msg){
//int i = JOptionPane.showConfirmDialog(null, msg, " Confirmacion", JOptionPane.YES_NO_OPTION);
//return (i == JOptionPane.YES_OPTION);
return true;
}
/**
* Cierra la ventana actual
*/
public void dispose(){
this.jfWindow.dispose();
}
/**
* Evita la interaccion con la ventana actual
* @param val
*/
public void disable(Boolean val) {
this.jfWindow.setEnabled(!val);
}
/**
* Reclama el foco hacia la ventana principal
* y la trae al frente
*/
public void requestFocus(){
this.jfWindow.requestFocus();
this.jfWindow.toFront();
}
/**
* Verifica que solo ponga numeros entre 0 y 9
*/
private class IntegerInput extends InputVerifier{
@Override
public boolean verify(JComponent input) {
JTextField tmp = (JTextField)input;
String text = tmp.getText();
int num;
if (text.length()==0){
return true;
} else {
try {
num = Integer.parseInt(text);
} catch (Exception e) {
tmp.setText("");
return false;
}
if (num<0 || num >9){
tmp.setText("");
return false;
} else {
return true;
}
}
}
}
/**
* Punta el Tablero (fondo) con los colores normales
*/
private void normalizeBoard(){
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
matriz[i][j].setBackground(matriz[i][j].getNormalColor());
}
}
}
/**
* Evita poner otra cosa que no sea un numero del 1..9
* @param evt
*/
private void Teclea(KeyEvent evt){
Celda tmp = (Celda) evt.getComponent();
switch (evt.getKeyChar()) {
case '1': tmp.setText("1");insert(tmp,1);break;
case '2': tmp.setText("2");insert(tmp,2);break;
case '3': tmp.setText("3");insert(tmp,3);break;
case '4': tmp.setText("4");insert(tmp,4);break;
case '5': tmp.setText("5");insert(tmp,5);break;
case '6': tmp.setText("6");insert(tmp,6);break;
case '7': tmp.setText("7");insert(tmp,7);break;
case '8': tmp.setText("8");insert(tmp,8);break;
case '9': tmp.setText("9");insert(tmp,9);break;
}
}
/**
* Inserta un numero en la celda seleccionada infroma al observador
* @param field
* @param value
*/
private void insert(Celda field, int value){
field.setWrong(false);
Pair<Pair<Integer,Integer>,Integer> tmp = new Pair<Pair<Integer,Integer>,Integer>();
Pair<Integer,Integer> pos = new Pair(field.getFil(),field.getCol());
tmp.setFirst(pos);tmp.setSecond(value);
setChanged();
notifyObservers(tmp);
}
/**
* Permite desplazarce en la grilla con las
* teclas de direccion y borrar elementos con supr y delete
* @param evt
*/
private void Mover(KeyEvent evt){
int dir = evt.getKeyCode();
Celda actual = (Celda) evt.getComponent();
int fil = actual.getFil();
int col = actual.getCol();
switch (dir){
case 40: moverAbajo(fil,col);break;
case 38: moverArriba(fil,col);break;
case 37: moverIzquierda(fil,col);break;
case 39: moverDerecha(fil,col);break;
case 8: case 127: /*Borra valor*/
insert(actual,0);
actual.setText("");break;
}
}
/**
* Mueve el foco una fila abajo
* @param fil
* @param col
*/
private void moverAbajo(int fil, int col){
if (fil+1<9){
while (!matriz[fil+1][col].isEnabled() && fil+1<9){
fil++;
if (fil+1>8) fil = -1;
}
}
if (fil+1>8){
moverAbajo(-1,col);
} else {
matriz[fil+1][col].requestFocus();
}
}
/**
* Mueve el foco una celda a la derecha
* @param fil
* @param col
*/
private void moverDerecha(int fil, int col){
if (col+1<9){
while (!matriz[fil][col+1].isEnabled() && col+1<9){
col++;
if (col+1>8) col = -1;
}
}
if (col+1>8){
moverDerecha(fil,-1);
} else {
matriz[fil][col+1].requestFocus();
}
}
/**
* Mueve el foco una fila arriba
* @param fil
* @param col
*/
private void moverArriba(int fil, int col){
if (fil-1>-1){
while (!matriz[fil-1][col].isEnabled() && fil-1>-1){
fil--;
if (fil-1<0) fil = 9;
}
}
if (fil-1<0){
moverArriba(9,col);
} else {
matriz[fil-1][col].requestFocus();
}
}
/**
* Mueve el foco una celda a la derecha
* @param fil
* @param col
*/
private void moverIzquierda(int fil, int col){
if (col-1>-1){
while (!matriz[fil][col-1].isEnabled() && col-1>-1){
col--;
if (col-1<0) col = 9;
}
}
if (col-1<0){
moverIzquierda(fil,9);
} else {
matriz[fil][col-1].requestFocus();
}
}
/**
* Cuando la celda gana el foco se pinta de otro color
* @param evt
*/
private void textFieldFocusGained(FocusEvent evt){
((Celda)evt.getSource()).setBackground(selectedColor);
}
/**
* Cuando la celda pierde el foco recupera color original
* @param evt
*/
private void textFieldFocusLost(FocusEvent evt){
Celda tmp = (Celda)evt.getSource();
if (tmp.isWrong())
tmp.setBackground(wrongCell);
else
tmp.setBackground(tmp.getNormalColor());
}
/**
* Cuando hago clic derecho quito el foco actual
* @param evt
*/
private void formMouseClicked(java.awt.event.MouseEvent evt) {
if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK){
jfWindow.requestFocus();
}
}
}