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