/* * MIT License * * Copyright (c) 2018 Daniel Cortes * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package danielcortes.xyz.controllers; import danielcortes.xyz.models.caja.Caja; import danielcortes.xyz.models.ingreso.Ingreso; import danielcortes.xyz.models.ingreso.IngresoDAO; import danielcortes.xyz.models.tipo_ingreso.TipoIngreso; import danielcortes.xyz.models.tipo_ingreso.TipoIngresoDAO; import danielcortes.xyz.views.IngresosView; import danielcortes.xyz.views.components.IngresosTableModel; import org.jetbrains.annotations.Contract; import javax.swing.*; import java.awt.event.*; /** * Controlador el cual esta orientado a manejar la vista de IngresosView * Maneja su contenido y las acciones que esta realiza */ public class IngresosController { private IngresosView view; private IngresoDAO ingresoDAO; private TipoIngresoDAO tipoIngresoDAO; private Caja caja; private int editingId; private Ingreso editingIngreso; private boolean editing; /** * Crea el controlado de egresos, el cual esta acoplado con la vista de ingresos, controlando el estado y contenido de esta. * Al iniciarse ejecuta. * - Metodo que llena el combobox de tipos de ingreso * - Metodo que genera los eventos para la vista * - Metodo que actualiza el estado de los botones */ public IngresosController(IngresosView view, IngresoDAO ingresoDAO, TipoIngresoDAO tipoIngresoDAO) { this.view = view; this.ingresoDAO = ingresoDAO; this.tipoIngresoDAO = tipoIngresoDAO; this.fillTipoIngresoCombo(); this.setupViewEvents(); this.updateButtonsEnabled(); } /** * Getter!! */ public IngresoDAO getIngresoDAO() { return ingresoDAO; } /** * Getter!!! * @return */ public TipoIngresoDAO getTipoIngresoDAO() { return tipoIngresoDAO; } /** * Guarda la caja ingresada y actualiza el contenido de la tabla de ingresos y el campo de total de ingresos */ public void updateCaja(Caja caja){ this.caja = caja; this.fillIngresosTable(); this.updateTotalIngresos(); } /** * LLena el combobox de tipos de ingresos */ private void fillTipoIngresoCombo() { JComboBox tipoCombo = this.view.getTipoCombo(); for (TipoIngreso tipo : this.tipoIngresoDAO.findAll()) { tipoCombo.addItem(tipo); } } /** * Llena la tabla de ingresos con los ingresos pertenecientes a la caja guarda */ private void fillIngresosTable() { IngresosTableModel ingresosTableModel = this.view.getIngresosTableModel(); ingresosTableModel.removeRows(); for (Ingreso ingreso : this.ingresoDAO.findByCaja(this.caja)) { ingresosTableModel.addRow(ingreso); } } /** * Genera los eventos para los distintos componentes de la vista * - Cuando se presiona el boton de guardar o se apreta enter en los fields de valor, nro inicial, * nro final y tipo se llama a guardarActionListener * - Cuando se presiona el boton de eliminar se llama al eliminarActionListener * - Cuando se selecciona una fila en la tabla se llama a updateButtonsEnabled * - Cuando se presiona el boton de editar o se hace doble click sobre una fila de la tabla se llama a editarActionListener */ private void setupViewEvents() { this.view.getValorField().getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("ENTER"), "nextField"); this.view.getNroInicialField().getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("ENTER"), "nextField"); this.view.getNroFinalField().getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("ENTER"), "nextField"); this.view.getTipoCombo().getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("ENTER"), "save"); this.view.getValorField().getActionMap().put("nextField", new NextAction(this.view.getNroInicialField())); this.view.getNroInicialField().getActionMap().put("nextField", new NextAction(this.view.getNroFinalField())); this.view.getNroFinalField().getActionMap().put("nextField", new NextAction(this.view.getTipoCombo())); this.view.getTipoCombo().getActionMap().put("save", new GuardarAction(this)); this.view.getIngresosTable().getSelectionModel().addListSelectionListener(e -> updateButtonsEnabled()); this.view.getGuardarButton().addActionListener(e -> guardarActionListener()); this.view.getEliminarButton().addActionListener(e -> eliminarActionListener()); this.view.getEditarButton().addActionListener(e -> editarActionListener()); this.view.getIngresosTable().addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent mouseEvent) { JTable table = (JTable) mouseEvent.getSource(); if (mouseEvent.getClickCount() == 2 && table.getSelectedRow() != -1) { IngresosController.this.editarActionListener(); } } }); } /** * Realiza las preparaciones previas a guardar un ingreso * Primero llama a normalizar los inputs y a esconder los mensajes de error * Luego dependiendo si se tiene la flag editing en true o false se llama a editar ingreso o a guardarlo * Tras terminar esto se llama a resetear el focus. */ private void guardarActionListener() { this.normalizeInputs(); this.hideErrorMessages(); String valor = this.view.getValorField().getText(); String nroInicial = this.view.getNroInicialField().getText(); String nroFinal = this.view.getNroFinalField().getText(); TipoIngreso tipoIngreso = (TipoIngreso) this.view.getTipoCombo().getSelectedItem(); if(editing) { this.editarIngreso(valor, nroInicial, nroFinal, tipoIngreso, this.caja); } else { this.guardarIngreso(valor, nroInicial, nroFinal, tipoIngreso, this.caja); } this.resetFocus(); } /** * Realiza las acciones necesarias para eliminar un ingreso * Solo lo va a realizar si es que esta seleccionada una fila de la tabla, se eliminara el ingreso seleccionado * Una vez eliminado se llama a actualizar el total de ingresos y el estado de los botones */ private void eliminarActionListener() { int selectedId = this.view.getIngresosTable().getSelectedRow(); if(selectedId >= 0){ Ingreso ingreso = this.view.getIngresosTableModel().getIngreso(selectedId); this.view.getIngresosTableModel().removeRow(selectedId); this.ingresoDAO.deleteIngreso(ingreso); this.updateTotalIngresos(); this.updateButtonsEnabled(); } } /** * Realiza las preparaciones previas a editar un ingreso * Primero llama a esconder los mensajes de error. * Guarda globlarmente el ingreso a ser editar, el id de este y una flag que indica que se esta en modo de editar. * Finalmente llena los campos de inputs con los datos del ingreso a editar. */ private void editarActionListener() { this.hideErrorMessages(); int selectedID = this.view.getIngresosTable().getSelectedRow(); int selectedModelID = this.view.getIngresosTable().getRowSorter().convertRowIndexToModel(selectedID); if(selectedModelID >= 0) { Ingreso ingreso = this.view.getIngresosTableModel().getIngreso(selectedModelID); this.editingId = selectedModelID; this.editingIngreso = ingreso; this.editing = true; this.view.getTipoCombo().setSelectedItem(ingreso.getTipoIngreso()); this.view.getValorField().setText(String.valueOf(ingreso.getValor())); this.view.getNroInicialField().setText(String.valueOf(ingreso.getNroInicial())); this.view.getNroFinalField().setText(String.valueOf(ingreso.getNroFinal())); } } /** * Obtiene el total de ingresos de la caja y lo coloca en el el field totalingresos */ private void updateTotalIngresos(){ int total = this.ingresoDAO.getTotalIngreso(this.caja); this.view.getTotalIngresoField().setText(String.valueOf(total)); } /** * Actualiza si los botones estan habilitados * Esto depende de si se encuentra al menos una fila en la tabla seleccionada * Si es asi, son habilidatos, si no, de deshabilitan */ private void updateButtonsEnabled() { if(this.view.getIngresosTable().getSelectedRow()>=0){ this.view.getEliminarButton().setEnabled(true); this.view.getEditarButton().setEnabled(true); }else{ this.view.getEliminarButton().setEnabled(false); this.view.getEditarButton().setEnabled(false); } } /** * Guarda un ingreso tras llamar a validar el input * Luego de guardar agrega a la tabla el ingreso, llama a limpiar los campos de input y a actualizar el total de ingresos */ private void guardarIngreso(String valor, String nroInicial, String nroFinal, TipoIngreso tipoIngreso, Caja caja){ if(this.validateInput(valor, nroInicial, nroFinal, tipoIngreso, caja)){ Ingreso ingreso = new Ingreso(); ingreso.setTipoIngreso(tipoIngreso); ingreso.setCaja(caja); ingreso.setValor(Integer.valueOf(valor)); ingreso.setNroInicial(nroInicial); ingreso.setNroFinal(nroFinal); this.ingresoDAO.insertIngreso(ingreso); this.view.getIngresosTableModel().addRow(ingreso); this.clearInputs(); this.updateTotalIngresos(); } } /** * Edita el ingreso tras llamar a validar el input * Tras esto actualiza el ingreso en la tabla, llama a actualizar el total de ingresos, a limpiar los campos de input y a desactivar la flag de editing. * */ private void editarIngreso(String valor, String nroInicial, String nroFinal, TipoIngreso tipoIngreso, Caja caja){ if(this.validateInput(valor, nroInicial, nroFinal, tipoIngreso, caja)){ this.editingIngreso.setTipoIngreso(tipoIngreso); this.editingIngreso.setValor(Integer.valueOf(valor)); this.editingIngreso.setNroInicial(nroInicial); this.editingIngreso.setNroFinal(nroFinal); this.ingresoDAO.updateIngreso(this.editingIngreso); this.view.getIngresosTableModel().setIngreso(this.editingId, this.editingIngreso); this.updateTotalIngresos(); this.clearInputs(); this.editing = false; } } /** * Llama a los metodos necesarios para validar el input * @return true cuando todas las validaciones retoran true, si no, false */ private boolean validateInput(String valor, String nroInicial, String nroFinal, TipoIngreso tipoIngreso, Caja caja) { this.hideErrorMessages(); boolean valorValidation = this.validateValor(valor); boolean nroInicialValidation = this.validateNroInicial(nroInicial); boolean nroFinalValidation = this.validateNroFinal(nroFinal); boolean tipoIngresoValidation = this.validateTipoIngreso(tipoIngreso); boolean cajaValidation = this.validateCaja(caja); return valorValidation && tipoIngresoValidation && cajaValidation; } /** * Valida la variable caja este caso * - Es null * @return Si este caso es true se retornara false, si no, se retorna true */ private boolean validateCaja(Caja caja) { return caja != null; } /** * Valida la variable valor contra los casos * - Es null * - Esta vacio * - Los caracteres no son solamente digitos * - El largo del string es mayor a 10 * Cuando el primer caso sea true, colocara un mensaje de error correspondiente en el jlabel correspondiente * @return Si cualquiera de estos casos son true se retornara false, si no, se retorna true */ private boolean validateValor(String valor) { if (valor == null) { this.view.getErrorValor().setText("Hubo un problema con los datos"); this.view.getErrorValor().setVisible(true); return false; } if (valor.isEmpty()) { this.view.getErrorValor().setText("El campo esta vacio"); this.view.getErrorValor().setVisible(true); return false; } if (!valor.chars().allMatch(Character::isDigit)) { this.view.getErrorValor().setText("Deben ser numeros"); this.view.getErrorValor().setVisible(true); return false; } if(valor.length() > 10){ this.view.getErrorValor().setText("El numero ingresado es demasiado largo"); this.view.getErrorValor().setVisible(true); return false; } return true; } /** * Valida la variable nroInicial contra los casos * - Es null * - Esta vacio * Cuando el primer caso sea true, colocara un mensaje de error correspondiente en el jlabel correspondiente * @return Si cualquiera de estos casos son true se retornara false, si no, se retorna true */ private boolean validateNroInicial(String nroInicial){ if (nroInicial == null) { this.view.getErrorNroInicial().setText("Hubo un problema con los datos"); this.view.getErrorNroInicial().setVisible(true); return false; } if (nroInicial.isEmpty()) { this.view.getErrorNroInicial().setText("El campo esta vacio"); this.view.getErrorNroInicial().setVisible(true); return false; } return true; } /** * Valida la variable nroFinal contra los casos * - Es null * - Esta vacio * Cuando el primer caso sea true, colocara un mensaje de error correspondiente en el jlabel correspondiente * @return Si cualquiera de estos casos son true se retornara false, si no, se retorna true */ private boolean validateNroFinal(String nroFinal){ if (nroFinal == null) { this.view.getErrorNroFinal().setText("Hubo un problema con los datos"); this.view.getErrorNroFinal().setVisible(true); return false; } if (nroFinal.isEmpty()) { this.view.getErrorNroFinal().setText("El campo esta vacio"); this.view.getErrorNroFinal().setVisible(true); return false; } return true; } /** * Valida la variable caja este caso * - Es null * Cuando sea true, colocara un mensaje de error en el jlabel correspondiente * @return Si este caso es true se retornara false, si no, se retorna true */ private boolean validateTipoIngreso(TipoIngreso tipoIngreso) { if (tipoIngreso == null) { this.view.getErrorTipoIngreso().setText("Hubo un problema con los datos"); this.view.getErrorTipoIngreso().setVisible(true); return false; } return true; } /** * Esconde los mensajes de error en la ventana de ingresos */ private void hideErrorMessages() { this.view.getErrorTipoIngreso().setVisible(false); this.view.getErrorValor().setVisible(false); this.view.getErrorNroInicial().setVisible(false); this.view.getErrorNroFinal().setVisible(false); } /** * Vacia los jtextfields y selecciona la primera opcion del jcombobox */ private void clearInputs() { this.view.getTipoCombo().setSelectedIndex(0); this.view.getValorField().setText(""); this.view.getNroInicialField().setText(""); this.view.getNroFinalField().setText(""); } /** * Ejecuta un trim sobre todos los jtextfield */ private void normalizeInputs(){ this.view.getValorField().setText(this.view.getValorField().getText().trim()); this.view.getNroInicialField().setText(this.view.getNroInicialField().getText().trim()); this.view.getNroFinalField().setText(this.view.getNroFinalField().getText().trim()); } /** * Le pide focus al tipo combo */ private void resetFocus(){ this.view.getValorField().requestFocus(); } private class NextAction extends AbstractAction{ JComponent next; NextAction(JComponent next){ this.next = next; } @Override public void actionPerformed(ActionEvent e) { this.next.requestFocus(); } } private class GuardarAction extends AbstractAction{ IngresosController controller; GuardarAction(IngresosController controller){ this.controller = controller; } @Override public void actionPerformed(ActionEvent e) { this.controller.guardarActionListener(); } } }