PintaLlop - Programa de dibujo

Llop Site Home > JAVA > PintaLlop > ArkaLlop

PintaLlop:

Clase PintaLlop 

package pintallop;

import java.io.*;
import java.net.*;
import javax.imageio.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.print.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.metal.*;

/** Título: PintaLlop
    Descripción: Prácticas capítulo 11, ejercicio 3
    Copyright: Copyright (c) 2005
    Empresa: Casa_Llop
    @author Albert_Lobo
    @version 1.0 */

/** La clase estrella del programa. Se trata de un applet que puede acceder al portapapeles
    -una aparente contradicción, por las restricciones de acceso al equipo 'cliente' de los
    'applets'. Esto es porque el programa también se puede ejecutar como 'aplicación'.
    Tenemos 2 configuraciones de ejecución del programa:
      - Applet: Tiene toda la funcionalidad que permite un applet -no puede guardar imágenes al disco
                del equipo cliente, ni abrirlas, ni utilizar el portapapeles.
      - Aplicación: La versión más completa -permite hacer lo que el applet podía y no podía hacer. */
public class PintaLlop extends JApplet implements ClipboardOwner
{
  // Cursores estáticos para los lienzos.
  /** Cursor con apariencia de lápiz. */
  public static Cursor cursorLapiz;
  /** Cursor con apariencia de goma de borrar. */
  public static Cursor cursorGoma;
  /** Cursor propio del texto. */
  public static Cursor cursorTexto;
  /** Cursor con apariencia de cruz. */
  public static Cursor cursorCruz;

  private JMenuBar barraMenu;                  // Barra de menú.
  private JToolBar barraHerramientas;          // Barra de herramientas.
  private PanelPropiedades panelPropiedades;   // El panel de propiedades (para la herramienta actual).
  private JTabbedPane panelLienzo;             // El panel para los lienzos.
  private ColeccionLienzos coleccionLienzos;   // Los lienzos.

  private boolean esAplicacion;                // ¿Se ejecuta como aplicación (true), o como applet (false)?
  private ColeccionHerramientas herramientas;  // Las herramientas de dibujo.
  private Clipboard clipboard;                 // El portapapeles del sistema.

  private JTextField cajaURL;                  // Caja de texto para entrar 'URL's.
  private short cuentaPestanas;                // Cuántos lienzos hay en el 'panelLienzo'.

  private PanelInformacion panelInfo;          // Panel para las instrucciones del programa.

  // Las acciones que se pueden ejecutar sobre los lienzos.
  private Action accionNuevoLienzo;
  private Action accionAbrirImagenDeUrl;
  private Action accionAbrirImagen;
  private Action accionGuardarImagen;
  private Action accionGuardarImagenComo;
  private Action accionCerrarLienzo;
  private Action accionImprimirLienzo;
  private Action accionDeshacer;
  private Action accionRehacer;
  private Action accionCopiarImagenAlPortapapeles;
  private Action accionPegarImagenDelPortapapeles;

  /** Constructor. Se asume que el programa se ejecutará como 'applet'. */
  public PintaLlop ()
  {
    esAplicacion = false;
  }

  private void inicializaTodo () throws Exception
  {
    // Gestor de diseño 'BorderLayout'.
    getContentPane ().setLayout (new BorderLayout ());
    // Ningún lienzo en el panel.
    cuentaPestanas = 0;
    // Inicializar la caja para entrar 'URL's.
    cajaURL = new JTextField ();
    // Inicializar el panel con las instruccones (para el menú 'ayuda').
    panelInfo = new PanelInformacion ();
    // Inicializar las acciones (en la barra de menú).
    inicializaAcciones ();
    // Inicializar la barra de menú.
    barraMenu = creaBarraMenu ();
    // Inicializar las herramientas, y la barra de herramientas.
    herramientas = new ColeccionHerramientas ();
    barraHerramientas = creaBarraHerramientas ();
    // Inicializar el panel de propiedades de la herramienta actual.
    panelPropiedades = new PanelPropiedades (herramientas.getHerramientaEnUso ());
    // Inicializar el panel para los lienzos, y luego los mismos lienzos.
    panelLienzo = creaPanelLienzo ();
    coleccionLienzos = new ColeccionLienzos (herramientas);

    // Añadimos todos los componentes al 'applet'.
    setJMenuBar (barraMenu);
    getContentPane ().add (barraHerramientas, BorderLayout.WEST);
    getContentPane ().add (panelPropiedades, BorderLayout.SOUTH);
    getContentPane ().add (panelLienzo, BorderLayout.CENTER);
  }

  /** Crea el panel para los lienzos por defecto.
      @return JTabbedPane  El panel para los lienzos. */
  private JTabbedPane creaPanelLienzo ()
  {
    // Es un 'JTabbedPane' que lleva en cada 'tab' o 'pestaña' un lienzo. Cuando cambia el 'tab'
    // seleccionado, informa a los lienzos de cuál es el nuevo 'protagonista'.
    // El índice de los lienzos se corresponde con el de los 'tabs'.
    JTabbedPane retorno = new JTabbedPane ();
    retorno.addChangeListener (new ChangeListener ()
    {
      public void stateChanged (ChangeEvent e)
      {
        coleccionLienzos.setLienzoActual ((byte) panelLienzo.getSelectedIndex ());
      }
    });
    return retorno;
  }

  /** El método que inicia 'PintaLlop Aplicación'.
      Utiliza el 'applet' como un simple 'Component', y lo añade a un 'JFrame'.
      @param args String []  Argumentos de la línea de comandos. Son obviados. */
  public static void main (String args [])
  {
    // El 'JFrame' al que se añadirá el applet.
    // Termina la aplicación al cerrarse.
    // No puede cambiar de tamaño.
    JFrame marco = new JFrame ("PintaLlop Aplicación");
    marco.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
    marco.setResizable (false);
    marco.setSize (504, 430);
    // Se coloca en el centro de la pantalla, y se hace visible.
    Dimension tamanoPantalla = Toolkit.getDefaultToolkit ().getScreenSize ();
    Dimension tamanoMarco = marco.getSize ();
    if (tamanoMarco.height > tamanoPantalla.height)
      tamanoMarco.height = tamanoPantalla.height;
    if (tamanoMarco.width > tamanoPantalla.width)
      tamanoMarco.width = tamanoPantalla.width;
    marco.setLocation ((tamanoPantalla.width - tamanoMarco.width) / 2,
                      (tamanoPantalla.height - tamanoMarco.height) / 2);
    marco.setVisible (true);

    // Se inicializa el 'applet'; nótese que se le da acceso al portapapeles.
    PintaLlop aplicacion = new PintaLlop ();
    aplicacion.determinaAplicacionOApplet (true);
    aplicacion.init ();
    aplicacion.inicializaPortapapeles ();

    // Se añade el 'applet' al 'marco', se pone el primer lienzo por defecto, y a éste se
    // le da el 'foco'.
    marco.getContentPane ().add (aplicacion);
    aplicacion.nuevoLienzo ();
    marco.validate ();
    aplicacion.coleccionLienzos.getLienzoActual ().requestFocus ();
  }

  /** Toma el portapapeles del sistema como el propio de 'PintaLlop'. */
  private void inicializaPortapapeles ()
  {
    // Es buena idea asegurarse de que el portapapeles del sistema está accesible.
    SecurityManager segurata = System.getSecurityManager ();
    if (segurata != null)
      try
      {
        segurata.checkSystemClipboardAccess ();
      } catch (SecurityException e)
      {
        JOptionPane.showMessageDialog (PintaLlop.this, "No se puede acceder al portapapeles.");
        return;
      }
    clipboard = Toolkit.getDefaultToolkit ().getSystemClipboard ();
  }

  /** La función que inicializa 'PintaLlop Applet'. */
  public void init ()
  {
    try
    {
      inicializaTodo ();
    } catch (Exception e) { System.err.println ("Error al iniciar PintaLlop."); }
  }

  /** Al iniciar el applet, se crea el primer lienzo por defecto, y se da el 'foco'. */
  public void start ()
  {
    nuevoLienzo ();
    coleccionLienzos.getLienzoActual ().requestFocus ();
  }

  /** Obtener información del applet: el nombre del autor. */
  public String getAppletInfo ()
  {
    return "Autor: Albert Lobo, 2005.";
  }

  /** Determina la configuración de ejecución del programa.
      Para que la función surta efecto, debe llamarse antes de 'inicializarTodo ()'.
      @param bool boolean  'true' para ejecutar el programa como aplicación, y 'false' para
                           ejecutarlo como a 'applet'. */
  private void determinaAplicacionOApplet (boolean bool)
  {
    esAplicacion = bool;
  }

  /** Inicializa las acciones para tratar los lienzos. */
  private void inicializaAcciones ()
  {
    // Crear un nuevo lienzo para dibujar.
    accionNuevoLienzo = new AbstractAction ("Nuevo lienzo")
    {
      public void actionPerformed (ActionEvent evento)
      {
        nuevoLienzo ();
      }
    };
    // Abrir una imagen en una URL (ejmplo: "es.geocities.com/imagenes/b1.jpg").
    accionAbrirImagenDeUrl = new AbstractAction ("Abrir imagen de URL")
    {
      public void actionPerformed (ActionEvent evento)
      {
        // Abre un 'Dialog' en el que se puede entrar una URL (en 'cajaURL').
        Object textoBotones [] = {"Aceptar", "Cancelar"};
        int retorno = JOptionPane.showOptionDialog (PintaLlop.this, cajaURL,
                                                    "Entre la URL donde está la imagen",
                                                    JOptionPane.OK_CANCEL_OPTION,
                                                    JOptionPane.PLAIN_MESSAGE,
                                                    null, textoBotones, textoBotones [0]);
        if (retorno == JOptionPane.OK_OPTION)
        {
          // Si el usuario acepta, habrá que hacer un par de comprobaciones:
          // La cadena debe empezar por "http://", y terminar en alguna de las extensiones de imágenes
          // reconocidas: '.gif', '.jpg', y '.png'.
          // Para validar más fácilmente la URL, utilizamos la dirección en minúsculas.
          String cadenaUrl = cajaURL.getText ();
          String cadenaUrlMinusculas = new String (cadenaUrl).toLowerCase ();
          if (!cadenaUrlMinusculas.startsWith ("http://"))
            cadenaUrl = "http://" + cadenaUrl;
          if (!cadenaUrlMinusculas.endsWith (".png") && !cadenaUrlMinusculas.endsWith (".gif")
              && !cadenaUrlMinusculas.endsWith (".jpg") && !cadenaUrlMinusculas.endsWith (".jpeg"))
          {
            JOptionPane.showMessageDialog (PintaLlop.this, "En la URL entrada no hay una imagen reconocida.");
            return;
          }

          // Sacamos la imagen de la URL.
          URL url = null;
          Image i = null;
          try
          {
            url = new URL (cadenaUrl);
            i = ImageIO.read (url);
          } catch (MalformedURLException e) {
          } catch (IOException e) {}

          if (i == null)
          {
            // Si no hay imagen, una de dos: o la URL no existe, o no hay conexión a Internet.
            JOptionPane.showMessageDialog (PintaLlop.this, "La URL entrada no es válida. "
                                           + "Compruebe que está bien escrita.");
            return;
          }
          // Si no hay lienzos abiertos, se crea uno nuevo para pegar la imagen.
          if (coleccionLienzos.getNumeroLienzos () == -1)
            nuevoLienzo ();
          // Pegamos la imagen.
          coleccionLienzos.getLienzoActual ().pegaImagen (i);
        }
      }
    };
    // Abrir una imagen del disco duro.
    accionAbrirImagen = new AbstractAction ("Abrir imagen")
    {
      public void actionPerformed (ActionEvent evento)
      {
        // Se abre el 'JFileChooser' personalizado para que el usuario pueda elegir la imagen.
        SelectorImagenes selector = new SelectorImagenes ("Abrir");
        int opcion = selector.showOpenDialog (null);
        if (opcion == JFileChooser.APPROVE_OPTION)
        {
          // Leemos la imagen.
          Image i = null;
          try
          {
            i = ImageIO.read (selector.getSelectedFile ());
          } catch (IOException e) {}

          if (i == null)
          {
            // El archivo está probablemente corrupto.
            JOptionPane.showMessageDialog (PintaLlop.this, "El archivo no es válido.");
            return;
          }
          // Si no hay lienzos abiertos, se crea uno nuevo para pegar la imagen.
          if (coleccionLienzos.getNumeroLienzos () == -1)
            nuevoLienzo ();
          // Pegamos la imagen.
          coleccionLienzos.getLienzoActual ().pegaImagen (i);
        }
      }
    };
    // Guardar la imagen al disco.
    accionGuardarImagen = new AbstractAction ("Guardar imagen")
    {
      public void actionPerformed (ActionEvent evento)
      {
        // Lo primero es comprobar que el lienzo ya se ha guardado en un archivo.
        // Si no, 'guardamos la imagen como'.
        if (coleccionLienzos.getLienzoActual ().getArchivo() == null)
          guardarImagenComo ();
        else
          try
          {
            ImageIO.write ((RenderedImage)coleccionLienzos.getLienzoActual ().getDibujo (),
                           coleccionLienzos.getLienzoActual ().getExtension (),
                           coleccionLienzos.getLienzoActual ().getArchivo ());
          } catch (IOException e) {}
      }
    };
    // Guardar la imagen al disco en un nuevo archivo.
    accionGuardarImagenComo = new AbstractAction ("Guardar imagen como")
    {
      public void actionPerformed (ActionEvent evento)
      {
        guardarImagenComo ();
      }
    };
    // Imprimir el lienzo.
    accionImprimirLienzo = new AbstractAction ("Imprimir lienzo")
    {
      public void actionPerformed (ActionEvent evento)
      {
        // Lo primero es mirar si hay impresora en este equipo.
        PrinterJob controlImpresion = PrinterJob.getPrinterJob ();
        if (controlImpresion.lookupPrintServices ().length == 0)
        {
          JOptionPane.showMessageDialog (PintaLlop.this, "No hay ninguna impresora disponible.");
          return;
        }

        // Renderizamos el dibujo en el lienzo para que se imprima.
        // Mostramos el 'Dialog' para cambiar propiedades de la impresión, y si el usuario acepta, imprimimos.
        controlImpresion.setPrintable (new Impresion ());
        if (controlImpresion.printDialog ())
        {
          try
          {
            controlImpresion.print ();
          } catch (PrinterException e) {}
        }
      }
    };
    // Cierra el lienzo actualmente en pantalla.
    accionCerrarLienzo = new AbstractAction ("Cerrar lienzo")
    {
      public void actionPerformed (ActionEvent evento)
      {
        // Se destruye el liezo, y se quita el 'tab' del 'panelLienzos'.
        coleccionLienzos.destruyeLienzo ();
        panelLienzo.remove (coleccionLienzos.getNumeroLienzoActual ());
        // Si éste era el último lienzo en pantalla, desactivamos las acciones pertinentes.
        if (coleccionLienzos.getNumeroLienzos () == -1)
          desactivaAccionesNoDisponibles ();
      }
    };
    // Deshacer el último cambio en el lienzo actual.
    accionDeshacer = new AbstractAction ("Deshacer")
    {
      public void actionPerformed (ActionEvent evento)
      {
        coleccionLienzos.getLienzoActual ().deshacer ();
      }
    };
    // Rehacer el último cambio en el lienzo actual.
    accionRehacer = new AbstractAction ("Rehacer")
    {
      public void actionPerformed (ActionEvent evento)
      {
        coleccionLienzos.getLienzoActual ().rehacer ();
      }
    };
    // Copia la imagen en el lienzo actual al portapapeles.
    accionCopiarImagenAlPortapapeles = new AbstractAction ("Copiar imagen al portapapeles")
    {
      public void actionPerformed (ActionEvent evento)
      {
        clipboard.setContents (coleccionLienzos.getLienzoActual (), PintaLlop.this);
      }
    };
    // Pega la imagen del portapapeles al lienzo actual.
    accionPegarImagenDelPortapapeles = new AbstractAction ("Pegar imagen del portapapeles")
    {
      public void actionPerformed (ActionEvent evento)
      {
        // En esta interfaz pondremos información sobre los datos a transferir desde el portapapeles
        // a la aplicación.
        Transferable imagen = null;
        try
        {
          imagen = clipboard.getContents (null);
        } catch (IllegalStateException e)
        {
          JOptionPane.showMessageDialog (PintaLlop.this, "Portapapeles no accesible. "
                                        + "Puede que otro programa lo tenga 'secuestrado'.");
          return;
        }
        // Si había algo en el portapapeles, lo pega como imagen en el lienzo.
        if (imagen != null)
          try
          {
            coleccionLienzos.getLienzoActual ().pegaImagen
                ((Image) imagen.getTransferData (DataFlavor.imageFlavor));
          } catch (UnsupportedFlavorException e) {
          } catch (IOException e) {}
      }
    };
  }

  /** Desactiva las acciones que no deben estar disponibles cuando no hay lienzos en pantalla. */
  private void desactivaAccionesNoDisponibles ()
  {
    accionGuardarImagen.setEnabled (false);
    accionGuardarImagenComo.setEnabled (false);
    accionCerrarLienzo.setEnabled (false);
    accionImprimirLienzo.setEnabled (false);
    accionDeshacer.setEnabled (false);
    accionRehacer.setEnabled (false);
    accionCopiarImagenAlPortapapeles.setEnabled (false);
    accionPegarImagenDelPortapapeles.setEnabled (false);
  }

  /** Activa las acciones que deben estar disponibles cuando hay algún lienzo en pantalla. */
  private void activaAccionesDisponibles ()
  {
    accionGuardarImagen.setEnabled (true);
    accionGuardarImagenComo.setEnabled (true);
    accionCerrarLienzo.setEnabled (true);
    accionImprimirLienzo.setEnabled (true);
    accionDeshacer.setEnabled (true);
    accionRehacer.setEnabled (true);
    accionCopiarImagenAlPortapapeles.setEnabled (true);
    accionPegarImagenDelPortapapeles.setEnabled (true);
  }

  /** Crea la barra de menú por defecto del programa, le añade los menús 'Archivo' y 'Edición',
      y la manda de vuelta.
      @return JMenuBar  La barra de menú. */
  private JMenuBar creaBarraMenu ()
  {
    JMenuBar retorno = new JMenuBar ();

    // Añadimos el menú 'Archivo', y le ponemos los 'items' (en este caso, acciones).
    // Nótese que según se esté ejecutando 'PintaLlop Aplicación' o 'Applet'
    // habrá más o menos acciones disponibles.
    // Hay 'JMenuItems' que tienen 'acelerador'
    // -una combinación de teclas que ejecuta la acción automáticamente.
    JMenu archivo = new JMenu ("Archivo");
    archivo.add (accionNuevoLienzo).setAccelerator
        (KeyStroke.getKeyStroke (KeyEvent.VK_N, KeyEvent.CTRL_MASK));
    archivo.add (accionAbrirImagenDeUrl).setAccelerator
        (KeyStroke.getKeyStroke (KeyEvent.VK_A, KeyEvent.CTRL_MASK + KeyEvent.ALT_MASK));
    if (esAplicacion)
    {
      archivo.add (accionAbrirImagen).setAccelerator
          (KeyStroke.getKeyStroke (KeyEvent.VK_A, KeyEvent.CTRL_MASK));
      archivo.add (accionGuardarImagen).setAccelerator
          (KeyStroke.getKeyStroke (KeyEvent.VK_S, KeyEvent.CTRL_MASK));
      archivo.add (accionGuardarImagenComo).setAccelerator
          (KeyStroke.getKeyStroke (KeyEvent.VK_Z, KeyEvent.CTRL_MASK + KeyEvent.ALT_MASK));
    }
    archivo.add (accionImprimirLienzo).setAccelerator
        (KeyStroke.getKeyStroke (KeyEvent.VK_I, KeyEvent.CTRL_MASK));
    archivo.add (accionCerrarLienzo).setAccelerator
        (KeyStroke.getKeyStroke (KeyEvent.VK_Q, KeyEvent.CTRL_MASK));
    // El botón para terminar la aplicación no tiene sentido en un contexto de 'applet'.
    if (esAplicacion)
    {
      archivo.addSeparator ();
      archivo.add (new AbstractAction ("Salir")
      {
        public void actionPerformed (ActionEvent evento)
        {
          System.exit (0);
        }
      }).setAccelerator (KeyStroke.getKeyStroke (KeyEvent.VK_F4, KeyEvent.ALT_MASK));
    }

    // Añadimos el menú 'Edición', igual que hemos hecho con el 'Archivo'.
    JMenu edicion = new JMenu ("Edición");
    edicion.add (accionDeshacer).setAccelerator
        (KeyStroke.getKeyStroke (KeyEvent.VK_Z, KeyEvent.CTRL_MASK));
    edicion.add (accionRehacer).setAccelerator
        (KeyStroke.getKeyStroke (KeyEvent.VK_Y, KeyEvent.CTRL_MASK));
    if (esAplicacion)
    {
      edicion.addSeparator ();
      edicion.add (accionCopiarImagenAlPortapapeles).setAccelerator
          (KeyStroke.getKeyStroke (KeyEvent.VK_C, KeyEvent.CTRL_MASK));
      edicion.add (accionPegarImagenDelPortapapeles).setAccelerator
          (KeyStroke.getKeyStroke (KeyEvent.VK_V, KeyEvent.CTRL_MASK));
    }

    // Añadimos los 2 menús creados hasta ahora a la 'JMenuBar', y la mandamos de vuelta.
    retorno.add (archivo);
    retorno.add (edicion);
    return retorno;
  }

  /** Crea un nuevo lienzo, y lo añade al panel. */
  private synchronized void nuevoLienzo ()
  {
    // Si es el primer lienzo el que se está creando, activamos las acciones.
    if (coleccionLienzos.getNumeroLienzos () == -1)
      activaAccionesDisponibles ();
    // Intentamos crear el nuevo lienzo.
    if (!coleccionLienzos.creanuevoLienzo ())
      return;
    // Si ha salido bien, se añade al panel de los lienzos.
    panelLienzo.addTab ("Lienzo " + String.valueOf (++cuentaPestanas),
                        coleccionLienzos.getLienzoFinal ());
    coleccionLienzos.setLienzoActual (coleccionLienzos.getNumeroLienzos ());
    coleccionLienzos.preparaNuevoLienzo ();
    panelLienzo.setSelectedIndex (panelLienzo.getTabCount () - 1);
  }

  /** Permite guardar la imagen del lienzo actual al disco.
      Primero, muestra un 'Dialog' en el que se puede elegir el formato de la imagen entre los
      disponibles: '.jpg' o '.png' -no hay codificadores '.gif' en las librerías estándar.
      Luego, muestra un 'SelectorImagenes' para especificar dónde se guardará la imagen. */
  private void guardarImagenComo ()
  {
    // Un 'JRadioButton' para cada formato.
    JRadioButton botonJpg = new JRadioButton ("Formato JPG");
    botonJpg.setSelected (true);
    JRadioButton botonPng = new JRadioButton ("Formato PNG");
    // Un grupo de botones para los 'JRadioButton's.
    ButtonGroup grupoBotones = new ButtonGroup ();
    grupoBotones.add (botonJpg);
    grupoBotones.add (botonPng);
    // Un panel para meter los botones.
    JPanel panelBotones = new JPanel ();
    panelBotones.add (botonJpg);
    panelBotones.add (botonPng);
    Object textoBotones [] = {"Aceptar", "Cancelar"};
    int retorno = JOptionPane.showOptionDialog (PintaLlop.this, panelBotones,
                                                "Elija el formato de la imagen",
                                                JOptionPane.OK_CANCEL_OPTION,
                                                JOptionPane.PLAIN_MESSAGE,
                                                null, textoBotones, textoBotones [0]);
    // El usuario acaba de decidir el formato de la imagen.
    if (retorno == JOptionPane.OK_OPTION)
    {
      if (botonJpg.isSelected ())
        coleccionLienzos.getLienzoActual ().setExtension ("jpg");
      else
        coleccionLienzos.getLienzoActual ().setExtension ("png");
    }
    else
      return;

    // Ahora saltará el 'SelectorImagenes'.
    SelectorImagenes selector = new SelectorImagenes ("Guardar");
    int opcion = selector.showOpenDialog (null);
    if (opcion == JFileChooser.APPROVE_OPTION)
    {
      boolean archivoExiste = false;
      File archivo;
      String nombreArchivoMinusculas = selector.getSelectedFile ().getName ().toLowerCase ();
      if (!nombreArchivoMinusculas.endsWith (coleccionLienzos.getLienzoActual ().getExtension ()))
        archivo = new File (selector.getSelectedFile ().getAbsolutePath () + "."
                            + coleccionLienzos.getLienzoActual ().getExtension ());
      else
        archivo = selector.getSelectedFile ();
      try
      {
        archivoExiste = archivo.createNewFile ();
      } catch (IOException e) {}

      // Estamos creando un nuevo archivo, así que no podemos permitir que otro se sobreescriba.
      if (!archivoExiste)
      {
        JOptionPane.showMessageDialog (PintaLlop.this, "Existe otro archivo con este nombre. Cámbielo.");
        return;
      }

      try
      {
        ImageIO.write ((RenderedImage) coleccionLienzos.getLienzoActual ().getDibujo (),
                       coleccionLienzos.getLienzoActual ().getExtension (), archivo);
      } catch (IOException e)
      {
        JOptionPane.showMessageDialog (PintaLlop.this, "No se ha podido guardar la imagen.");
        return;
      }

      // Indicamos al lienzo dónde está guardado su archivo.
      // Si intentamos 'Guardar', la imagen irá directamente al archivo en el disco.
      coleccionLienzos.getLienzoActual ().setArchivo (archivo);
    }
  }

  /** Tengamos en cuenta cómo funciona la herramienta de texto:
      Al hacer click sobre el lienzo, se indica dónde irá el texto.
      A falta de un cursor más sofisticado, cuando no hay texto, se añade una barra vertical ('|')
      para indicar su posición.
      Si, con la misma herramienta, se vuelve a hacer click con sobre el lienzo, ese cursor quedará
      empastado en el lienzo.
      El solo propósito de esta función es evitar esto. */
  private void terminaTexto ()
  {
    if (herramientas.getHerramientaEnUso ().getTipo () == ColeccionHerramientas.TEXTO)
      if (herramientas.getHerramientaEnUso ().getCadena ().equals ("|"))
      {
        herramientas.getHerramientaEnUso ().setCadena ("");
        coleccionLienzos.getLienzoActual ().pintaTexto ();
      }
  }

  /** Crea la barra de herramientas por defecto, y la manda de vuelta.
      De paso, completa la barra de menú añadiendo los menús 'Propiedades' y 'Ayuda'.
      @return JToolBar  La barra de herramientas. */
  private JToolBar creaBarraHerramientas ()
  {
    // Creamos la barra de herramientas.
    JToolBar retorno = new JToolBar ("Barra de herramientas");
    retorno.setLayout (new GridLayout (6, 1));

    // Creamos el menú 'Herramientas'.
    JMenu menuHerramientas = new JMenu ("Herramientas");
    // Creamos la acción que pone el 'Lápiz' como la herramienta en uso.
    // Añadimos acción a la barra de herramientas, y también al menú 'Herramientas'.
    // Añadiremos con la misma lógica el resto de acciones.
    Action accion = new AbstractAction ("Lápiz", herramientas.getIcono (ColeccionHerramientas.LAPIZ))
    {
      public void actionPerformed (ActionEvent evento)
      {
        terminaTexto ();
        herramientas.setHerramientaEnUso (ColeccionHerramientas.LAPIZ);
        panelPropiedades.setHerramientaEnUso (herramientas.getHerramientaEnUso ());
      }
    };
    retorno.add (accion);
    menuHerramientas.add (accion);
    accion = new AbstractAction ("Goma", herramientas.getIcono (ColeccionHerramientas.GOMA))
    {
      public void actionPerformed (ActionEvent evento)
      {
        terminaTexto ();
        herramientas.setHerramientaEnUso (ColeccionHerramientas.GOMA);
        panelPropiedades.setHerramientaEnUso (herramientas.getHerramientaEnUso ());
      }
    };
    retorno.add (accion);
    menuHerramientas.add (accion);
    accion = new AbstractAction ("Línea", herramientas.getIcono (ColeccionHerramientas.LINEA))
    {
      public void actionPerformed (ActionEvent evento)
      {
        terminaTexto ();
        herramientas.setHerramientaEnUso (ColeccionHerramientas.LINEA);
        panelPropiedades.setHerramientaEnUso (herramientas.getHerramientaEnUso ());
      }
    };
    retorno.add (accion);
    menuHerramientas.add (accion);
    accion = new AbstractAction ("Rectángulo", herramientas.getIcono (ColeccionHerramientas.RECTANGULO))
    {
      public void actionPerformed (ActionEvent evento)
      {
        terminaTexto ();
        herramientas.setHerramientaEnUso (ColeccionHerramientas.RECTANGULO);
        panelPropiedades.setHerramientaEnUso (herramientas.getHerramientaEnUso ());
      }
    };
    retorno.add (accion);
    menuHerramientas.add (accion);
    accion = new AbstractAction ("Óvalo", herramientas.getIcono (ColeccionHerramientas.OVALO))
    {
      public void actionPerformed (ActionEvent evento)
      {
        terminaTexto ();
        herramientas.setHerramientaEnUso (ColeccionHerramientas.OVALO);
        panelPropiedades.setHerramientaEnUso (herramientas.getHerramientaEnUso ());
      }
    };
    retorno.add (accion);
    menuHerramientas.add (accion);
    accion = new AbstractAction ("Texto", herramientas.getIcono (ColeccionHerramientas.TEXTO))
    {
      public void actionPerformed (ActionEvent evento)
      {
        herramientas.setHerramientaEnUso (ColeccionHerramientas.TEXTO);
        panelPropiedades.setHerramientaEnUso (herramientas.getHerramientaEnUso ());
      }
    };
    retorno.add (accion);
    menuHerramientas.add (accion);

    // El resto de función crea el menú 'Ayuda' para la barra de menú.
    JMenu ayuda = new JMenu ("Ayuda");
    // Esta acción hace saltar una ventana con las instrucciones de uso de 'PintaLlop'.
    ayuda.add (new AbstractAction ("Introducción a PintaLlop")
    {
      public void actionPerformed (ActionEvent evento)
      {
        String textoBotones [] = new String [] {"Aceptar"};
        JOptionPane.showOptionDialog (PintaLlop.this, panelInfo, "Introducción a PintaLlop",
                                      JOptionPane.OK_OPTION, JOptionPane.PLAIN_MESSAGE,
                                      null, textoBotones, textoBotones [0]);
      }
    });
    ayuda.addSeparator ();
    // Esta acción hace saltar una ventana con información sobre la versión y el autor de 'PintaLlop'.
    ayuda.add (new AbstractAction ("Acerca de PintaLlop " + (esAplicacion ? "Aplicación" : "Applet"))
    {
      public void actionPerformed (ActionEvent evento)
      {
        String mensajeAcerca = "<HTML>PintaLlop ";
        mensajeAcerca += esAplicacion ? "Aplicación versión 1.0" : "Applet versión 1.0";
        mensajeAcerca += "<BR>Copyright (c) 2005, Albert Lobo";
        JLabel etiqueta = new JLabel (mensajeAcerca);
        etiqueta.setHorizontalAlignment (JLabel.CENTER);
        String textoBotones [] = new String [] {"Aceptar"};
        JOptionPane.showOptionDialog (PintaLlop.this, etiqueta,
                                      "Acerca de PintaLlop " + (esAplicacion ? "Aplicación" : "Applet"),
                                      JOptionPane.OK_OPTION, JOptionPane.PLAIN_MESSAGE,
                                      null, textoBotones, textoBotones [0]);
      }
    });
    // Añadimos los dos menús acabados de crear a la barra de menú.
    barraMenu.add (menuHerramientas);
    barraMenu.add (ayuda);

    // La barra de herramientas se envía de vuelta.
    // ¿Por qué inicializar los otros 2 menús de la 'JMenuBar' aquí?
    // Como tanto la barra de herramientas como la de menú deben tener acceso a las mismas acciones
    // para cambiar de herramienta, las inicializamos en la misma función.
    // El menú 'Ayuda', lógicamente, es el último a añadir a la barra de menú.
    return retorno;
  }

  /** Notifica al applet que ha perdido la posesión del portapapeles.
      No utilizamos ninguno de los argumentos.
      @param nuevoPortapapeles Clipboard  El portapapeles.
      @param transferible Transferable    Datos que este programa ha puesto en el portapapeles. */
  public void lostOwnership (Clipboard nuevoPortapapeles, Transferable transferible)
  {
    JOptionPane.showMessageDialog (PintaLlop.this, "El applet ha perdido la posesión del portapapeles.");
  }

  /** Método estático que proporciona un icono, construido a partir de una imagen
      del fichero de recursos del programa.
      @param imagen String  Nombre de la imagen para el icono.
      @return ImageIcon     El icono con la imagen especificada. */
  public static ImageIcon getIcono (String imagen)
  {
    URL uRL = PintaLlop.class.getResource ("rcsPintaLlop/" + imagen) ;
    if (uRL == null)
    {
      System.err.println (imagen + " no encontrada.");
      return null;
    }
    return new ImageIcon (uRL);
  }

  /** Inicializar las variables estáticas:
      Define el 'look'n'feel' del programa, e inicializa los cursores para los lienzos. */
  static
  {
    try
    {
      UIManager.setLookAndFeel (new MetalLookAndFeel ());
    } catch (Exception e) {}

    cursorLapiz = Toolkit.getDefaultToolkit ().createCustomCursor
        (PintaLlop.getIcono ("cursorLapiz.gif").getImage (), new Point (4, 28), "CursorLápiz");
    cursorGoma = Toolkit.getDefaultToolkit ().createCustomCursor
        (PintaLlop.getIcono ("cursorGoma.gif").getImage (), new Point (2, 25), "CursorGoma");
    cursorTexto = new Cursor (Cursor.TEXT_CURSOR);
    cursorCruz = new Cursor (Cursor.CROSSHAIR_CURSOR);
  }

  /** Interfaz que se encarga de imprimir. */
  class Impresion implements Printable
  {
    /** Imprime la imagen en el lienzo actual.
        Cuando se llama a la función 'print ()' de 'PrintJob', ésta a su vez llama al 'print ()'
        de esta interfaz, 'Printable'.
        @param graficos Graphics         Contexto 'Graphics' sobre el que se dibuja la imagen.
        @param formatoPagina PageFormat  El tamaño y la orientación de la página a imprimir.
        @param indicePagina int          Índice de la página que se imprimirá.
        @throws PrinterException         Excepción lanzada al terminar la impresión.
        @return int                      'Printable.PAGE_EXISTS' -asumimos que, llegado este punto,
                                         la imagen a imprimir se renderizará siempre. */
    public int print (Graphics graficos, PageFormat formatoPagina, int indicePagina) throws PrinterException
    {
      // Para que no se líe a imprimir infinitas páginas, indicamos que después de la primera 
      // página ya no necesita imprimir más.
      if (indicePagina >= 1)
        return Printable.NO_SUCH_PAGE;
      
      graficos.drawImage (coleccionLienzos.getLienzoActual ().getDibujo (),
                          (int) formatoPagina.getImageableX (), (int) formatoPagina.getImageableY (), null);
      return Printable.PAGE_EXISTS;
    }
  }

  /** Clase interna que extiende 'JScrollPane'.
      Lleva un 'JEditorPane' en el que incrustamos una página HTML con información acerca del programa. */
  class PanelInformacion extends JScrollPane
  {
    // Panel en el que pegaremos el archivo HTML.
    private JEditorPane pnlEdtr;

    /** Constructor. */
    public PanelInformacion ()
    {
      // Llamada al constructor de la superclase. La barra deslizante debe ser vertical.
      super ();
      setPreferredSize (new Dimension (600, 400));
      setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
      // Inicializa 'pnlEdtr', se hace no editable, y se incrusta la página web.
      pnlEdtr = new JEditorPane ();
      pnlEdtr.setEditable (false);
      try
      {
        pnlEdtr.setPage (PintaLlop.class.getResource ("rcsPintaLlop/info.htm"));
      } catch (IOException e) {}

      setViewportView (pnlEdtr);
    }
  }
}

¿Comentarios, sugerencias?: llopsite.at.yahoo.es | © 2005-07 Albert Lobo

Última actualización: 18-Feb-2007

Hosted by www.Geocities.ws

1