001package jmri.jmrit.symbolicprog; 002 003import java.awt.Component; 004import java.awt.event.FocusEvent; 005import java.awt.event.FocusListener; 006import java.util.EventObject; 007import java.util.Vector; 008import javax.swing.JComboBox; 009import javax.swing.JLabel; 010import javax.swing.JTable; 011import javax.swing.JTextField; 012import javax.swing.event.CellEditorListener; 013import javax.swing.event.ChangeEvent; 014import javax.swing.table.TableCellEditor; 015import org.slf4j.Logger; 016import org.slf4j.LoggerFactory; 017 018/** 019 * JTable editor for cells representing CV values. This is a somewhat 020 * unconventional thing in several ways: 021 * <ul> 022 * <li>The returned value is not the String edited into the cell, but an Integer 023 * value. It is not clear how that arose, and it should probably be changed at 024 * some point. 025 * <li>This is also a focus listener. People are not used to having to hit 026 * return/enter to "set" their value in place, and are rather expecting that the 027 * value they typed will be in effect as soon as they type it. We use a 028 * focusListener to do that. 029 * </ul> 030 * 031 * @author Bob Jacobsen Copyright (C) 2001 032 */ 033public class ValueEditor extends JComboBox<Object> implements TableCellEditor, FocusListener { 034 035 protected transient Vector<CellEditorListener> listeners; 036 protected transient String originalValue = null; 037 protected Object mValue; 038 039 public ValueEditor() { 040 super(); 041 listeners = new Vector<CellEditorListener>(); 042 } 043 044 @Override 045 public Component getTableCellEditorComponent(JTable table, Object value, 046 boolean isSelected, 047 int row, int column) { 048 mValue = value; 049 if (log.isDebugEnabled()) { 050 log.debug("getTableCellEditorComponent {} {} {} {}", row, column, isSelected, value.getClass()); 051 } 052 table.setRowSelectionInterval(row, row); 053 table.setColumnSelectionInterval(column, column); 054 if (value instanceof Component) { 055 if (value instanceof JTextField) { 056 JTextField tempField = (JTextField) value; 057 originalValue = tempField.getText(); 058 tempField.addFocusListener(this); 059 return tempField; 060 } else { 061 return (Component) value; 062 } 063 } else if (value instanceof String) { 064 return new JLabel((String) value); 065 } else { 066 return new JLabel("Unknown value type!"); 067 } 068 } 069 070 /** 071 * FocusListener implementations 072 */ 073 @Override 074 public void focusGained(FocusEvent e) { 075 if (log.isDebugEnabled()) { 076 log.debug("focusGained"); 077 } 078 if (mValue instanceof JTextField) { 079 JTextField tempField = (JTextField) mValue; 080 originalValue = tempField.getText(); 081 } 082 } 083 084 @Override 085 public void focusLost(FocusEvent e) { 086 if (log.isDebugEnabled()) { 087 log.debug("focusLost"); 088 } 089 if (!(mValue instanceof JTextField) 090 || !(originalValue.equals(((JTextField) mValue).getText()))) { 091 fireEditingStopped(); 092 } 093 } 094 095 void removeFocusListener() { 096 if (mValue instanceof JTextField) { 097 JTextField tempField = (JTextField) mValue; 098 originalValue = null; 099 tempField.removeFocusListener(this); 100 } 101 } 102 103 // CellEditor methods 104 @Override 105 public void cancelCellEditing() { 106 if (log.isDebugEnabled()) { 107 log.debug("cancelCellEditing"); 108 } 109 removeFocusListener(); 110 fireEditingCanceled(); 111 } 112 113 @Override 114 public Object getCellEditorValue() { 115 if (log.isDebugEnabled()) { 116 log.debug("getCellEditorValue with 'value' object of type {}", mValue.getClass()); 117 } 118 if (mValue instanceof JTextField) { 119 // extract the string from the JTextField and return it 120 return Integer.valueOf(((JTextField) mValue).getText()); 121 } else if (mValue instanceof Component) { 122 // extract the string from the JTextField and return it 123 return mValue; 124 } else { 125 log.error("getCellEditorValue unable to return a value from unknown type {}", mValue.getClass()); 126 return null; 127 } 128 } 129 130 @Override 131 public boolean isCellEditable(EventObject eo) { 132 return true; 133 } 134 135 @Override 136 public boolean shouldSelectCell(EventObject eo) { 137 return true; 138 } 139 140 @Override 141 public boolean stopCellEditing() { 142 if (log.isDebugEnabled()) { 143 log.debug("stopCellEditing"); 144 } 145 removeFocusListener(); 146 fireEditingStopped(); 147 return true; 148 } 149 150 @Override 151 public void addCellEditorListener(CellEditorListener cel) { 152 listeners.addElement(cel); 153 } 154 155 @Override 156 public void removeCellEditorListener(CellEditorListener cel) { 157 listeners.removeElement(cel); 158 } 159 160 protected void fireEditingCanceled() { 161 if (log.isDebugEnabled()) { 162 log.debug("fireEditingCancelled, but we are not setting back the old value"); 163 } 164 Vector<CellEditorListener> local; 165 synchronized (listeners) { 166 local = new Vector<CellEditorListener>(listeners); 167 } 168 ChangeEvent ce = new ChangeEvent(this); 169 for (int i = local.size() - 1; i >= 0; i--) { 170 local.elementAt(i).editingCanceled(ce); 171 } 172 } 173 174 protected void fireEditingStopped() { 175 if (log.isDebugEnabled()) { 176 log.debug("fireEditingStopped"); 177 } 178 Vector<CellEditorListener> local; 179 synchronized (listeners) { 180 local = new Vector<CellEditorListener>(listeners); 181 } 182 ChangeEvent ce = new ChangeEvent(this); 183 for (int i = local.size() - 1; i >= 0; i--) { 184 local.elementAt(i).editingStopped(ce); 185 } 186 } 187 188 // initialize logging 189 private final static Logger log = LoggerFactory.getLogger(ValueEditor.class); 190}