/**
   @version 1.01 2004-08-22
   @author Cay Horstmann
*/

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

/**
   Program demonstrujący sortowanie tabeli według wybranej kolumny.
   W celu przesortowania tabeli należy dwukrotnie kliknąć jedną z kolumn.
*/
public class TableSortTest
{  
   public static void main(String[] args)
   {  
      JFrame frame = new TableSortFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setVisible(true);
   }
}

/**
   Ramka zawierająca tabelę danych o planetach.
*/
class TableSortFrame extends JFrame
{  
   public TableSortFrame()
   {  
      setTitle("TableSortTest");
      setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

      // tworzy model tabeli oraz model filtra

      DefaultTableModel model = new DefaultTableModel(cells, columnNames);
      final SortFilterModel sorter = new SortFilterModel(model);

      // pokazuje tabelę

      final JTable table = new JTable(sorter);
      add(new JScrollPane(table), BorderLayout.CENTER);

      // dodaje obiekt nasłuchujący dwukrotnych kliknięć 
      // nagłówka tabeli


      table.getTableHeader().addMouseListener(new 
         MouseAdapter()
         {  
            public void mouseClicked(MouseEvent event)
            {  
               // czy dwukrotne kliknięcie?
               if (event.getClickCount() < 2) return;

               // sprawdza, dla której kolumny
               int tableColumn = table.columnAtPoint(event.getPoint());

               // zamienia indeks kolumny na indeks kolumny w modelu
               int modelColumn = table.convertColumnIndexToModel(tableColumn);
               sorter.sort(modelColumn);
            }
         });
   }

   private Object[][] cells =
   {  
      { "Mercury", 2440.0,  0, false, Color.yellow },    
      { "Venus", 6052.0, 0, false, Color.yellow },
      { "Earth", 6378.0, 1, false, Color.blue },
      { "Mars", 3397.0, 2, false, Color.red },
      { "Jupiter", 71492.0, 16, true, Color.orange },
      { "Saturn", 60268.0, 18, true, Color.orange },
      { "Uranus", 25559.0, 17, true, Color.blue },
      { "Neptune", 24766.0, 8, true, Color.blue },
      { "Pluto", 1137.0, 1, false, Color.black }
   };

   private String[] columnNames = { "Planet", "Radius", "Moons", "Gaseous", "Color" };

   private static final int DEFAULT_WIDTH = 400;
   private static final int DEFAULT_HEIGHT = 200;
}

/**
   Model tabeli wykorzystujący oryginalny model tabeli 
   i sortujący wiersze tabeli według wybranej kolumny.
*/
class SortFilterModel extends AbstractTableModel
{
   /**
      Tworzy model filtra sortującego.
      @param m wyjściowy model tabeli
   */
   public SortFilterModel(TableModel m)
   {  
      model = m;
      rows = new Row[model.getRowCount()];
      for (int i = 0; i < rows.length; i++)
      {  
         rows[i] = new Row();
         rows[i].index = i;
      }
   }

   /**
      Sortuje wiersze tabeli.
      @param c kolumna, według której odbywa się sortowanie
   */
   public void sort(int c)
   {  
      sortColumn = c;
      Arrays.sort(rows);
      fireTableDataChanged();
   }

   // Dla poniższych metod musi najpierw zostać wyznaczony
   // odpowiedni wiersz

   public Object getValueAt(int r, int c) { return model.getValueAt(rows[r].index, c); }

   public boolean isCellEditable(int r, int c) { return model.isCellEditable(rows[r].index, c); }

   public void setValueAt(Object aValue, int r, int c) 
   { 
      model.setValueAt(aValue, rows[r].index, c);
   }

   // pozostałe wywołania metod delegowane są do modelu wyjściowego

   public int getRowCount() { return model.getRowCount(); }
   public int getColumnCount() { return model.getColumnCount(); }
   public String getColumnName(int c) { return model.getColumnName(c); }
   public Class getColumnClass(int c) { return model.getColumnClass(c); }

   /** 
      Klasa wewnętrzna przechowująca indeks wiersza w modelu.
      Wiersze porównywane są na podstawie wartości modelu w kolumnie, 
      według której sortowana jest tabela.
   */
   private class Row implements Comparable<Row>
   {  
      public int index;
      public int compareTo(Row other)
      {  
         Object a = model.getValueAt(index, sortColumn);
         Object b = model.getValueAt(other.index, sortColumn);
         if (a instanceof Comparable)
            return ((Comparable) a).compareTo(b);
         else
            return a.toString().compareTo(b.toString());
      }
   }

   private TableModel model;
   private int sortColumn;
   private Row[] rows;
}

