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