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.NamedBeanHandle; 018import jmri.NamedBean.DisplayOptions; 019import jmri.jmrit.logixng.GlobalVariable; 020import jmri.jmrit.logixng.GlobalVariableManager; 021import jmri.util.swing.*; 022 023import org.slf4j.Logger; 024import org.slf4j.LoggerFactory; 025 026/** 027 * An icon to display and input a GlobalVariable value in a TextField. 028 * <p> 029 * Handles the case of either a String or an Integer in the GlobalVariable, preserving 030 * what it finds. 031 * 032 * @author Pete Cressman Copyright (c) 2009 033 * @author Daniel Bergqvist Copyright (C) 2022 034 * @since 2.7.2 035 */ 036public class GlobalVariableInputIcon extends PositionableJPanel implements java.beans.PropertyChangeListener { 037 038 JTextField _textBox = new JTextField(); 039 int _nCols; 040 041 // the associated GlobalVariable object 042 private NamedBeanHandle<GlobalVariable> namedGlobalVariable; 043 044 private final java.awt.event.MouseListener _mouseListener = JmriMouseListener.adapt(this); 045 private final java.awt.event.MouseMotionListener _mouseMotionListener = JmriMouseMotionListener.adapt(this); 046 047 public GlobalVariableInputIcon(int nCols, Editor editor) { 048 super(editor); 049 _nCols = nCols; 050 setDisplayLevel(Editor.LABELS); 051 052 setLayout(new java.awt.GridBagLayout()); 053 add(_textBox, new java.awt.GridBagConstraints()); 054 _textBox.addKeyListener(new KeyAdapter() { 055 @Override 056 public void keyReleased(KeyEvent e) { 057 int key = e.getKeyCode(); 058 if (key == KeyEvent.VK_ENTER || key == KeyEvent.VK_TAB) { 059 updateGlobalVariable(); 060 } 061 } 062 }); 063 _textBox.setColumns(_nCols); 064 _textBox.addMouseMotionListener(_mouseMotionListener); 065 _textBox.addMouseListener(_mouseListener); 066 setPopupUtility(new PositionablePopupUtil(this, _textBox)); 067 } 068 069 @Override 070 public Positionable deepClone() { 071 GlobalVariableInputIcon pos = new GlobalVariableInputIcon(_nCols, _editor); 072 return finishClone(pos); 073 } 074 075 protected Positionable finishClone(GlobalVariableInputIcon pos) { 076 pos.setGlobalVariable(namedGlobalVariable.getName()); 077 return super.finishClone(pos); 078 } 079 080 @Override 081 public JComponent getTextComponent() { 082 return _textBox; 083 } 084 085 @Override 086 public void mouseExited(JmriMouseEvent e) { 087 updateGlobalVariable(); 088 super.mouseExited(e); 089 } 090 091 /** 092 * Attached a named GlobalVariable to this display item 093 * 094 * @param pName Used as a system/user name to lookup the GlobalVariable object 095 */ 096 public void setGlobalVariable(String pName) { 097 log.debug("setGlobalVariable for memory= {}", pName); 098 if (InstanceManager.getNullableDefault(GlobalVariableManager.class) != null) { 099 try { 100 GlobalVariable globalVariable = InstanceManager.getDefault(GlobalVariableManager.class).getGlobalVariable(pName); 101 setGlobalVariable(jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(pName, globalVariable)); 102 } catch (IllegalArgumentException e) { 103 log.error("GlobalVariable '{}' not available, icon won't see changes", pName); 104 } 105 } else { 106 log.error("No GlobalVariableManager for this protocol, icon won't see changes"); 107 } 108 updateSize(); 109 } 110 111 /** 112 * Attached a named GlobalVariable to this display item 113 * 114 * @param m The GlobalVariable object 115 */ 116 public void setGlobalVariable(NamedBeanHandle<GlobalVariable> m) { 117 if (namedGlobalVariable != null) { 118 getGlobalVariable().removePropertyChangeListener(this); 119 } 120 namedGlobalVariable = m; 121 if (namedGlobalVariable != null) { 122 getGlobalVariable().addPropertyChangeListener(this, namedGlobalVariable.getName(), "GlobalVariable Input Icon"); 123 displayState(); 124 setName(namedGlobalVariable.getName()); 125 } 126 } 127 128 public void setNumColumns(int nCols) { 129 _textBox.setColumns(nCols); 130 _nCols = nCols; 131 } 132 133 public NamedBeanHandle<GlobalVariable> getNamedGlobalVariable() { 134 return namedGlobalVariable; 135 } 136 137 public GlobalVariable getGlobalVariable() { 138 if (namedGlobalVariable == null) { 139 return null; 140 } 141 return namedGlobalVariable.getBean(); 142 } 143 144 public int getNumColumns() { 145 return _nCols; 146 } 147 148 // update icon as state of GlobalVariable 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_GlobalVariableInputIcon"); 160 } 161 162 @Override 163 public String getNameString() { 164 String name; 165 if (namedGlobalVariable == null) { 166 name = Bundle.getMessage("NotConnected"); 167 } else { 168 name = getGlobalVariable().getDisplayName(DisplayOptions.USERNAME_SYSTEMNAME); 169 } 170 return name; 171 } 172 173 @Override 174 public void mouseMoved(JmriMouseEvent e) { 175 updateGlobalVariable(); 176 } 177 178 private void updateGlobalVariable() { 179 if (namedGlobalVariable == null) { 180 return; 181 } 182 String str = _textBox.getText(); 183 getGlobalVariable().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("BeanNameGlobalVariable")); 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("GlobalVariable") { 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, "GlobalVariable", true, _iconEditor); 224 _iconEditor.setPickList(jmri.jmrit.picker.PickListModel.globalVariablePickModelInstance()); 225 ActionListener addIconAction = a -> editGlobalVariable(); 226 _iconEditor.makeIconPanel(false); 227 _iconEditor.complete(addIconAction, false, false, true); 228 _iconEditor.setSelection(getGlobalVariable()); 229 } 230 231 void editGlobalVariable() { 232 setGlobalVariable(_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 GlobalVariable. 244 */ 245 public void displayState() { 246 log.debug("displayState"); 247 if (namedGlobalVariable == null) { // leave alone if not connected yet 248 return; 249 } 250 Object show = getGlobalVariable().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 (namedGlobalVariable != null) { 261 getGlobalVariable().removePropertyChangeListener(this); 262 } 263 if (_textBox != null) { 264 _textBox.removeMouseMotionListener(_mouseMotionListener); 265 _textBox.removeMouseListener(_mouseListener); 266 } 267 namedGlobalVariable = null; 268 } 269 270 private final static Logger log = LoggerFactory.getLogger(GlobalVariableInputIcon.class); 271}