// -*- 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 java.util.Optional;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

public final class MainPanel extends JPanel {
  private final JTable table = new JTable(new DefaultTableModel(10, 10)) {
    private transient HighlightListener highlighter;
    @Override public void updateUI() {
      removeMouseListener(highlighter);
      removeMouseMotionListener(highlighter);
      super.updateUI();
      // setAutoCreateRowSorter(true);
      setRowSelectionAllowed(false);

      highlighter = new HighlightListener();
      addMouseListener(highlighter);
      addMouseMotionListener(highlighter);

      setDefaultRenderer(Object.class, new HighlightRenderer(highlighter));
      setDefaultRenderer(Number.class, new HighlightRenderer(highlighter));
    }
  };

  private MainPanel() {
    super(new BorderLayout());
    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 HighlightListener extends MouseAdapter {
  private static final Color HIGHLIGHT1 = new Color(0xC8_C8_FF);
  private static final Color HIGHLIGHT2 = new Color(0xF0_F0_FF);
  private int vrow = -1; // viewRowIndex
  private int vcol = -1; // viewColumnIndex

  public Optional<? extends Color> getHighlightableCellColor(int row, int column) {
    if (this.vrow == row || this.vcol == column) {
      if (this.vrow == row && this.vcol == column) {
        return Optional.of(HIGHLIGHT1);
      } else {
        return Optional.of(HIGHLIGHT2);
      }
    }
    return Optional.empty();
  }

  private void setHighlighTableCell(MouseEvent e) {
    Point pt = e.getPoint();
    Component c = e.getComponent();
    if (c instanceof JTable) {
      JTable table = (JTable) c;
      vrow = table.rowAtPoint(pt);
      vcol = table.columnAtPoint(pt);
      if (vrow < 0 || vcol < 0) {
        vrow = -1;
        vcol = -1;
      }
      table.repaint();
    }
  }

  @Override public void mouseMoved(MouseEvent e) {
    setHighlighTableCell(e);
  }

  @Override public void mouseDragged(MouseEvent e) {
    setHighlighTableCell(e);
  }

  @Override public void mouseExited(MouseEvent e) {
    vrow = -1;
    vcol = -1;
    e.getComponent().repaint();
  }
}

class HighlightRenderer extends DefaultTableCellRenderer {
  private final transient HighlightListener highlighter;

  protected HighlightRenderer(HighlightListener highlighter) {
    super();
    this.highlighter = highlighter;
  }

  @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    setHorizontalAlignment(value instanceof Number ? RIGHT : LEFT);
    setBackground(table.getBackground());
    highlighter.getHighlightableCellColor(row, column).ifPresent(this::setBackground);
    return this;
  }
}

// class HighlightableTable extends JTable {
//   private final HighlightListener highlighter;
//   protected HighlightableTable(TableModel model) {
//     super(model);
//     highlighter = new HighlightListener(this);
//     addMouseListener(highlighter);
//     addMouseMotionListener(highlighter);
//   }
//   @Override public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
//     Component c = super.prepareRenderer(renderer, row, column);
//     if (highlighter.isHighlightableCell(row, column)) {
//       c.setBackground(Color.RED);
//     } else if (isRowSelected(row)) {
//       c.setBackground(getSelectionBackground());
//     } else {
//       c.setBackground(Color.WHITE);
//     }
//     return c;
//   }
// }

@@ -2144,16 +2144,20 @@
 lor%3E get
+Cell
 Highligh
@@ -2153,32 +2153,24 @@
 ellHighlight
-ableCell
 Color(int ro
@@ -3695,16 +3695,20 @@
 hter.get
+Cell
 Highligh
@@ -3708,24 +3708,16 @@
 ighlight
-ableCell
 Color(ro
@@ -3788,24 +3788,28 @@
 %7D%0A%0A// class 
+Cell
 Highlightabl
@@ -3801,28 +3801,24 @@
 ellHighlight
-able
 Table extend
@@ -3885,32 +3885,36 @@
 %0A//   protected 
+Cell
 HighlightableTab
@@ -3906,20 +3906,16 @@
 ighlight
-able
 Table(Ta

rename the method