/*
 * HugeTableModel.java	1.0 
 *
 * Copyright (c) 1999 Emmanuel PUYBARET - eTeks.
 * All Rights Reserved.
 *
 */

import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
import java.util.*;

// Classe heritant de la classe AbstractTableModel
// AbstractTableModel
public class HugeTableModel extends AbstractTableModel
{
  private int  rowCount;    // Nombre de lignes
  private int  columnCount; // Nombre de colonnes
  
  // Table de hash memorisant les valeurs des cellules
  private Hashtable cellValues = new Hashtable ();
  
  // Les instances de la classe interne CellKey sont utilisees 
  // comme cle de hash pour acceder a la valeur d'une cellule 
  // stockee dans cellValues.
  private class CellKey
  {
    private int row;    // Ligne
    private int column; // Colonne

    // Constructeur 
    public CellKey (int row, int column)
    {
      this.row    = row;
      this.column = column;
    }

    // Methode de la classe Object outrepassee pour renvoyer
    // true si object et this designe la meme cellule.                  
    public boolean equals (Object object)
    {
      return    object instanceof CellKey
             && ((CellKey)object).row == row
             && ((CellKey)object).column == column;
    }
  
    // Methode de la classe Object outrepassee pour renvoyer
    // un code de hash. La valeur retournee doit etre la meme
    // pour deux objets designant la meme cellule.
    public int hashCode ()
    {
      return (row % 0xFFFF) | ((column % 0xFFFF) << 16);
    }
  }

  // Constructeur par defaut
  public HugeTableModel ()
  {
    this (Short.MAX_VALUE, Short.MAX_VALUE); 
  }
  
  // Constructeur avec le nombre de lignes et de colonnes
  public HugeTableModel (int rowCount, int columnCount)
  {
    this.rowCount     = rowCount;
    this.columnCount  = columnCount;
  }
  
  // Doit renvoyer le nombre de lignes
  public int getRowCount ()
  {
    return rowCount;
  }

  // Doit renvoyer le nombre de colonnes
  public int getColumnCount ()
  {
    return columnCount;
  }

  public boolean isCellEditable (int row, int column) 
  {
    // Autorisation d'editer toutes les cellules
    return true;
  }
  
  public Object getValueAt (int row, int column)
  {
    // Recherche de la valeur stockee dans la table de hash
    return cellValues.get (new CellKey (row, column));
  }
  
  public void setValueAt (Object value, int row, int column) 
  {    
    CellKey key = new CellKey (row, column);
    if (value == null)
      // Suppression de la table de hash si la valeur est nulle 
      cellValues.remove (key);
    else
      // Ajout de la valeur a la table de hash 
      cellValues.put (key, value);           
    // Avertissement des listeners
    fireTableChanged (new TableModelEvent (this, row, row, column));
  }
  
  // Methode main () d'exemple de mise en oeuvre.
  // Utilisation : java HugeTableModel
  public static void main (String [] args)
  {
    // Creation d'un modele de table pouvant stocker
    // 1000 lignes x 100 colonnes = 100 000 cellules
    TableModel  tableModel = new HugeTableModel (1000, 100);

    // Creation d'un tableau utilisant ce modele
    JTable      table = new JTable (tableModel);    
    table.setAutoResizeMode (JTable.AUTO_RESIZE_OFF);

    // Ajout du tableau a une zone avec ascenseur 
    JScrollPane scrollPane = new JScrollPane (table);
    // Creation d'une fenetre d'exemple
    JFrame      frame = new JFrame ("Exemple de table");
    frame.getContentPane ().add (scrollPane);
    frame.pack ();
    frame.show ();
  }
}
