package gdxstudio.panel;
import gdxstudio.Style;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;
import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JSpinner.DefaultEditor;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import web.laf.lite.layout.ToolbarLayout;
import web.laf.lite.layout.VerticalFlowLayout;
import web.laf.lite.utils.UIUtils;
import web.laf.lite.widget.NumberTextField;
public abstract class BaseTable extends JPanel implements ActionListener, TableModelListener {
private static final long serialVersionUID = 1L;
protected DefaultTableModel tableModel = new DefaultTableModel(){
private static final long serialVersionUID = 1L;
@Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
public boolean isCellEditable(int row, int column) {
if (column == 1)
return true;
return false;
}
};
public final JTable table = new JTable(tableModel){
private static final long serialVersionUID = 1L;
public TableCellEditor getCellEditor(int row, int column)
{
int modelColumn = convertColumnIndexToModel( column );
if (modelColumn == 1){
if(row<editors.size())
return editors.get(row);
}
return super.getCellEditor(row, column);
}
};
protected final JScrollPane scrollPane;
protected final List<TableCellEditor> editors = new ArrayList<TableCellEditor>(3);
protected final JButton headerButton;
public BaseTable(String title, DefaultTableModel model, DefaultTableCellRenderer renderer){
super(new VerticalFlowLayout());
if(model != null)
tableModel = model;
UIUtils.setShadeWidth(this, 0);
UIUtils.setRound(this, 0);
//UIUtils.setDrawSides(this, false, false, false, false);
table.setTableHeader(null);
if(renderer != null)
table.setDefaultRenderer(String.class, renderer);
else
table.setDefaultRenderer(String.class, new BaseRenderer());
table.setShowGrid(true);
table.setColumnSelectionAllowed(false);
table.setRowSelectionAllowed(false);
table.setCellSelectionEnabled(true);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
tableModel.setColumnCount(2);
tableModel.addTableModelListener(this);
clear();
headerButton = new Style.TitleButton(title, this);
if(!title.isEmpty()){
add(headerButton);
}
scrollPane = new JScrollPane(table);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
scrollPane.setPreferredSize(new Dimension(200, table.getRowCount()*table.getRowHeight()));
UIUtils.setDrawBorder(scrollPane, false);
add(scrollPane);
}
public BaseTable(String title){
this(title, null, null);
}
public void lock(){
tableModel.removeTableModelListener(this);
}
public void unlock(){
tableModel.addTableModelListener(this);
}
public void enable(){
table.setEnabled(true);
}
public void disable(){
table.setEnabled(false);
}
public void addRow(String key, String value){
tableModel.addRow(new String[]{key, value});
}
public void addRow(String key, boolean value){
tableModel.addRow(new Object[]{key, new Boolean(value)});
}
public void update(String... propertyAndValueNames){
if(table.isEditing())
table.getCellEditor().stopCellEditing();
tableModel.getDataVector().clear();
for(int i=0;i<propertyAndValueNames.length;i+=2)
addRow(propertyAndValueNames[i], propertyAndValueNames[i+1]);
table.setEnabled(true);
table.repaint();
}
public void clear(String... propertyNames){
if(table.isEditing())
table.getCellEditor().stopCellEditing();
tableModel.getDataVector().clear();
for(int i=0;i<propertyNames.length;i++)
addRow(propertyNames[i], "");
table.repaint();
table.setEnabled(false);
}
@Override
public void tableChanged(TableModelEvent e) {
if(e.getType() == TableModelEvent.UPDATE && e.getLastRow() < tableModel.getRowCount()){
String key = (String)tableModel.getValueAt(e.getLastRow(), e.getColumn()-1);
String value = tableModel.getValueAt(e.getLastRow(), e.getColumn()).toString();
setProperty(key, value);
}
}
public void setProperty(String name, String value){
}
public void updateProperty(String key, String value, int row){
lock();
tableModel.setValueAt(value, row, 1);
unlock();
}
public int getRowCount(){
return table.getRowCount();
}
@Override
public void actionPerformed(ActionEvent arg0) {
scrollPane.setVisible(!scrollPane.isVisible());
validate();
repaint();
}
public SpinnerIntegerEditor createIntegerSpinner(final String key){
final SpinnerIntegerEditor editor = new SpinnerIntegerEditor();
editor.spinner.addChangeListener(new ChangeListener(){
@Override
public void stateChanged(ChangeEvent arg0) {
setProperty(key, editor.spinner.getValue().toString());
}
});
return editor;
}
public SpinnerFloatEditor createFloatSpinner(final String key){
final SpinnerFloatEditor editor = new SpinnerFloatEditor();
editor.spinner.addChangeListener(new ChangeListener(){
@Override
public void stateChanged(ChangeEvent arg0) {
setProperty(key, editor.spinner.getValue().toString());
}
});
return editor;
}
public static JSpinner createSpinnerInteger(){
JSpinner spinner = new JSpinner(new SpinnerNumberModel(new Integer(0), new Integer(-99999),
new Integer(99999), new Integer(1)));
UIUtils.setDrawBorder(spinner, false);
UIUtils.setShadeWidth(spinner, 0);
UIUtils.setRound(spinner, 0);
UIUtils.setDrawFocus(spinner, false);
spinner.setFocusable(false);
return spinner;
}
public static JSpinner createSpinnerFloat(){
JSpinner spinner = new JSpinner(new SpinnerNumberModel(new Float(0), new Float(-99999),
new Float(99999), new Float(0.1f)));
UIUtils.setDrawBorder(spinner, false);
UIUtils.setShadeWidth(spinner, 0);
UIUtils.setRound(spinner, 0);
UIUtils.setDrawFocus(spinner, false);
spinner.setFocusable(false);
return spinner;
}
public static DefaultCellEditor createTextFieldEditor(){
JTextField tf = new JTextField();
UIUtils.setShadeWidth(tf, 0);
UIUtils.setRound(tf, 0);
UIUtils.setDrawFocus(tf, false);
tf.setFocusable(false);
return new DefaultCellEditor(tf);
}
public static JTextField createTextField(){
JTextField tf = new JTextField();
UIUtils.setShadeWidth(tf, 0);
UIUtils.setRound(tf, 0);
UIUtils.setDrawFocus(tf, false);
tf.setFocusable(false);
return tf;
}
public static DefaultCellEditor createNumberField(){
NumberTextField tf = new NumberTextField();
UIUtils.setShadeWidth(tf, 0);
UIUtils.setRound(tf, 0);
UIUtils.setDrawFocus(tf, false);
tf.setFocusable(false);
return new DefaultCellEditor(tf);
}
public static JComboBox<String> createComboBox(){
JComboBox<String> combo = new JComboBox<String>();
UIUtils.setShadeWidth(combo, 0);
UIUtils.setRound(combo, 0);
UIUtils.setDrawFocus(combo, false);
combo.setFocusable(false);
return combo;
}
public static JComboBox<String> createComboBox(String... items){
JComboBox<String> combo = new JComboBox<String>(items);
UIUtils.setShadeWidth(combo, 0);
UIUtils.setRound(combo, 0);
UIUtils.setDrawFocus(combo, false);
return combo;
}
public static DefaultCellEditor createBooleanEditor(){
return new DefaultCellEditor(createComboBox("false", "true"));
}
public static DefaultCellEditor createTouchableEditor(){
return new DefaultCellEditor(createComboBox(Touchable.enabled.toString()
, Touchable.disabled.toString(), Touchable.childrenOnly.toString()));
}
public static TableCellEditor createCheckBoxEditor(){
return new CheckBoxEditor();
}
}
class BaseRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
JLabel label = new JLabel(" ");
JCheckBox checkBox = new JCheckBox();
JSpinner spinnerFloat = BaseTable.createSpinnerFloat();
JSpinner spinnerInteger = BaseTable.createSpinnerInteger();
public BaseRenderer(){
spinnerInteger.setBorder(BorderFactory.createEmptyBorder());
spinnerFloat.setBorder(BorderFactory.createEmptyBorder());
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
setBorder(noFocusBorder);
if(column == 0)
return new HeaderLabel(value.toString());
else {
if(value instanceof Boolean) { // Boolean
checkBox.setSelected(((Boolean) value).booleanValue());
checkBox.repaint();
checkBox.setHorizontalAlignment(JLabel.CENTER);
return checkBox;
}
}
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
}
}
class HeaderLabel extends JLabel{
private static final long serialVersionUID = 1L;
HeaderLabel(String text){
super(text);
setHorizontalAlignment ( JLabel.CENTER );
UIUtils.setMargin(this, new Insets(0,0,0,0));
setForeground(Style.font);
}
@Override
public void paint ( Graphics g){
Style.drawTableHeader(g, getWidth(), getHeight());
super.paint(g);
}
}
class ColorEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {
private static final long serialVersionUID = 1L;
Color currentColor = Color.red;
JButton button;
JColorChooser colorChooser;
JDialog dialog;
JPanel pan;
protected static final String EDIT = "edit";
public ColorEditor() {
//Set up the editor (from the table's point of view),
//which is a button.
//This button brings up the color chooser dialog,
//which is the editor from the user's point of view.
button = new JButton();
button.setActionCommand(EDIT);
button.addActionListener(this);
button.setBorderPainted(false);
button.setRolloverEnabled(false);
button.setOpaque(true);
pan = new JPanel(new ToolbarLayout());
pan.setOpaque(false);
UIUtils.setMargin(pan, new Insets(2,3,2,3));
pan.add(button);
//Set up the dialog that the button brings up.
colorChooser = new JColorChooser();
dialog = JColorChooser.createDialog(button,
"Pick a Color",true, //modal
colorChooser,
this, //OK button handler
null); //no CANCEL button handler
}
/**
* Handles events from the editor button and from
* the dialog's OK button.
*/
public void actionPerformed(ActionEvent e) {
if (EDIT.equals(e.getActionCommand())) {
//The user has clicked the cell, so
//bring up the dialog.
button.setBackground(currentColor);
colorChooser.setColor(currentColor);
dialog.setVisible(true);
//Make the renderer reappear.
fireEditingStopped();
} else { //User pressed dialog's "OK" button.
currentColor = colorChooser.getColor();
dialog.setVisible(false);
}
}
//Implement the one CellEditor method that AbstractCellEditor doesn't.
@Override
public String getCellEditorValue() {
return String.format("%02x%02x%02x%02x",currentColor.getRed(),
currentColor.getGreen(), currentColor.getBlue(), currentColor.getAlpha());
}
//Implement the one method defined by TableCellEditor.
@Override
public Component getTableCellEditorComponent(JTable table,
Object value,
boolean isSelected,
int row,
int column) {
String colorString = (String) value;
if(colorString.length() == 8 && colorString.matches("[0-9A-Fa-f]+")){
com.badlogic.gdx.graphics.Color cl = com.badlogic.gdx.graphics.Color.valueOf(colorString);
currentColor = new Color(cl.r, cl.g, cl.b, cl.a);
}
return pan;
}
@Override
public void addCellEditorListener(CellEditorListener arg0) {
super.addCellEditorListener(arg0);
}
@Override
public void cancelCellEditing() {
dialog.setVisible(false);
super.cancelCellEditing();
}
@Override
public boolean isCellEditable(EventObject arg0) {
return true;
}
@Override
public void removeCellEditorListener(CellEditorListener arg0) {
super.removeCellEditorListener(arg0);
}
@Override
public boolean shouldSelectCell(EventObject arg0) {
return super.shouldSelectCell(arg0);
}
@Override
public boolean stopCellEditing() {
dialog.setVisible(false);
return super.stopCellEditing();
}
}
class CheckBoxEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {
private static final long serialVersionUID = 1L;
private JCheckBox checkBox;
public CheckBoxEditor() {
checkBox = new JCheckBox();
checkBox.setHorizontalAlignment(JLabel.LEFT);
//checkBox.addActionListener(this);
}
public CheckBoxEditor(boolean value) {
checkBox = new JCheckBox();
checkBox.setSelected(value);
checkBox.setHorizontalAlignment(JLabel.LEFT);
//checkBox.addActionListener(this);
}
/**
* Handles events from the editor button and from
* the dialog's OK button.
*/
public void actionPerformed(ActionEvent e) {
}
//Implement the one CellEditor method that AbstractCellEditor doesn't.
@Override
public Boolean getCellEditorValue() {
return checkBox.isSelected();
}
//Implement the one method defined by TableCellEditor.
@Override
public Component getTableCellEditorComponent(JTable table,
Object value,
boolean isSelected,
int row,
int column) {
checkBox.setSelected(((Boolean) value).booleanValue());
checkBox.repaint();
return checkBox;
}
@Override
public void addCellEditorListener(CellEditorListener arg0) {
super.addCellEditorListener(arg0);
}
@Override
public void cancelCellEditing() {
super.cancelCellEditing();
}
@Override
public boolean isCellEditable(EventObject arg0) {
return true;
}
@Override
public void removeCellEditorListener(CellEditorListener arg0) {
super.removeCellEditorListener(arg0);
}
@Override
public boolean shouldSelectCell(EventObject arg0) {
return super.shouldSelectCell(arg0);
}
@Override
public boolean stopCellEditing() {
return super.stopCellEditing();
}
}
class SpinnerIntegerEditor extends AbstractCellEditor implements TableCellEditor {
private static final long serialVersionUID = 1L;
JSpinner spinner;
// Initializes the spinner.
public SpinnerIntegerEditor() {
spinner = BaseTable.createSpinnerInteger();
spinner.setBorder(BorderFactory.createEmptyBorder());
((DefaultEditor) spinner.getEditor()).getTextField().setEditable(false);
}
// Prepares the spinner component and returns it.
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
int row, int column) {
float f = (Float) Float.parseFloat(value.toString());
spinner.setValue((int) f);
return spinner;
}
public boolean isCellEditable( EventObject eo ) {
return true;
}
// Returns the spinners current value.
public Object getCellEditorValue() {
return spinner.getValue();
}
public boolean stopCellEditing() {
try {
spinner.commitEdit();
} catch ( java.text.ParseException e ) {
JOptionPane.showMessageDialog(null,"Invalid value, discarding.");
}
return super.stopCellEditing();
}
}
class SpinnerFloatEditor extends AbstractCellEditor implements TableCellEditor {
private static final long serialVersionUID = 1L;
JSpinner spinner;
// Initializes the spinner.
public SpinnerFloatEditor() {
spinner = BaseTable.createSpinnerFloat();
spinner.setBorder(BorderFactory.createEmptyBorder());
((DefaultEditor) spinner.getEditor()).getTextField().setEditable(false);
}
// Prepares the spinner component and returns it.
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
int row, int column) {
spinner.setValue((Float)Float.parseFloat(value.toString()));
return spinner;
}
public boolean isCellEditable( EventObject eo ) {
return true;
}
// Returns the spinners current value.
public Object getCellEditorValue() {
return spinner.getValue();
}
public boolean stopCellEditing() {
try {
spinner.commitEdit();
} catch ( java.text.ParseException e ) {
JOptionPane.showMessageDialog(null, "Invalid value, discarding.");
}
return super.stopCellEditing();
}
}