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.addMouseMotionListener(_mouseMotionListener); 063 _textBox.addMouseListener(_mouseListener); 064 setPopupUtility(new PositionablePopupUtil(this, _textBox)); 065 } 066 067 @Override 068 public Positionable deepClone() { 069 MemoryInputIcon pos = new MemoryInputIcon(_nCols, _editor); 070 return finishClone(pos); 071 } 072 073 protected Positionable finishClone(MemoryInputIcon pos) { 074 pos.setMemory(namedMemory.getName()); 075 return super.finishClone(pos); 076 } 077 078 @Override 079 public JComponent getTextComponent() { 080 return _textBox; 081 } 082 083 @Override 084 public void mouseExited(JmriMouseEvent e) { 085 updateMemory(); 086 super.mouseExited(e); 087 } 088 089 /** 090 * Attached a named Memory to this display item 091 * 092 * @param pName Used as a system/user name to lookup the Memory object 093 */ 094 public void setMemory(String pName) { 095 log.debug("setMemory for memory= {}", pName); 096 if (InstanceManager.getNullableDefault(jmri.MemoryManager.class) != null) { 097 try { 098 Memory memory = InstanceManager.memoryManagerInstance(). 099 provideMemory(pName); 100 setMemory(jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(pName, memory)); 101 } catch (IllegalArgumentException e) { 102 log.error("Memory '{}' not available, icon won't see changes", pName); 103 } 104 } else { 105 log.error("No MemoryManager for this protocol, icon won't see changes"); 106 } 107 updateSize(); 108 } 109 110 /** 111 * Attached a named Memory to this display item 112 * 113 * @param m The Memory object 114 */ 115 public void setMemory(NamedBeanHandle<Memory> m) { 116 if (namedMemory != null) { 117 getMemory().removePropertyChangeListener(this); 118 } 119 namedMemory = m; 120 if (namedMemory != null) { 121 getMemory().addPropertyChangeListener(this, namedMemory.getName(), "Memory Input Icon"); 122 displayState(); 123 setName(namedMemory.getName()); 124 } 125 } 126 127 public void setNumColumns(int nCols) { 128 _textBox.setColumns(nCols); 129 _nCols = nCols; 130 } 131 132 public NamedBeanHandle<Memory> getNamedMemory() { 133 return namedMemory; 134 } 135 136 public Memory getMemory() { 137 if (namedMemory == null) { 138 return null; 139 } 140 return namedMemory.getBean(); 141 } 142 143 public int getNumColumns() { 144 return _nCols; 145 } 146 147 // update icon as state of Memory changes 148 @Override 149 public void propertyChange(java.beans.PropertyChangeEvent e) { 150 if (e.getPropertyName().equals("value")) { 151 displayState(); 152 } 153 } 154 155 @Override 156 @Nonnull 157 public String getTypeString() { 158 return Bundle.getMessage("PositionableType_MemoryInputIcon"); 159 } 160 161 @Override 162 public String getNameString() { 163 String name; 164 if (namedMemory == null) { 165 name = Bundle.getMessage("NotConnected"); 166 } else { 167 name = getMemory().getDisplayName(DisplayOptions.USERNAME_SYSTEMNAME); 168 } 169 return name; 170 } 171 172 @Override 173 public void mouseMoved(JmriMouseEvent e) { 174 updateMemory(); 175 } 176 177 private void updateMemory() { 178 if (namedMemory == null) { 179 return; 180 } 181 String str = _textBox.getText(); 182 getMemory().setValue(str); 183 } 184 185 @Override 186 public boolean setEditIconMenu(javax.swing.JPopupMenu popup) { 187 String txt = java.text.MessageFormat.format(Bundle.getMessage("EditItem"), Bundle.getMessage("BeanNameMemory")); 188 popup.add(new javax.swing.AbstractAction(txt) { 189 @Override 190 public void actionPerformed(ActionEvent e) { 191 edit(); 192 } 193 }); 194 return true; 195 } 196 197 /** 198 * Popup menu iconEditor's ActionListener 199 */ 200 SpinnerNumberModel _spinModel = new SpinnerNumberModel(3, 1, 100, 1); 201 202 @Override 203 protected void edit() { 204 _iconEditor = new IconAdder("Memory") { 205 final JSpinner spinner = new JSpinner(_spinModel); 206 207 @Override 208 protected void addAdditionalButtons(JPanel p) { 209 ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().setColumns(2); 210 spinner.setMaximumSize(spinner.getPreferredSize()); 211 spinner.setValue(_textBox.getColumns()); 212 JPanel p2 = new JPanel(); 213 //p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS)); 214 //p2.setLayout(new FlowLayout(FlowLayout.TRAILING)); 215 p2.add(new JLabel(Bundle.getMessage("NumColsLabel"))); 216 p2.add(spinner); 217 p.add(p2); 218 p.setVisible(true); 219 } 220 }; 221 222 makeIconEditorFrame(this, "Memory", true, _iconEditor); 223 _iconEditor.setPickList(jmri.jmrit.picker.PickListModel.memoryPickModelInstance()); 224 ActionListener addIconAction = a -> editMemory(); 225 _iconEditor.makeIconPanel(false); 226 _iconEditor.complete(addIconAction, false, true, true); 227 _iconEditor.setSelection(getMemory()); 228 } 229 230 void editMemory() { 231 setMemory(_iconEditor.getTableSelection().getDisplayName()); 232 _nCols = _spinModel.getNumber().intValue(); 233 _textBox.setColumns(_nCols); 234 setSize(getPreferredSize().width + 1, getPreferredSize().height); 235 _iconEditorFrame.dispose(); 236 _iconEditorFrame = null; 237 _iconEditor = null; 238 validate(); 239 } 240 241 /** 242 * Drive the current state of the display from the state of the Memory. 243 */ 244 public void displayState() { 245 log.debug("displayState"); 246 if (namedMemory == null) { // leave alone if not connected yet 247 return; 248 } 249 Object show = getMemory().getValue(); 250 if (show != null) { 251 _textBox.setText(show.toString()); 252 } else { 253 _textBox.setText(""); 254 } 255 } 256 257 @Override 258 void cleanup() { 259 if (namedMemory != null) { 260 getMemory().removePropertyChangeListener(this); 261 } 262 if (_textBox != null) { 263 _textBox.removeMouseMotionListener(_mouseMotionListener); 264 _textBox.removeMouseListener(_mouseListener); 265 } 266 namedMemory = null; 267 } 268 269 private final static Logger log = LoggerFactory.getLogger(MemoryInputIcon.class); 270}