Java 7: guión de prácticas

32
JNotas Guión de prácticas

description

Java 7: guión de prácticas

Transcript of Java 7: guión de prácticas

Page 1: Java 7: guión de prácticas

JNotasGuión de prácticas

Page 2: Java 7: guión de prácticas

Table of ContentsDescripción del proyecto............................................................................................................4P1 – La clase Nota......................................................................................................................4P2 – La clase BussinessObject....................................................................................................4P3 – Notas.Save(): guardar Nota en fichero...............................................................................5P4 – Notas.Get(): Leer Nota del fichero.....................................................................................5P5 – JUnit: test de guardar nota en fichero.................................................................................5P6 – newId: autoincremento en el fichero de notas....................................................................5P7 – Windowbuilder: ventana de visualización de notas............................................................5P8 – Base de datos: recuperar notas de BD................................................................................6P9 – Base de datos: Actualizar notas en BD (update).................................................................6P10 – Mantenimiento de notas: buscar, crear, editar, borrar,......................................................7P11 – División en paquetes: Modelo, Vista y Controladora y JNotasTest..................................7P12 – JNotasTest: testGuardarNotaEnBD()................................................................................7P14 – MainFrm: panel de búsqueda y panel de datos.................................................................8P15 – ResizeableFrm: Formulario de pruebas redimensionable.................................................8P16 – MainForm: Formulario redimensionable con barra de herramientas y barra de estado...8P17 – NotaSelFrm: Formulario de selección de nota. Cargar notas...........................................9P18 – NotaSelFrm: Formulario de selección de nota. Filtrar notas..........................................10

P18.a. Generación manual de eventos.............................................................................10P18.b. Buscar por titulo, descripción e id........................................................................10

P19 – Mejorar apariencia..........................................................................................................11P19.a: Mejorar el área de system icon.............................................................................11P19.b: Mejorar la botonera..............................................................................................12P19.c: Más mejoras a la botonera. Texto de los botones debajo del icono......................12P19.d: Margen interior en el panel de datos de la nota....................................................13P19.e: Margen interior del buscador/selector de notas....................................................13

P20 – MainCCU y SeleccionarNotaCCU: esqueleto................................................................14MainCCU: controladora principal...................................................................................14SeleccionarNotaCCU.......................................................................................................14MainFrm..........................................................................................................................15

P21 – MostrarNotaCCU: esqueleto...........................................................................................15P22 – Interconectar controladoras.............................................................................................15P23 – Borrar una nota...............................................................................................................16P24 – Eliminar Warning asociados a la generación de eventos................................................17P25 – Formulario modal crear nueva nota................................................................................18P26 – Controladora CrearEditarNotaCCU: crear nota..............................................................19P27 – Controladora CrearEditarNotaCCU: editar nota existente.............................................20P28 – Nota: descripción multilínea + campo resuelta...............................................................20P29 – Bloqueamos controles en el modo visualización............................................................21P30 – Doble click sobre nota en selector de notas edita la nota...............................................21P31 – Atajos de teclado en el selector de notas: INTRO edita, SUPR elimina .......................22P32 – Atajos de teclado en el selector de notas: cursor actualiza nota seleccionada................23P33 – Cuando creamos/editamos una nota, que quede seleccionada ésta.................................23P34 – Tabla de carpetas.............................................................................................................25P35 – Clase carpeta...................................................................................................................25P36 – Colección de carpetas: CarpetasList...............................................................................25P37 – Mostrar carpetas en el selector de notas.........................................................................25P38 – Subimos proyecto a Github.............................................................................................25P39 – Añadimos colección de notas a las carpetas...................................................................26

Solución...........................................................................................................................26Carpeta...................................................................................................................26

Page 3: Java 7: guión de prácticas

NotasList................................................................................................................26NotaSelPane...........................................................................................................27SeleccionarNotaCCU.............................................................................................27

P40 – Incluir botones para carpetas en la barra de herramientas..............................................27P41 – Volver a hacer funcionar el selector de notas..................................................................27

Solución...........................................................................................................................28P42 – Ocultar panel de nota cuando seleccionamos carpeta.....................................................28P43 – Desactivar el warning serialVersionUID........................................................................29P44 – Crear una nueva carpeta..................................................................................................29

Solución...........................................................................................................................30P45 – Modificar nombre de una carpeta...................................................................................30P46 – Eliminar una carpeta.......................................................................................................30P47 – Atajos de teclado para carpetas.......................................................................................30

Solución...........................................................................................................................31P48 – Crear notas bajo la carpeta que le toca...........................................................................31P49 – Cuando borro una nota, se selecciona el anterior...........................................................31

Una pista..........................................................................................................................31

Page 4: Java 7: guión de prácticas

Descripción del proyectoNuestro guión de prácticas irá enfocado a construir un programa para gestión y dirección de proyectos informáticos.

Este proyecto está basado en el proyecto ANotas que utiliza el servicio de informática de la Consejería de Educación del Gobierno de Canarias para dirigir los proyectos de desarrollo de software que allí se desarrollan. El proyecto original ha sido desarrollado por Armando Fumero Fernández, jefe del proyecto Pincel eKade, persona por la que siento gran admiración profesional.

Una vez hayamos terminado nuestro proyecto, JNotas será capaz de:

• Crear tareas, hitos e iteraciones de programación

• Programar reuniones

• Generar informes de seguimiento del proyecto

• Publicar las programaciones asociadas a cada iteración del desarrollo

• Asignar tareas a programadores

• Generar informes de seguimiento por cada programador

• Medir la envergadura de nuestro proyecto: número de líneas de código, número de clases, número de tablas en base de datos,...

• Registrar errores de ejecución en producción

• …

P1 – La clase Nota• Atributos

• Getters y setters de los atributos

• Constructor

• Método toString

• Versión básica: sin carpetas, sin guardar,...

P2 – La clase BussinessObject• Atributo id

• Atributos isValid, isEmpty, isNew

• Método setPropertyChanged

• Constructor

• Método toString

• Método Save: simplemente lanza excepción

• Método Get(id): simplemente lanza excepción

Page 5: Java 7: guión de prácticas

P3 – Notas.Save(): guardar Nota en fichero• Vamos a completar el método Save de las notas

• Con ello vamos a guardar la nota en un fichero de texto

• Cada campo separado del siguiente por un “;”

• Utilizamos clase FileWriter para escribir:

◦ Al hacer new FileWriter, utilizar parámetro 2 para abrir en modo append

◦ método write para escribir en el fichero

• No nos preocupamos si ya existe esa nota, si no existe,... Directamente añadimos al final del fichero una nueva línea con el contenido de la nota

P4 – Notas.Get(): Leer Nota del fichero• Vamos a completar el método Get de las notas

• Utilizamos clase Scanner para leer

• Simplemente leemos la primera nota y nos aseguramos de que carga bien

• Recuerda que cada nota ocupa una línea

P5 – JUnit: test de guardar nota en fichero• Crear clase de test NotaTest.java

• Crear un primer método de test testGuardarEnFichero

• Ese test elimina el fichero Notas.txt

• Crear una nueva nota con id=100 y valores en los atributos

• Guarda la nota en fichero

• Crea una nueva nota nota2

• Leemos nota2 de fichero con nota2.get(100)

• Comparamos campo a campo nota con nota2 para saber si escribió/leyó bien

P6 – newId: autoincremento en el fichero de notas• Modificar la clase Nota para que su constructor asigne un id automáticamente de forma

incremental

• Para ello, en NotasDB crear un método estático newId que recorra el fichero de notas y busque maxId, que es el valor máximo actual de id que hay en el fichero

• Devolver maxId + 1

P7 – Windowbuilder: ventana de visualización de notas• Utilizando el plugin para eclipse Windowbuilder generar el formulario de visualización de

Page 6: Java 7: guión de prácticas

una nota

• Internamente incluye un objeto nota de tipo Nota

• El método setNota nos permite asignarle la nota que queremos visualizar

• Para cada atributo de nota, incluye una etiqueta con el nombre del campo y una caja de textocon su valor:

P8 – Base de datos: recuperar notas de BD• Hasta ahora hemos utilizado un fichero llamado Notas.txt.

• Crear una base de datos llamada JNotas con una única tabla Notas

• Insertar varias notas de prueba

• Esta tabla tendrá exactamente los mismos campos que tiene actualmente la clase Nota

• Modificar el método get para que lea/escriba de base de datos, en lugar que de fichero

• Para gestionar el acceso a la base de datos, crea una clase DAL con los siguientes métodos estáticos:

◦ public static Connection devuelveConexionAbierta();

◦ public static ResultSet executeQuery(Connection conn, String sql) throws Exception;

P9 – Base de datos: Actualizar notas en BD (update)• Recuperar de BD una nota

• Mostrarla en un JFrame (NotaFrm)

txtIdCarpetatxtTitulo

...

frmNota

Page 7: Java 7: guión de prácticas

• Agregarle un botón Guardar a ese JFrame

• Modificar en base de datos según los datos que se hayan insertado en el JFrame

P10 – Mantenimiento de notas: buscar, crear, editar, borrar,...Vamos a tomar el formulario de visualización de notas NotasFrm y le vamos a añadir una barra de herramientas con la que podremos:

• Crear una nueva nota

• Borrar la nota actual

◦ Añadirle a las notas el método getLast()

◦ Este método recupera de la BD la nota con mayor Id

◦ Después de borrar, cargamos la mayor y la mostramos

• Editar la nota actual

• Buscar una nota concreta

• Ver los datos asociados a una nota en detalle

Debemos editar el formulario NotasFrm con el plugin Windowbuilder de Google.

P11 – División en paquetes: Modelo, Vista y Controladora y JNotasTest

Dividimos nuestro proyecto en 3 paquetes: Modelo, vista y controladora

Además, creamos un nuevo proyecto para todos los test. Lo llamamos JNotasTest

P12 – JNotasTest: testGuardarNotaEnBD()• Creamos una nota nota1 y la guardamos

• Creamos una nota2 y la cargamos de base de datos con el id de nota1

• Comparamos uno a uno los campos de nota1 y nota2

• Si hay alguno diferente, las notas NO son iguales, de modo que algo NO habrá ido bien en elguardado/recuperado de base de datos

Page 8: Java 7: guión de prácticas

P14 – MainFrm: panel de búsqueda y panel de datos• Crearemos un nuevo JFrame llamado MainFrm

• Será el frame principal de la aplicación

• A la izquierda tendrá un panel de búsqueda/selección

• A la derecha un panel de datos de una nota

• Crear los paneles como objetos independientes (NotaSelPane y NotaDataPane)

• En esta versión este formulario todavía NO hace nada, solo hemos modificado la capa de presentación

P15 – ResizeableFrm: Formulario de pruebas redimensionableEn esta práctica vamos a hacer un ejercicio sencillo de redimensionamiento de formularios.

El objetivo es crear un formulario tal que, sus componentes se auto-organicen en función del tamaño del mismo.

Hemos puesto GridBagLayout

El botón hemos puesto Anchor NorthWest y widthx a 1.0

P16 – MainForm: Formulario redimensionable con barra de herramientas y barra de estado• Modificaremos nuestro formulario principal para que:

Page 9: Java 7: guión de prácticas

• Sea redimensionable

• Incluya la barra de tareas y la barra de estado

• Además, debe contener el área de selección/navegación de notas y los datos de una nota

• Todavía NO interactúa con la base de datos, es únicamente una cuestión gráfica

P17 – NotaSelFrm: Formulario de selección de nota. Cargar notas

• Vamos a trabajar sobre la funcionalidad completa de la selección y búsqueda de notas

• Para ello, utilizando el panel NotaSelPane, crearemos un formulario que trabaje de forma autónoma.

• Cargará todas las notas de la base de datos y las mostrará en la lista

• De momento es una caja tonta: muestra las notas en el JList de notas.

• Crear la clase NotasList, que tiene un ArrayList que almacena todas las notas

• Crear un método get que recupera de base de datos todas las notas

• Modificar el método toString para devuelva un string que concatena todas las notas leídas dela base de datos y almacenadas en el ArrayList

Page 10: Java 7: guión de prácticas

• Tanto al notaSelPane como al notaSelFrm agregar un método setNotas que asigne una lista de notas nueva

• El selPane, agrega los títulos de cada una de las notas de esa lista al JList

• El formulario debe ser redimensionable

P18 – NotaSelFrm: Formulario de selección de nota. Filtrar notas• Si escribimos un texto en la caja de búsqueda y pulsamos buscar, filtrará el listado de notas

por aquellas que coincidan con el filtro

P18.a. Generación manual de eventos

Empieza primero generando de forma manual dentro del notaSelPane un evento personalizado cuando el usuario hace click sobre buscar

Recupera ese evento en notaSelFrm

Muestra simplemente en consola que el usuario ha pulsado el botón buscar e incluye el texto que había en la caja de texto

P18.b. Buscar por titulo, descripción e id

A NotasList le agregamos un nuevo método get(String texto)

En la SQL, agregamos al where para que busque en el titulo, en la descripción y en el id

Page 11: Java 7: guión de prácticas

P19 – Mejorar aparienciaÉste es el aspecto actual. Ninguno de los paneles es en este momento funcional:

P19.a: Mejorar el área de system icon

Hemos creado la imagen en Gimp.

La asociamos a la JLabel que hemos colocado en ese panel

JLabel lblSystemIcon = new JLabel("");

imageHeader = new ImageIcon(MainFrm.class.getResource("/images/headerMain.jpg"));

lblSystemIcon.setIcon(imageHeader);

Hacemos que la línea de división del splitter coincida justo con el ancho de la imagen

splitPane.setDividerLocation(imageHeader.getIconWidth());

Page 12: Java 7: guión de prácticas

P19.b: Mejorar la botonera

Hemos añadido imágenes (icon) a los botones

Establecemos su tamaño preferido:

JButton btnNuevo = new JButton("Nuevo");

Dimension buttonDimension = new Dimension(120, imageHeader.getIconHeight() - 20);

btnNuevo.setIcon(new ImageIcon(MainFrm.class.getResource("/images/newFile_32x32.png")));

P19.c: Más mejoras a la botonera. Texto de los botones debajo del icono

btnNuevo.setMargin(new Insets(0, 0, 0, 0));

btnNuevo.setVerticalTextPosition(SwingConstants.BOTTOM);

btnNuevo.setHorizontalTextPosition(SwingConstants.CENTER);

Page 13: Java 7: guión de prácticas

P19.d: Margen interior en el panel de datos de la nota

Hemos modificado los insets de todos los componentes:

gbc_btnNuevo.insets = new Insets(10, 5, 5, 0);

...

Insets insets = new Insets(5,5,5,5);

...

gbc_lblId.insets = insets;

...

gbc_txtId.insets = insets;

P19.e: Margen interior del buscador/selector de notas

De nuevo trabajamos sobre los insets de los elementos gráficos.

Page 14: Java 7: guión de prácticas

También hemos agregado un borde a la caja de selección de notas

P20 – MainCCU y SeleccionarNotaCCU: esqueleto

Empezaremos por dos controladoras: MainCCU y NotaSelCCU

MainCCU: controladora principal

MainCCU es la controladora principal. Es la que contiene las controladoras de selección y búsquedade notas y la controladora de visualización de datos de una nota

Estará organizada en las siguientes regiones:

• Objetos de negocio

• Vista

• Controladoras de inclusión

• Métodos propios de las CCU

De momento en objetos de negocio no ponemos ninguno

Su vista será de tipo MainFrm, el formulario principal que ya habíamos creado

Las controladoras de inclusión serán SeleccionarNotaCCU y MostrarNotaCCU.

De momento solo incluimos SeleccionarNotaCCU, que crearemos a continuación

En métodos propios de las CCU, añadimos el método iniciar

Básicamente, inicia las CCU incluidas, recupera sus vistas, y le pasa las vistas de las CCU a su propia vista

SeleccionarNotaCCU

Estará organizada en las siguientes regiones:

• Objetos de negocio

• Vista

• Controladoras de inclusión

• Métodos propios de las CCU

• Gestión de eventos

En objetos de negocio colocamos una lista de notas (NotasList)

Su vista será de tipo NotaSelPane

Esta CCU debe capturar los eventos del panel, en este caso, el evento ButtonClick

Su método iniciar, recupera de base de datos todas las notas y se lo suministra a su vista

Page 15: Java 7: guión de prácticas

En la gestión de eventos, manejamos los eventos de la vista

MainFrm

Hay que hacer algunos cambios

En primer lugar, ahora tiene 2 paneles que recibe de fuera, de las controladoras incluidas.

De modo que tenemos que suministrar dos métodos setNotaSelPane y setNotaDataPane

P21 – MostrarNotaCCU: esqueletoEsta nueva CCU se encargará únicamente de mostrar los datos de una nota

P22 – Interconectar controladorasAhora mismo, la ventana principal carga 2 controladoras que van a su aire.

Es decir, si seleccionamos una nota en la controladora de selección, la que muestra los datos ni se entera, sigue mostrando la nota 1.

¿Cómo las vamos a comunicar?

Usuario: Usuario hace click sobre una nota

NotaSelPane: Ese click es detectado por el JList

NotaSelPane: Disparamos un evento con _raiseNotaClickEvent(...)

SeleccionarNotaCCU: El evento es capturado por SeleccionarNotaCCU, que a su vez, lanza un evento hacia afuera:

MainCCU: Este nuevo evento es capturado por MainCCU, que lo que hace es pasarle el idNota a MostrarNotaCCU.

MostrarNotaCCU: recupera la nota de base de datos y se la suministra a su vista con miVista.setNota(nota):

NotaDataPane: La vista MostrarNotaFrm muestra los datos de esa nota

IMPORTANTE: Haz que la aplicación reaccione de forma esperada cuando utilizamos la búsqueda de notas por su descripción.

listNotas = new JList<String>(datos);

listNotas.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

MouseListener mouseListener = new MouseAdapter() {

public void mouseClicked(MouseEvent e) {

if (e.getClickCount() == 1) {

int index = listNotas.locationToIndex(e.getPoint());

System.out.println("Double clicked on Item " + index);

...

_raiseNotaClickEvent(idNota);

}

}

Page 16: Java 7: guión de prácticas

};

listNotas.addMouseListener(mouseListener);

Código para NotaSelPane

public void notaClick(NotaSelPaneEvent e) {

System.out.println("click sobre nota " + e.getIdNota());

_raiseNotaClickEvent(e.getIdNota());

}

Código de SeleccionarNotaCCU

public void notaClick(NotaSelPaneEvent ev) {

System.out.println("MainCCU: Has pulsado sobre la nota " + ev.getIdNota());

}

Código de MainCCU

P23 – Borrar una notaVamos a eliminar la nota seleccionada.

MainCCU captura el evento de la barra de herramientas

Carga un objeto Nota con el id de la seleccionada

Invoca su método delete

Invoca al método reiniciar el la controladora SeleccionarNotaCCU

// #region Gestión de eventos de su vista

private void borrarSelectedNota() {

Nota n = new Nota();

try {

n.get(seleccionarNotaCCU.getIdSelectedNota());

n.delete();

}

catch (Exception e) {

e.printStackTrace();

}

seleccionarNotaCCU.reiniciar();

}

// -------------------------------------------------------------------------------------

public void buttonClick(ToolbarEvent ev) {

if (ev.getButtonName().equals("Borrar")) {

borrarSelectedNota();

}

}

// #endregion

Page 17: Java 7: guión de prácticas

P24 – Eliminar Warning asociados a la generación de eventosEn la generación de eventos, usamos la clase List pero no con Generics. Modificamos para eliminar los Warning.

Cada clase que genera sus propios eventos, tiene un código como este:

private List _listeners = new ArrayList();

public synchronized void addListener(SeleccionarNotaCCUListener l ) {

_listeners.add(l);

}

public synchronized void removeListener(SeleccionarNotaCCUListener l ) {

_listeners.remove(l);

}

private synchronized void _raiseNotaClickEvent(int idNota) {

NotaSelPaneEvent ev = new NotaSelPaneEvent(this, idNota);

Iterator listeners = _listeners.iterator();

while( listeners.hasNext() ) {

((SeleccionarNotaCCUListener) listeners.next() ).notaClick(ev);

}

}

Cambiamos por este otro:

private List<SeleccionarNotaCCUListener> _listeners = new ArrayList<SeleccionarNotaCCUListener>();

public synchronized void addListener(SeleccionarNotaCCUListener l ) {

_listeners.add(l);

}

public synchronized void removeListener(SeleccionarNotaCCUListener l ) {

_listeners.remove(l);

}

private synchronized void _raiseNotaClickEvent(int idNota) {

NotaSelPaneEvent ev = new NotaSelPaneEvent(this, idNota);

Iterator<SeleccionarNotaCCUListener> listeners = _listeners.iterator();

while( listeners.hasNext() ) {

((SeleccionarNotaCCUListener) listeners.next() ).notaClick(ev);

}

}

Page 18: Java 7: guión de prácticas

P25 – Formulario modal crear nueva nota• Tenemos que capturar el evento del botón Nuevo en la barra de herramientas de MainFrm.

• Esto provoca que se abra un formulario modal con el panel de datos de la nota vacíos

• Este formulario debe tener un botón aceptar y otro cancelar

• De momento no hacemos nada, solamente abrir el formulario, y desde MainCCU detectar si se pulsó Aceptar o cancelar.

• De momento NO guardamos la nueva nota en base de datos ni nada.

• Modificamos las clases ToolbarListener, ToolbarEvent,... para llamarlas ButtonListener, ButtonEvent,...

Creamos una ventana para crear notas que se abra en forma modal. Debe heredar de JDialog:

public class NuevaNotaFrm extends JDialog {

...

public NuevaNotaFrm(JFrame parent, boolean modal) {

super(parent, modal);

initComponents();

}

...

public NuevaNotaFrm() {

initComponents();

}

...

Una vez lo tenemos en la mainCCU, debemos lanzar este formulario en forma modal:

private void crearNuevaNota() {

NuevaNotaFrm nuevaNotaFrm = new NuevaNotaFrm(this.miVista, true);

nuevaNotaFrm.setVisible(true);

}

Page 19: Java 7: guión de prácticas

Cuando desde este formulario se pulsa aceptar o cancelar, simplemente lo recogemos en MainCCU y mostramos en consola el botón pulsado:

// Código de MainCCU en su región de gestión de eventos

...

public void buttonClick(ButtonEvent ev) {

switch (ev.getButtonName()) {

case "Borrar":

borrarSelectedNota();

break;

case "Nuevo":

crearNuevaNota();

break;

default:

System.out.println("MainCCU: pulsado botón " + ev.getButtonName());

break;

}

}

P26 – Controladora CrearEditarNotaCCU: crear notaEn la práctica anterior hemos hecho las cosas mal.

La controladora está manejando eventos de una vista que no es la suya.

Debemos crear una nueva controladora CrearEditarNotaCCU, que será la que abra el formulario CrearEditarNotaFrm

Esta nueva CCU será la que recogerá los eventos del formulario y la que salvará en base de datos (ono) las nuevas notas o las posibles ediciones de notas

NotaDataPane: Método reverseRefresh(). Vuelca el contenido de las cajas de texto a la Nota

CrearEditarNotaFrm: invoca a reverseRefresh cuando captura el evento Aceptar

MainCCU: método crearNuevaNota() ahora invoca a crearEditarNotaCCU.iniciar(), y al terminar invoca al reiniciar de la CCU de selección de notas, porque si creó una nueva, que figure en el buscador

private void crearNuevaNota() {

crearEditarNotaCCU = new CrearEditarNotaCCU(this.miVista);

crearEditarNotaCCU.iniciar();

// Cuando termine la controladora anterior, refrescamos la de seleccionar

// para que aparezca la nueva

seleccionarNotaCCU.reiniciar();

}

CrearEditarNotaCCU:

Page 20: Java 7: guión de prácticas

Métodos setNota y getNota simplemente invocan al setNota y getNota de su vista

Cuando capturamos evento, si es Aceptar, grabamos nota

public void buttonClick(ButtonEvent ev) {

if (ev.getButtonName().equals("Aceptar")) {

try {

nota.save();

}

catch (Exception e) {

e.printStackTrace();

}

}

miVista.setVisible(false);

}

P27 – Controladora CrearEditarNotaCCU: editar nota existenteAhora pulsamos sobre editar, en lugar de sobre Nuevo.

Son pocos los cambios, pues nuestra CCU CrearEditarNota ya recibe una nota en sus setters.

Simplemente es asignársela

private void editarNota() {

Nota nota = new Nota();

try {

nota.get(seleccionarNotaCCU.getIdSelectedNota());

crearEditarNotaCCU = new CrearEditarNotaCCU(this.miVista);

crearEditarNotaCCU.setNota(nota);

crearEditarNotaCCU.iniciar();

// Cuando termine la controladora anterior, refrescamos la de seleccionar

// para que aparezca la nueva

seleccionarNotaCCU.reiniciar();

}

catch (Exception e) {

}

}

P28 – Nota: descripción multilínea + campo resueltaVisualmente hacemos que la descripción sea multilinea y le agregamos un campo buleano de resuelta.

Visualmente agregamos un botón “Marcar como resuelta”

NotaDataPane: Actualizar métodos refresh y reverseRefresh

jno_notas: agregar campo a la tabla

Page 21: Java 7: guión de prácticas

Nota: agregar campo resuelta. Modificar el acceso a datos para que recupere este nuevo campo

P29 – Bloqueamos controles en el modo visualizaciónCuando estamos en modo de visualización, el usuario NO debe poder modificar ningún atributo de la nota.

Para ello, el panel NotaDataPane le agregamos, en su constructor, un atributo readOnly para que bloquee todos los controles

public void setOnlyReadable(boolean readOnly) {

for (int i = 0; i < this.getComponentCount(); i++) {

Component c = this.getComponent(i);

if (c instanceof JTextField)

((JTextField) c).setEditable(! readOnly);

if (c instanceof JTextArea)

((JTextArea) c).setEditable(! readOnly);

if (c instanceof JCheckBox)

((JCheckBox) c).setEnabled(! readOnly);

}

}

P30 – Doble click sobre nota en selector de notas edita la notaSi hacemos doble click sobre una nota en el selector de notas, editamos la nota.

Page 22: Java 7: guión de prácticas

NotaSelPaneEvent: tipo enumerado para distinguir click simple de doble

NotaSelPane: lanzamos un evento u otro según haya sido simple o doble

SeleccionarNotaCCU hace lo mismo, envía un evento u otro

MainCCU: en función de si ha sido simple o doble, hace una cosa u otra:click

public enum TipoAccion{SIMPLE_CLICK, DOUBLE_CLICK};

MouseListener mouseListener = new MouseAdapter() {

public void mouseClicked(MouseEvent e) {

if (e.getClickCount() == 1) {

int index = listNotas.locationToIndex(e.getPoint());

_raiseNotaClickEvent(index, TipoAccion.SIMPLE_CLICK);

}

if (e.getClickCount() == 2) {

int index = listNotas.locationToIndex(e.getPoint());

_raiseNotaClickEvent(index, TipoAccion.DOUBLE_CLICK);

}

}

};

public void notaClick(NotaSelPaneEvent ev) {

if (ev.getTipoAccion() == TipoAccion.SIMPLE_CLICK)

mostrarNotaCCU.iniciar(ev.getIdNota());

else if (ev.getTipoAccion() == TipoAccion.DOUBLE_CLICK)

editarNota();

}

P31 – Atajos de teclado en el selector de notas: INTRO edita, SUPR elimina

NotaSelPaneEvent: Aumentamos nuestro tipo TipoAccionNotaSelPane: incluimos handler de tecla pulsadaMainCCU: recibe el evento, y lo gestiona

Cuidado, porque ahora mismo NO detecta cuando, en el selector, nos movemos con el cursor por lasnotas, y cree que está seleccionada la 0 (la última en la que hicimos click)

public enum TipoAccion{SIMPLE_CLICK, DOUBLE_CLICK, SUPRIMIR, INTRO};

listNotas.addKeyListener(new KeyAdapter() {

@Override

public void keyTyped(KeyEvent e) {

int index = listNotas.getSelectedIndex();

Page 23: Java 7: guión de prácticas

switch ((int) e.getKeyChar()) {

case 10:

_raiseNotaClickEvent(index, TipoAccion.INTRO);

break;

case 127:

_raiseNotaClickEvent(index, TipoAccion.SUPRIMIR);

}

}

});

public void notaClick(NotaSelPaneEvent ev) {

if (ev.getTipoAccion() == TipoAccion.SIMPLE_CLICK)

mostrarNotaCCU.iniciar(ev.getIdNota());

else if (ev.getTipoAccion() == TipoAccion.DOUBLE_CLICK)

editarNota();

else if (ev.getTipoAccion() == TipoAccion.INTRO)

editarNota();

else if (ev.getTipoAccion() == TipoAccion.SUPRIMIR)

borrarSelectedNota();

}

P32 – Atajos de teclado en el selector de notas: cursor actualiza nota seleccionada

Ahora mismo, si nos movemos por el panel de notas con las teclas de cursor, NO se actualiza la nota seleccionada, y es que la CCU SeleccionarNota NO está enviando ningún evento, ya que no hemos hecho click sobre ninguna nota.

Capturamos el evento valueChanged del JList, y lanzamos el evento notaClick event.

listNotas.addListSelectionListener(new ListSelectionListener() {

public void valueChanged(ListSelectionEvent arg0) {

_raiseNotaClickEvent(listNotas.getSelectedIndex(), TipoAccion.SIMPLE_CLICK);

}

});

P33 – Cuando creamos/editamos una nota, que quede seleccionada ésta

Ahora mismo, cuando creamos/editamos una nota, al terminar, queda siempre seleccionada la primera nota de la lista, y no la que recién hemos creado o la que acaabamos de editar.

Para ello, cuando la controladora crearEditarNotaCCU termina, MainCCU, que es quien la ha invocado, deberá acceder a la nota mediante crearEditarNotaCCU.getNota() y forzar a seleccionarNotaCCU que seleccione justo ésa.

Se estaba produciendo un problema.

Page 24: Java 7: guión de prácticas

En el panel de selección de notas (NotaSelPane), cuando llamamos a refresh, y eliminamos todos los datos...

private void refresh() {

System.out.println("Refresh");

desengancharEventos();

datos.removeAllElements();

...

… se produce un error, y es que cuando eliminamos todos los elementos, se está invocando el evento valueChanged, en el sentido de que el elemento seleccionado ha cambiado, y claro, el códigode este evento da error, porque la lista está vacía.

Así que, cuando vamos a hacer un refresh, primero debemos desactivar los eventos y luego volver aactivarlos:

private void refresh() {

desactivarEventos();

datos.removeAllElements();

for (int i = 0; i < list.size(); i++) {

datos.addElement("[" + String.valueOf(list.getNota(i).getId()) + "] " + list.getNota(i).getTitulo());

}

activarEventos();

seleccionarFirstNota();

this.repaint();

}

Así activamos los eventos:

// #region Gestión de eventos de elementos gráficos

ListSelectionListener listSelectionListener;

KeyAdapter keyAdapter;

MouseAdapter mouseAdapter;

private void activarEventos() {

listSelectionListener = new ListSelectionListener() {

public void valueChanged(ListSelectionEvent arg0) {

_raiseNotaClickEvent(listNotas.getSelectedIndex(), TipoAccion.SIMPLE_CLICK);

}

};

keyAdapter = new KeyAdapter() {

@Override

public void keyTyped(KeyEvent e) {

...

Y así los desactivamos:

Page 25: Java 7: guión de prácticas

public void desactivarEventos() {

listNotas.removeListSelectionListener(listSelectionListener);

listNotas.removeKeyListener(keyAdapter);

listNotas.removeMouseListener(mouseAdapter);

}

P34 – Tabla de carpetasVamos a comenzar a trabajar con carpetas, que contendrán notas.

Comencemos creando la tabla que aloja las carpetas.

P35 – Clase carpetaEn su versión inicial, hacemos una copia de la clase Nota, con los correspondientes ajustes.

P36 – Colección de carpetas: CarpetasListEn su versión inicial, hacemos una copia de la clase NotasList, con los correspondientes ajustes.

P37 – Mostrar carpetas en el selector de notasVamos a modificar el selector de notas para que muestre las carpetas y las notas.

Todavía sin relacionar, quiero decir, no va a mostrar cada carpeta con sus notas asociadas, sino simplemente todas las carpetas y luego, todas las notas

SeleccionarNotaCCU:

• Añadimos la lista de carpetas

• En los métodos iniciar y reiniciar cargamos la lista de carpetas (carpetas.get())

• Asignamos la lista de carpetas a la vista (miVista.setCarpetasList(carpetas))

• Al buscar, no buscamos en carpetas, sino en notas

NotaSelPane:

• Añadimos la lista de carpetas y su setter (setCarpetasList)

• En el método refresh, cargamos sobre datos las carpetas y luego las notas

P38 – Subimos proyecto a Github

No he realizado ningún cambio significativo en la aplicación,simplemente quiero probar el Commit and Push desde EclipseLa ruta del repositorio es: https://github.com/moisespd/jnotas.git

Page 26: Java 7: guión de prácticas

P39 – Añadimos colección de notas a las carpetasLa clase carpeta contendrá un atributo que es su lista de carpetas asociadas

Esta lista de carpetas la cargaremos en modo LazyLoad

De momento no vamos a permitir subcarpetas, de modo que una carpeta no tiene una lista de subcarpetas hija, sino únicamente una lista de notas que cuelgan directamente de ella

En la visualización del selector de notas, mostraremos cada carpeta y su lista de notas un poco desplazado a la derecha, para que visualmente se aprecie que son las notas contenidas bajo esa carpeta:

De momento no nos preocupemos ni por editar las notas, ni por borrarlas, ni por poder buscar,...

Incluso cuando pulsamos una nota, es posible que dé error, ya que

Solución

Carpeta

• misNotas, que es una clase de tipo NotasList, y que será la lista de notas asociadas a la carpeta

• getNotas()

• cargarRecordset, hacemos misNotas.get()

NotasList

• get(int idCarpeta), este método devolverá la lista de notas asociadas a la carpeta idCarpeta

Page 27: Java 7: guión de prácticas

• Modificamos el procedimiento almacenado para que soporte un idCarpeta como parámetro

NotaSelPane

• refresh() , dos for anidados, uno que recorre las carpetas y el interior que recorre las notas asociadas a la carpeta actual

SeleccionarNotaCCU

• Eliminamos la lista de notas, ya solo necesita una lista de carpetas

• iniciar y reiniciar(), ya solo cargamos las carpetas, no las notas

P40 – Incluir botones para carpetas en la barra de herramientasIncluimos los botones crear, editar y borrar carpetas en la barra de herramientas

De momento solo como efecto visual, los botones NO hacen nada

Cuidado porque los botones de las notas podrían dejar de funcionar

Incluso, como ya hemos dicho, la selección de notas/carpetas de momento tampoco funciona

P41 – Volver a hacer funcionar el selector de notasEn el selector de notas ahora conviven carpetas y notas.

Por esta razón, ha dejado de funcionar

• la visualización de los datos de la nota seleccionada

• doble click sobre una nota

Page 28: Java 7: guión de prácticas

• tecla intro sobre una nota

• tecla suprimir sobre una nota

• Botones de crear/editar/borrar notas de la barra de herramientas

• ...

Volvamos a hacer funcionar el selector de notas sencillamente ignorando las carpetas.

Solución

¿Cómo sabemos que hemos hecho click sobre una carpeta?

Lo que haremos es que el id de las carpetas les añadiremos una c. delante.

Así tendremos [c1], [c2],... en el sentido de carpeta 1, carpeta 2,... de este modo sabremos que el usuario ha hecho click sobre una carpeta, y no sobre una nota.

Ten en cuenta que ahora el id de las notas sigue encerrado entre corchetes pero está desplazado en eltexto para que parezca que están vinculadas a la carpeta

Además, el id de las carpetas tiene una c dentro del corchete y antes de su valor de id

P42 – Ocultar panel de nota cuando seleccionamos carpeta

Tendremos que trabajar con un CardLayout, es decir, un Layout que contiene N paneles superpuestos, y en cada momento solo muestra uno:

Page 29: Java 7: guión de prácticas

NotaDataPane NoNotaPane

Este nuevo panel lo llamamos NotaPane

Ahora, la vista de MostrarNotaCCU será un NotaPane

Desde la controladora MainCCU, que sabe si hemos hecho click sobre una carpeta o sobre una nota,indicará a MostrarNotaCCU que se oculte, y ésta invocará a su vista para que muestre el segundo panel, el de “sin datos”

P43 – Desactivar el warning serialVersionUID

P44 – Crear una nueva carpetaVamos a hacer que el botón “Crear carpeta” funcione.

Crear una carpeta básicamente es asignarle un nombre y guardarla en base de datos

Ni siquiera necesitamos una vista, sino simplemente un JDialog.

Mira el tutorial de cómo crear JDialog en Java: http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html

Page 30: Java 7: guión de prácticas

Solución

La controladora MainCCU detectará el evento de botón pulsado, e invocará al método crearCarpeta()

Este método, solicita al usuario el nuevo nombre mediante un JOptionPane.showInputDialog()carpeta.setTitulo(...)Carpeta.save()seleccionarNotaCCU.reiniciar()

P45 – Modificar nombre de una carpeta

P46 – Eliminar una carpetaProhibir la eliminación si contiene notas en su interior

Advertir al usuario si no se pudo eliminar

Cuando pulsemos este botón, asegúrate que el usuario tiene seleccionada una carpeta, y no una nota

P47 – Atajos de teclado para carpetasINTRO: editar carpeta

SUPR: eliminar carpeta

SHIFT + INS: crear nueva carpeta

INS: Crea una nueva nota

Todavía, cuando creamos una nota, no la crea bajo la carpeta que le toca. No te preocupes por eso

Page 31: Java 7: guión de prácticas

aún.

Solución

KeyTyped no detecta muchas teclas de control.

Utiliza mejor el método KeyPressed del KeyAdapter que estés usando

Utiliza el método isShiftDown() del KeyEvent

P48 – Crear notas bajo la carpeta que le tocaHasta ahora, las notas se han creado con un idCarpeta = -1

Vamos a hacer que la nota se cree bajo la carpeta que nos encontremos en el selector de notas

Si en el selector de notas, tenemos seleccionada una carpeta, la carpeta padre de nuestra nueva nota estará clara.

Sin embargo, si lo que tenemos seleccionado es una nota, la nueva nota tendrá exactamente el mismo idCarpeta que la nota actual, de modo que ése será el valor que devolvamos.

Además, aprovechamos para corregir que cuando editamos un elemento (nota o carpeta), al terminar el proceso el selector de notas mantiene seleccionado el elemento que hemos editado.

¡¡¡Cuidado cuando no hay ninguna nota ni ninguna carpeta creada!!!

En ese caso, el idCarpeta será -1

P49 – Cuando borro una nota, se selecciona el anteriorCuando eliminamos una nota, ahora mismo se queda seleccionado el primer elemento de la lista.

Modificamos este comportamiento para que, cuando elimino una nota, se queda seleccionado el elemento justo por encima.

Salvo que no quede ninguno por encima, en cuyo caso se selecciona el que tiene por debajo

Una pista

Hasta ahora, hemos resuelto esta cuestión con los métodos

public void setIdSelectedNota(int value);

public void setIdSelectedCarpeta(int value);

En los que suminstrábamos el Id de la nota/carpeta que queríamos marcar como seleccionado.

Estos métodos eran invocados por MainCCU al terminar una operación de Crear/Editar/Borrar Nota/Carpeta.

Esto es válido para la edición/creación, ya que sé el Id que edité o creé, de modo que es devolverle el foco a este elemento.

Pero cuando borro, ¿cuál es el que debo seleccionar?

Lo que hacemos es que el panel NotaSelPane tiene un atributo que almacena la posición del elemento seleccionado (selectedPos).

Page 32: Java 7: guión de prácticas

Este valor coincide con el getIndexSelected del JList, de modo que tenemos que actualizarlo a este valor cada vez que haya un cambio de valor del JList y ya lo tendremos listo.

Cuando se invoca al método refresh(), al final me aseguro de marcar como seleccionado el elementoubicado en la posición selectedPos, en lugar de marcar la primera, tal y como teníamos antes:

seleccionarFirstNota();

Cambiamos por:if (datos.size() > 0) {

if (selectedPos >= datos.size())

selectedPos = datos.size() -1;

listNotas.setSelectedIndex(selectedPos);

}