// -*- mode:java; encoding:utf-8 -*-
// vim:set fileencoding=utf-8:
// @homepage@

package example;

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

public final class MainPanel extends JPanel {
  private MainPanel() {
    super(new BorderLayout());
    String[] columnNames = {"String", "Integer", "Boolean"};
    Object[][] data = {
      {"aaa", 12, true}, {"bbb", 5, false},
      {"ccc", 92, true}, {"ddd", 0, false}
    };
    TableModel model = new DefaultTableModel(data, columnNames) {
      @Override public Class<?> getColumnClass(int column) {
        return getValueAt(0, column).getClass();
      }

      @Override public boolean isCellEditable(int row, int column) {
        return column != 0;
      }
    };
    JTable table = new JTable(model) {
      private transient RowHeaderRenderer handler;
      @Override public void updateUI() {
        getColumnModel().getColumn(0).setCellRenderer(null);
        removeMouseListener(handler);
        removeMouseMotionListener(handler);
        super.updateUI();
        handler = new RowHeaderRenderer();
        getColumnModel().getColumn(0).setCellRenderer(handler);
        addMouseListener(handler);
        addMouseMotionListener(handler);
      }
    };
    table.setAutoCreateRowSorter(true);
    table.setRowHeight(24);
    // table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    // table.getTableHeader().setReorderingAllowed(false);

    add(new JScrollPane(table));
    setPreferredSize(new Dimension(320, 240));
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(MainPanel::createAndShowGui);
  }

  private static void createAndShowGui() {
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
      ex.printStackTrace();
      Toolkit.getDefaultToolkit().beep();
    }
    JFrame frame = new JFrame("@title@");
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new MainPanel());
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}

class RowHeaderRenderer extends MouseAdapter implements TableCellRenderer {
  private final JLabel renderer = new JLabel();
  private int rollOverRowIndex = -1;

  @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    TableCellRenderer tcr = table.getTableHeader().getDefaultRenderer();
    boolean f = row == rollOverRowIndex;
    JLabel l = (JLabel) tcr.getTableCellRendererComponent(table, value, isSelected, f || hasFocus, -1, -1);
    if (tcr.getClass().getName().contains("XPDefaultRenderer")) {
      l.setOpaque(!f);
      renderer.setIcon(new ComponentIcon(l));
      return renderer;
    } else {
      return l;
    }
  }

  // @Override public void mouseMoved(MouseEvent e) {
  //   JTable table = (JTable) e.getSource();
  //   Point pt = e.getPoint();
  //   int column = table.convertColumnIndexToModel(table.columnAtPoint(pt));
  //   rollOverRowIndex = column == 0 ? table.rowAtPoint(pt) : -1;
  //   table.repaint();
  // }

  // @Override public void mouseExited(MouseEvent e) {
  //   JTable table = (JTable) e.getSource();
  //   rollOverRowIndex = -1;
  //   table.repaint();
  // }

  @Override public void mouseMoved(MouseEvent e) {
    JTable table = (JTable) e.getComponent();
    Point pt = e.getPoint();
    int col = table.columnAtPoint(pt);
    int column = table.convertColumnIndexToModel(col);
    if (column != 0) {
      return;
    }
    int prevRow = rollOverRowIndex;
    rollOverRowIndex = table.rowAtPoint(pt);
    if (rollOverRowIndex == prevRow) {
      return;
    }
    Rectangle repaintRect;
    if (rollOverRowIndex >= 0) {
      Rectangle r = table.getCellRect(rollOverRowIndex, col, false);
      repaintRect = prevRow >= 0 ? r.union(table.getCellRect(prevRow, col, false)) : r;
    } else {
      repaintRect = table.getCellRect(prevRow, col, false);
    }
    table.repaint(repaintRect);
  }

  @Override public void mouseExited(MouseEvent e) {
    JTable table = (JTable) e.getComponent();
    Point pt = e.getPoint();
    int col = table.columnAtPoint(pt);
    int column = table.convertColumnIndexToModel(col);
    if (column != 0) {
      return;
    }
    if (rollOverRowIndex >= 0) {
      table.repaint(table.getCellRect(rollOverRowIndex, col, false));
    }
    rollOverRowIndex = -1;
  }
}

class ComponentIcon implements Icon {
  private final Component cmp;

  protected ComponentIcon(Component cmp) {
    this.cmp = cmp;
  }

  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    SwingUtilities.paintComponent(g, cmp, c.getParent(), x, y, getIconWidth(), getIconHeight());
  }

  @Override public int getIconWidth() {
    return 4000; // Short.MAX_VALUE;
  }

  @Override public int getIconHeight() {
    return cmp.getPreferredSize().height + 4; // XXX: +4 for Windows 7
  }
}

@@ -523,16 +523,18 @@
 %7B%0A      
+  
 %7B%22aaa%22, 
@@ -562,22 +562,16 @@
  false%7D,
-%0A     
  %7B%22ccc%22,
@@ -2764,16 +2764,20 @@
 oolean f
+ocus
  = row =
@@ -2799,32 +2799,42 @@
 dex;
-%0A    JLabel l = (JLabel)
+ // %7C%7C hasFocus;%0A    Component c =
  tcr
@@ -2891,24 +2891,16 @@
 ected, f
- %7C%7C hasF
 ocus, -1
@@ -2914,16 +2914,43 @@
     if (
+c instanceof JComponent && 
 tcr.getC
@@ -3005,17 +3005,32 @@
 %7B%0A      
-l
+((JComponent) c)
 .setOpaq
@@ -3034,16 +3034,20 @@
 paque(!f
+ocus
 );%0A     
@@ -3082,17 +3082,17 @@
 entIcon(
-l
+c
 ));%0A    
@@ -3111,34 +3111,25 @@
 derer;%0A    %7D
- else %7B%0A  
+%0A
     return l
@@ -3131,16 +3131,10 @@
 urn 
-l;%0A    %7D
+c;
 %0A  %7D

add instanceof check