/*
* This file is part of ADDIS (Aggregate Data Drug Information System).
* ADDIS is distributed from http://drugis.org/.
* Copyright © 2009 Gert van Valkenhoef, Tommi Tervonen.
* Copyright © 2010 Gert van Valkenhoef, Tommi Tervonen, Tijs Zwinkels,
* Maarten Jacobs, Hanno Koeslag, Florin Schimbinschi, Ahmad Kamal, Daniel
* Reid.
* Copyright © 2011 Gert van Valkenhoef, Ahmad Kamal, Daniel Reid, Florin
* Schimbinschi.
* Copyright © 2012 Gert van Valkenhoef, Daniel Reid, Joël Kuiper, Wouter
* Reckman.
* Copyright © 2013 Gert van Valkenhoef, Joël Kuiper.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.drugis.addis.gui.components;
import java.awt.AWTKeyStroke;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JWindow;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.table.TableModel;
@SuppressWarnings("serial")
abstract public class JTableWithPopupEditor extends JTable {
protected Window d_parent;
private JWindow d_window;
private JLabel d_hidden;
private int d_row = 0;
private int d_col = 0;
public JTableWithPopupEditor(TableModel model, Window frame) {
super(model);
d_parent = frame;
setCellSelectionEnabled(true);
if (d_parent == null) {
return;
}
// Mouse listener to start editing cell
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int row = ((JTable)e.getComponent()).rowAtPoint(e.getPoint());
int col = ((JTable)e.getComponent()).columnAtPoint(e.getPoint());
startCellEditor(row, col);
}
});
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE || e.getKeyCode() == KeyEvent.VK_ENTER) {
int col = getSelectedColumn();
int row = getSelectedRow();
if (row >= 0 && col >= 0) {
e.consume();
startCellEditor(row, col);
}
}
}
});
// Make sure the window closes when our hidden field gains focus
d_hidden = new JLabel();
d_hidden.setFocusable(true);
FocusAdapter destroyInputListener = new FocusAdapter() {
@Override
public void focusGained(FocusEvent ev) {
destroyInputWindow();
}
};
d_hidden.addFocusListener(destroyInputListener);
d_parent.addFocusListener(destroyInputListener);
addFocusListener(destroyInputListener);
addAncestorListener(new AncestorListener() {
public void ancestorRemoved(AncestorEvent event) {
destroyInputWindow();
}
public void ancestorMoved(AncestorEvent event) {
positionWindow();
}
public void ancestorAdded(AncestorEvent e) {
}
});
addHierarchyListener(new HierarchyListener() {
@Override
public void hierarchyChanged(HierarchyEvent e) {
if(e.getChanged() instanceof JScrollPane) {
registerDestroyInputMouseListener(e.getChanged());
}
}
});
}
private void positionWindow() {
if (d_window != null) {
setWindowLocation();
}
}
abstract protected JPanel createEditorPanel(int row, int col);
private JWindow startCellEditor(int row, int col) {
destroyInputWindow();
JPanel panel = createEditorPanel(row, col);
if (panel == null) {
return null;
}
for (Component c : panel.getComponents()) {
c.addKeyListener(new KeyAdapter() {
@Override public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
destroyInputWindow();
}
}
});
Set<AWTKeyStroke> keys = new HashSet<AWTKeyStroke>(c.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
keys.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_ENTER, 0));
c.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, keys);
}
panel.add(d_hidden);
// create the window
final JWindow window = new JWindow(d_parent);
d_window = window;
window.getContentPane().add(panel, BorderLayout.CENTER);
window.pack();
d_col = col;
d_row = row;
setWindowLocation();
// Make sure the window closes when we click in the frame containing the table
getTopLevelAncestor().addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
destroyInputWindow();
}
});
window.setVisible(true);
// Make sure the first component has focus
window.requestFocusInWindow();
window.getFocusTraversalPolicy().getFirstComponent(window).requestFocus();
return window;
}
private void setWindowLocation() {
Rectangle cellLocation = getCellRect(d_row, d_col, false);
Point l = getComponentAt(d_col, d_row).getLocationOnScreen();
l.translate(cellLocation.x + cellLocation.width / 2, cellLocation.y + cellLocation.height / 2);
d_window.setLocation(l);
}
public void destroyInputWindow() {
if (d_window != null) {
d_window.dispose();
d_window = null;
}
}
private void registerDestroyInputMouseListener(Component component) {
component.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
destroyInputWindow();
}
});
}
}