001package jmri.jmrit.display; 002 003import java.awt.event.ActionEvent; 004import java.awt.event.ActionListener; 005import java.awt.event.KeyAdapter; 006import java.awt.event.KeyEvent; 007 008import javax.annotation.Nonnull; 009import javax.swing.JComponent; 010import javax.swing.JLabel; 011import javax.swing.JPanel; 012import javax.swing.JSpinner; 013import javax.swing.JTextField; 014import javax.swing.SpinnerNumberModel; 015 016import jmri.InstanceManager; 017import jmri.Memory; 018import jmri.NamedBeanHandle; 019import jmri.NamedBean.DisplayOptions; 020import jmri.util.swing.*; 021 022import org.slf4j.Logger; 023import org.slf4j.LoggerFactory; 024 025/** 026 * An icon to display and input a Memory value in a TextField. 027 * <p> 028 * Handles the case of either a String or an Integer in the Memory, preserving 029 * what it finds. 030 * 031 * @author Pete Cressman Copyright (c) 2009 032 * @since 2.7.2 033 */ 034public class MemoryInputIcon extends PositionableJPanel implements java.beans.PropertyChangeListener { 035 036 JTextField _textBox = new JTextField(); 037 int _nCols; 038 039 // the associated Memory object 040 private NamedBeanHandle<Memory> namedMemory; 041 042 private final java.awt.event.MouseListener _mouseListener = JmriMouseListener.adapt(this); 043 private final java.awt.event.MouseMotionListener _mouseMotionListener = JmriMouseMotionListener.adapt(this); 044 045 public MemoryInputIcon(int nCols, Editor editor) { 046 super(editor); 047 _nCols = nCols; 048 setDisplayLevel(Editor.LABELS); 049 050 setLayout(new java.awt.GridBagLayout()); 051 add(_textBox, new java.awt.GridBagConstraints()); 052 _textBox.addKeyListener(new KeyAdapter() { 053 @Override 054 public void keyReleased(KeyEvent e) { 055 int key = e.getKeyCode(); 056 if (key == KeyEvent.VK_ENTER || key == KeyEvent.VK_TAB) { 057 updateMemory(); 058 } 059 } 060 }); 061 _textBox.setColumns(_nCols); 062 _textBox.setBorder(null); // drop default border so user can configure entire border appearance 063 _textBox.addMouseMotionListener(_mouseMotionListener); 064 _textBox.addMouseListener(_mouseListener); 065 setPopupUtility(new PositionablePopupUtil(this, _textBox)); 066 } 067 068 @Override 069 public Positionable deepClone() { 070 MemoryInputIcon pos = new MemoryInputIcon(_nCols, _editor); 071 return finishClone(pos); 072 } 073 074 protected Positionable finishClone(MemoryInputIcon pos) { 075 pos.setMemory(namedMemory.getName()); 076 return super.finishClone(pos); 077 } 078 079 @Override 080 public JComponent getTextComponent() { 081 return _textBox; 082 } 083 084 @Override 085 public void mouseExited(JmriMouseEvent e) { 086 updateMemory(); 087 super.mouseExited(e); 088 } 089 090 /** 091 * Attached a named Memory to this display item 092 * 093 * @param pName Used as a system/user name to lookup the Memory object 094 */ 095 public void setMemory(String pName) { 096 log.debug("setMemory for memory= {}", pName); 097 if (InstanceManager.getNullableDefault(jmri.MemoryManager.class) != null) { 098 try { 099 Memory memory = InstanceManager.memoryManagerInstance(). 100 provideMemory(pName); 101 setMemory(jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(pName, memory)); 102 } catch (IllegalArgumentException e) { 103 log.error("Memory '{}' not available, icon won't see changes", pName); 104 } 105 } else { 106 log.error("No MemoryManager for this protocol, icon won't see changes"); 107 } 108 updateSize(); 109 } 110 111 /** 112 * Attached a named Memory to this display item 113 * 114 * @param m The Memory object 115 */ 116 public void setMemory(NamedBeanHandle<Memory> m) { 117 if (namedMemory != null) { 118 getMemory().removePropertyChangeListener(this); 119 } 120 namedMemory = m; 121 if (namedMemory != null) { 122 getMemory().addPropertyChangeListener(this, namedMemory.getName(), "Memory Input Icon"); 123 displayState(); 124 setName(namedMemory.getName()); 125 } 126 } 127 128 public void setNumColumns(int nCols) { 129 _textBox.setColumns(nCols); 130 _nCols = nCols; 131 } 132 133 public NamedBeanHandle<Memory> getNamedMemory() { 134 return namedMemory; 135 } 136 137 public Memory getMemory() { 138 if (namedMemory == null) { 139 return null; 140 } 141 return namedMemory.getBean(); 142 } 143 144 public int getNumColumns() { 145 return _nCols; 146 } 147 148 // update icon as state of Memory changes 149 @Override 150 public void propertyChange(java.beans.PropertyChangeEvent e) { 151 if (e.getPropertyName().equals("value")) { 152 displayState(); 153 } 154 } 155 156 @Override 157 @Nonnull 158 public String getTypeString() { 159 return Bundle.getMessage("PositionableType_MemoryInputIcon"); 160 } 161 162 @Override 163 public String getNameString() { 164 String name; 165 if (namedMemory == null) { 166 name = Bundle.getMessage("NotConnected"); 167 } else { 168 name = getMemory().getDisplayName(DisplayOptions.USERNAME_SYSTEMNAME); 169 } 170 return name; 171 } 172 173 @Override 174 public void mouseMoved(JmriMouseEvent e) { 175 updateMemory(); 176 } 177 178 private void updateMemory() { 179 if (namedMemory == null) { 180 return; 181 } 182 String str = _textBox.getText(); 183 getMemory().setValue(str); 184 } 185 186 @Override 187 public boolean setEditIconMenu(javax.swing.JPopupMenu popup) { 188 String txt = java.text.MessageFormat.format(Bundle.getMessage("EditItem"), Bundle.getMessage("BeanNameMemory")); 189 popup.add(new javax.swing.AbstractAction(txt) { 190 @Override 191 public void actionPerformed(ActionEvent e) { 192 edit(); 193 } 194 }); 195 return true; 196 } 197 198 /** 199 * Popup menu iconEditor's ActionListener 200 */ 201 SpinnerNumberModel _spinModel = new SpinnerNumberModel(3, 1, 100, 1); 202 203 @Override 204 protected void edit() { 205 _iconEditor = new IconAdder("Memory") { 206 final JSpinner spinner = new JSpinner(_spinModel); 207 208 @Override 209 protected void addAdditionalButtons(JPanel p) { 210 ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().setColumns(2); 211 spinner.setMaximumSize(spinner.getPreferredSize()); 212 spinner.setValue(_textBox.getColumns()); 213 JPanel p2 = new JPanel(); 214 //p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS)); 215 //p2.setLayout(new FlowLayout(FlowLayout.TRAILING)); 216 p2.add(new JLabel(Bundle.getMessage("NumColsLabel"))); 217 p2.add(spinner); 218 p.add(p2); 219 p.setVisible(true); 220 } 221 }; 222 223 makeIconEditorFrame(this, "Memory", true, _iconEditor); 224 _iconEditor.setPickList(jmri.jmrit.picker.PickListModel.memoryPickModelInstance()); 225 ActionListener addIconAction = a -> editMemory(); 226 _iconEditor.makeIconPanel(false); 227 _iconEditor.complete(addIconAction, false, true, true); 228 _iconEditor.setSelection(getMemory()); 229 } 230 231 void editMemory() { 232 setMemory(_iconEditor.getTableSelection().getDisplayName()); 233 _nCols = _spinModel.getNumber().intValue(); 234 _textBox.setColumns(_nCols); 235 setSize(getPreferredSize().width + 1, getPreferredSize().height); 236 _iconEditorFrame.dispose(); 237 _iconEditorFrame = null; 238 _iconEditor = null; 239 validate(); 240 } 241 242 /** 243 * Drive the current state of the display from the state of the Memory. 244 */ 245 public void displayState() { 246 log.debug("displayState"); 247 if (namedMemory == null) { // leave alone if not connected yet 248 return; 249 } 250 Object show = getMemory().getValue(); 251 if (show != null) { 252 _textBox.setText(show.toString()); 253 } else { 254 _textBox.setText(""); 255 } 256 } 257 258 @Override 259 void cleanup() { 260 if (namedMemory != null) { 261 getMemory().removePropertyChangeListener(this); 262 } 263 if (_textBox != null) { 264 _textBox.removeMouseMotionListener(_mouseMotionListener); 265 _textBox.removeMouseListener(_mouseListener); 266 } 267 namedMemory = null; 268 } 269 270 private static final Logger log = LoggerFactory.getLogger(MemoryInputIcon.class); 271}