Funcionalidad de la vista de detalle

Objetos requeridos

La clase controladora de la vista de detalle de una persona, se debe encargar de mostrar los datos contenidos en el objeto Persona que se esté tratando, permitir su edición y finalmente guardar los cambios o cancelar su volcado a la base de datos.

Para realizar todas esas operaciones, esta clase va a necesitar disponer de una serie de objetos que se encontraban creados en la clase controladora de la vista anterior, la de la lista. Esos objetos son:

  • La Persona que haya seleccionado el usuario.
  • El EntityManager que gestiona las operaciones con la base de datos.
  • El TableView de la lista de personas, ya que deberá actualizar su contenido cuando se editen los datos de la persona actual.

Además la clase del detalle debe conocer si el objeto Persona que esté recibiendo se trata de un objeto nuevo recién creado (se ha pulsado el botón Nuevo), o bien es un objeto que ya existía en la base de datos y se está editando su contenido (se ha pulsado el botón Editar). Para ello, se puede crear una nueva propiedad de tipo booleno que almacene si la persona es nueva o no.

Así que en esta clase del detalle se crearán las propiedades correspondientes:

private TableView tableViewPrevio;
private Persona persona;
private EntityManager entityManager;
private boolean nuevaPersona;

Para que cualquiera otra clase (en este caso la clase de la vista lista) pueda asignar el TableView a esta clase de detalle, se creará un método set para el tableViewPrevio, ya que se ha declarado como privada.

public void setTableViewPrevio(TableView tableViewPrevio) {
    this.tableViewPrevio = tableViewPrevio;
}

En el caso del objeto Persona, el EntityManager y la propiedad para conocer si es una nueva persona o no, se creará un único método que permita asignar todos esos valores. Como puedes observar en el código siguiente, se iniciará la transacción con la base de datos en el momento en que se use este método. Además, en caso de que el objeto Persona sea uno de los registros ya existentes, dicho objeto se tomará desde la base de datos (entityManager.find()) usando su identificador, con el fin de que si el usuario cancela la operación de edición, se pueda realizar un rollback que recupere los datos originales del objeto, es decir, los que se encontraban previamente en la base de datos.

public void setPersona(EntityManager entityManager, Persona persona, boolean nuevaPersona) {
    this.entityManager = entityManager;
    entityManager.getTransaction().begin();
    if(!nuevaPersona) {
        this.persona = entityManager.find(Persona.class, persona.getId());
    } else {
        this.persona = persona;
    }
    this.nuevaPersona = nuevaPersona;
}

Como se comentó antes, en la clase controladora de la vista de la lista, concretamente en el código de los botones Nuevo y Editar, se utilizarán esos métodos set para pasar los objetos correspondientes desde la vista al detalle.

personaDetalleViewController.setTableViewPrevio(tableViewContactos);

En esos botones, para pasar el objeto Persona y el EntityManager, se usará el método setPersona que se acaba de declarar, pasando un nuevo objeto Persona para el caso del botón Nuevo, o el objeto seleccionado para el botón Editar, e indicando en cada caso, a través del tercer parámetro, si es nuevo o no.

// Para el botón Nuevo:
personaSeleccionada = new Persona();
personaDetalleViewController.setPersona(entityManager, personaSeleccionada, true);
// Para el botón Editar: personaDetalleViewController.setPersona(entityManager, personaSeleccionada, false);

Mostrar datos actuales del objeto

Otra acción que se realizará desde el código de los botones Nuevo y Editar de la controladora de la lista será indicar que se muestren en la vista de detalle los datos correspondientes al objeto Persona que estemos tratando. La orden se hará invocando a un método que podemos denominar mostrarDatos que en unos momentos desarrollaremos en la clase controladora del detalle, pero que de momento podemos ir ejecutando desde el código de ambos botones.

personaDetalleViewController.mostrarDatos();

En el código del método mostrarDatos, que se debe implementar en la clase controladora del detalle, se deben incluir las sentencias necesarias para mostrar los datos de la persona en cada control correspondiente (TextField, ComboBox, CheckBox, etc) de la vista detalle. De momento, y para no hacer más compleja esta parte, sólo se muestra a continuación el código correspondiente a mostrar los datos de tipos String (Varchar en la base de datos). Se utilizarán los métodos get que se habían generado automáticamente en la clase entidad para obtener los valores de cada propiedad.

public void mostrarDatos() {
    textFieldNombre.setText(persona.getNombre());
    textFieldApellidos.setText(persona.getApellidos());
    textFieldTelefono.setText(persona.getTelefono());
    textFieldEMail.setText(persona.getEmail());
// Falta implementar el código para el resto de controles }

Almacenar datos en la base de datos

En el código del botón Guardar de la vista detalle se deben indicar las sentencias necesarias para actualizar las propiedades del objeto Persona obteniendo la información que se encuentre en cada uno de los controles de la ventana. Una vez actualizado el objeto, se debe almacenar en la base de datos, teniendo en cuenta que si se estaba creando una nueva persona hay que insertarla en la base de datos (persist - INSERT en SQL), mientras que se la persona ya existía previamente hay que actualizar los datos ya existentes (merge - UPDATE en SQL). Podemos saber si se trata de una persona nueva o no gracias a la variable nuevaPersona cuya gestión ya habíamos realizado anteriormente.

Al igual que antes, sólo vamos a reflejar de momento cómo se haría para las propiedades de tipo String:

persona.setNombre(textFieldNombre.getText());
persona.setApellidos(textFieldApellidos.getText());
persona.setTelefono(textFieldTelefono.getText());
persona.setEmail(textFieldEMail.getText());

if(nuevaPersona) {
    entityManager.persist(persona);
} else {
    entityManager.merge(persona);
}
entityManager.getTransaction().commit();

Actualizar datos en el TableView

Con el código anterior se habrán actualizado los datos en la base de datos, pero no en el TableView que muestra la lista de la ventana anterior. El código necesario ya se vió en un artículo anterior de este tutorial, en concreto cuando se implementó la edición de datos en la misma vista que la lista, por lo que no se detalla mucho más ahora.

Para el caso del botón Cancelar, no se deben actualizar los datos del registro seleccionado por lo que hay anular la transacción que se había comenzado en el código del método setPersona, y además es conveniente devolver al foco al TableView, concretamente a la misma fila que estuviera seleccionada previamente:

entityManager.getTransaction().rollback();

int numFilaSeleccionada = tableViewPrevio.getSelectionModel().getSelectedIndex();
TablePosition pos = new TablePosition(tableViewPrevio, numFilaSeleccionada, null);
tableViewPrevio.getFocusModel().focus(pos);
tableViewPrevio.requestFocus();

En cambio, si el usuario hubiera pulsado el botón Guardar, hay que actualizar los nuevos datos en el TableView, teniendo en cuenta que si se trata de una nueva persona, hay que seleccionar la última fila del TableView, ya que ahí se debe encontrar el nuevo objeto que se añade también al TableView, y si se estaba editando una persona ya existente se debe volver a seleccionar la línea en la que se encontraba dentro del TableVew.

int numFilaSeleccionada;
if(nuevaPersona) {
    tableViewPrevio.getItems().add(persona);
    numFilaSeleccionada = tableViewPrevio.getItems().size() - 1;
    tableViewPrevio.getSelectionModel().select(numFilaSeleccionada);
    tableViewPrevio.scrollTo(numFilaSeleccionada);
} else {
    numFilaSeleccionada = tableViewPrevio.getSelectionModel().getSelectedIndex();
    tableViewPrevio.getItems().set(numFilaSeleccionada, persona);
}
TablePosition pos = new TablePosition(tableViewPrevio, numFilaSeleccionada, null);
tableViewPrevio.getFocusModel().focus(pos);
tableViewPrevio.requestFocus();