/* 
* Copyright 2016 Agencia Estatal de Administración Tibutaria
*
* Licencia con arreglo a la EUPL, Versión 1.1 o –en cuanto
* sean aprobadas por la Comisión Europea– versiones
* posteriores de la EUPL (la «Licencia»);
* Solo podrá usarse esta obra si se respeta la Licencia.
* Puede obtenerse una copia de la Licencia en:
*  
* https://joinup.ec.europa.eu/software/page/eupl
*  
* Salvo cuando lo exija la legislación aplicable o se acuerde
* por escrito, el programa distribuido con arreglo a la
* Licencia se distribuye «TAL CUAL», SIN GARANTÍAS NI CONDICIONES
* DE NINGÚN TIPO, ni expresasni implícitas.
*
* Véase la Licencia en el idioma concreto que rige los permisos y 
* limitaciones que establece la Licencia.
*/ 

package javax.swing.grid;

import java.awt.Component;
import java.awt.event.*;
import java.awt.Font;
import java.io.Serializable;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.table.*;

public class JGrid extends JTable implements Serializable {

   private int cabeceraColumnaPulsada = -1;
   private int celdaFilaPulsada = -1;
   private int celdaColumnaPulsada = -1;
   private ArrayList<Integer> columnasBotones;
   private JLabel botonFila;
   private boolean cabeceraResaltada = false;
   private boolean cabeceraPulsable = false;
   private EventListenerList mlistenerList;

   public JGrid() {
      super();
      mlistenerList = new EventListenerList();
      columnasBotones = new ArrayList<Integer>();
      preparaCabecera();
      preparaBotonFila();
   }

   void preparaCabecera() {
      if (cabeceraPulsable || cabeceraResaltada) {
         tableHeader.setDefaultRenderer(new BotonCabeceraRenderer());
      }
      if (cabeceraPulsable) {
         tableHeader.addMouseListener(new HeaderMouseListener());
      }
   }

   void preparaBotonFila() {
      botonFila = new JLabel();
      botonFila.setBackground(tableHeader.getBackground());
      Font fuente = botonFila.getFont();
      botonFila.setFont(fuente.deriveFont(Font.PLAIN));
      botonFila.setOpaque(true);
   }

   public JLabel etiquetaBoton() {
      return botonFila;
   }

   public void ponColumnaFija(int v) {
      if (columnasBotones.contains(v)) {
         return;
      }
      columnasBotones.add(v);
      columnModel.getColumn(v).setCellRenderer(new BotonFilaRenderer());
   }

   public void quitaColumnaFija(int v) {
      if (!columnasBotones.contains(v)) {
         return;
      }
      columnasBotones.remove(v);
      columnModel.getColumn(v).setCellRenderer(new DefaultTableCellRenderer());
   }

   protected void processMouseEvent(MouseEvent e) {
      int colTabla = columnAtPoint(e.getPoint());
      int colModel = convertColumnIndexToModel(colTabla);
      if (columnasBotones.contains(colModel)) {
         int fila = rowAtPoint(e.getPoint());
         switch (e.getID()) {
            case MouseEvent.MOUSE_PRESSED:
               celdaFilaPulsada = fila;
               celdaColumnaPulsada = colTabla;
               repaint();
               break;
            case MouseEvent.MOUSE_RELEASED:
               celdaFilaPulsada = -1;
               lanzaCeldaPulsada(fila, colModel);
               repaint();
               break;
         }
      }
      super.processMouseEvent(e);
   }

   class BotonCabeceraRenderer extends DefaultTableCellRenderer {

      Border bordeNormal;
      Border bordePresionado;

      public BotonCabeceraRenderer() {
         if (cabeceraResaltada) {
            bordeNormal = BorderFactory.createBevelBorder(SoftBevelBorder.RAISED);
            bordePresionado = null;
         } else {
            bordeNormal = BorderFactory.createEtchedBorder();
            bordePresionado = BorderFactory.createBevelBorder(SoftBevelBorder.LOWERED);
         }
      }

      public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
              boolean hasFocus, int row, int column) {
         if (column == cabeceraColumnaPulsada) {
            this.setBorder(bordePresionado);
         } else {
            this.setBorder(bordeNormal);
         }
         this.setHorizontalAlignment(SwingConstants.CENTER);
         this.setValue(value);
         return this;
      }
   }

   class BotonFilaRenderer extends DefaultTableCellRenderer {

      Border bordeNormal;
      Border bordePresionado;

      public BotonFilaRenderer() {
         bordeNormal = BorderFactory.createBevelBorder(SoftBevelBorder.RAISED);
         bordePresionado = null;
      }

      public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
              boolean hasFocus, int row, int column) {
         if (row == celdaFilaPulsada && column == celdaColumnaPulsada) {
            botonFila.setBorder(bordePresionado);
         } else {
            botonFila.setBorder(bordeNormal);
         }
         botonFila.setText((String) value);
         return botonFila;
      }
   }

   class HeaderMouseListener extends MouseAdapter {

      public void mousePressed(MouseEvent ev) {
         int col = tableHeader.columnAtPoint(ev.getPoint());
         cabeceraColumnaPulsada = col;
         tableHeader.repaint();
      }

      public void mouseReleased(MouseEvent ev) {
         if (cabeceraColumnaPulsada != -1) {
            int sePulso = cabeceraColumnaPulsada;
            cabeceraColumnaPulsada = -1;
            lanzaCabeceraPulsada(sePulso);
            tableHeader.repaint();
         }
      }
   }

   public boolean isCabeceraResaltada() {
      return cabeceraResaltada;
   }

   public void setCabeceraResaltada(boolean cabeceraResaltada) {
      if (this.cabeceraResaltada != cabeceraResaltada) {
         this.cabeceraResaltada = cabeceraResaltada;
         preparaCabecera();
      }
   }

   public boolean isCabeceraPulsable() {
      return cabeceraPulsable;
   }

   public void setCabeceraPulsable(boolean cabeceraPulsable) {
      if (cabeceraPulsable != this.cabeceraPulsable) {
         this.cabeceraPulsable = cabeceraPulsable;
         preparaCabecera();
      }
   }

   /**
    * Gestion de eventos de las cabeceras
    */
   public void addCabeceraPulsadaListener(CabeceraPulsadaListener listener) {
      mlistenerList.add(CabeceraPulsadaListener.class, listener);
   }

   public void removeCabeceraPulsadaListener(CabeceraPulsadaListener listener) {
      mlistenerList.remove(CabeceraPulsadaListener.class, listener);
   }

   public void lanzaCabeceraPulsada(int columna) {
      CeldaPulsadaEvent evt = new CeldaPulsadaEvent(this, 0, columna);
      EventListener[] listeners = mlistenerList.getListeners(CabeceraPulsadaListener.class);
      for (int i = 0; i < listeners.length; i++) {
         CabeceraPulsadaListener listener = (CabeceraPulsadaListener) listeners[i];
         listener.cabeceraPulsada(evt);
      }
   }

   /*********************************************************
    * Gestion de eventos de los botones de columna
    *******************************************************/
   public void addCeldaPulsadaListener(CeldaPulsadaListener listener) {
      mlistenerList.add(CeldaPulsadaListener.class, listener);
   }

   public void removeCeldaPulsadaListener(CeldaPulsadaListener listener) {
      mlistenerList.remove(CeldaPulsadaListener.class, listener);
   }

   public void lanzaCeldaPulsada(int fila, int columna) {
      CeldaPulsadaEvent evt = new CeldaPulsadaEvent(this, fila, columna);
      EventListener[] listeners = mlistenerList.getListeners(CeldaPulsadaListener.class);
      for (int i = 0; i < listeners.length; i++) {
         CeldaPulsadaListener listener = (CeldaPulsadaListener) listeners[i];
         listener.celdaPulsada(evt);
      }
   }
}
