001package jmri.jmrit.display; 002 003import java.awt.event.ActionEvent; 004import java.awt.event.ActionListener; 005 006import javax.annotation.Nonnull; 007import javax.swing.AbstractButton; 008import javax.swing.DefaultListModel; 009import javax.swing.JButton; 010import javax.swing.JComboBox; 011import javax.swing.JLabel; 012import javax.swing.JList; 013import javax.swing.JPanel; 014import javax.swing.JScrollPane; 015import javax.swing.JTextField; 016import javax.swing.SwingConstants; 017 018import jmri.InstanceManager; 019import jmri.jmrit.logixng.GlobalVariable; 020import jmri.jmrit.logixng.GlobalVariableManager; 021import jmri.NamedBeanHandle; 022import jmri.NamedBean.DisplayOptions; 023import jmri.util.swing.*; 024 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027 028/** 029 * An icon to display and input a GlobalVariable value in a TextField. 030 * <p> 031 * Handles the case of either a String or an Integer in the GlobalVariable, preserving 032 * what it finds. 033 * 034 * @author Pete Cressman Copyright (c) 2012 035 * @author Daniel Bergqvist Copyright (C) 2022 036 * @since 2.7.2 037 */ 038public class GlobalVariableComboIcon extends MemoryOrGVComboIcon 039 implements java.beans.PropertyChangeListener, ActionListener { 040 041 private final JComboBox<String> _comboBox; 042 private final ComboModel _model; 043 044 // the associated GlobalVariable object 045 private NamedBeanHandle<GlobalVariable> namedGlobalVariable; 046 047 private final java.awt.event.MouseListener _mouseListener = JmriMouseListener.adapt(this); 048 private final java.awt.event.MouseMotionListener _mouseMotionListener = JmriMouseMotionListener.adapt(this); 049 050 public GlobalVariableComboIcon(Editor editor, String[] list) { 051 super(editor); 052 if (list != null) { 053 _model = new ComboModel(list); 054 } else { 055 _model = new ComboModel(); 056 } 057 _comboBox = new JComboBox<>(_model); 058 _comboBox.addActionListener(this); 059 setDisplayLevel(Editor.LABELS); 060 061 setLayout(new java.awt.GridBagLayout()); 062 add(_comboBox); 063 _comboBox.addMouseListener(JmriMouseListener.adapt(this)); 064 065 for (int i = 0; i < _comboBox.getComponentCount(); i++) { 066 java.awt.Component component = _comboBox.getComponent(i); 067 if (component instanceof AbstractButton) { 068 component.addMouseListener(_mouseListener); 069 component.addMouseMotionListener(_mouseMotionListener); 070 } 071 } 072 setPopupUtility(new PositionablePopupUtil(this, _comboBox)); 073 } 074 075 @Override 076 public JComboBox<String> getTextComponent() { 077 return _comboBox; 078 } 079 080 @Override 081 public Positionable deepClone() { 082 String[] list = new String[_model.getSize()]; 083 for (int i = 0; i < _model.getSize(); i++) { 084 list[i] = _model.getElementAt(i); 085 } 086 GlobalVariableComboIcon pos = new GlobalVariableComboIcon(_editor, list); 087 return finishClone(pos); 088 } 089 090 protected Positionable finishClone(GlobalVariableComboIcon pos) { 091 pos.setGlobalVariable(namedGlobalVariable.getName()); 092 return super.finishClone(pos); 093 } 094 095 /** 096 * Attach a named GlobalVariable to this display item. 097 * 098 * @param pName used as a system/user name to look up the GlobalVariable object 099 */ 100 public void setGlobalVariable(String pName) { 101 log.debug("setGlobalVariable for memory= {}", pName); 102 if (InstanceManager.getNullableDefault(GlobalVariableManager.class) != null) { 103 try { 104 GlobalVariable globalVariable = InstanceManager.getDefault(GlobalVariableManager.class).getGlobalVariable(pName); 105 setGlobalVariable(jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(pName, globalVariable)); 106 } catch (IllegalArgumentException e) { 107 log.error("No GlobalVariableManager for this protocol, icon won't see changes"); 108 } 109 } 110 updateSize(); 111 } 112 113 /** 114 * Attach a named GlobalVariable to this display item. 115 * 116 * @param m The GlobalVariable object 117 */ 118 public void setGlobalVariable(NamedBeanHandle<GlobalVariable> m) { 119 if (namedGlobalVariable != null) { 120 getGlobalVariable().removePropertyChangeListener(this); 121 } 122 namedGlobalVariable = m; 123 if (namedGlobalVariable != null) { 124 getGlobalVariable().addPropertyChangeListener(this, namedGlobalVariable.getName(), "GlobalVariable Input Icon"); 125 displayState(); 126 setName(namedGlobalVariable.getName()); 127 } 128 } 129 130 public NamedBeanHandle<GlobalVariable> getNamedGlobalVariable() { 131 return namedGlobalVariable; 132 } 133 134 public GlobalVariable getGlobalVariable() { 135 if (namedGlobalVariable == null) { 136 return null; 137 } 138 return namedGlobalVariable.getBean(); 139 } 140 141 @Override 142 public ComboModel getComboModel() { 143 return _model; 144 } 145 146 /** 147 * Display 148 */ 149 @Override 150 public void actionPerformed(ActionEvent e) { 151 update(); 152 } 153 154 // update icon as state of GlobalVariable changes 155 @Override 156 public void propertyChange(java.beans.PropertyChangeEvent e) { 157 if (e.getPropertyName().equals("value")) { 158 displayState(); 159 } 160 } 161 162 @Override 163 @Nonnull 164 public String getTypeString() { 165 return Bundle.getMessage("PositionableType_GlobalVariableComboIcon"); 166 } 167 168 @Override 169 public String getNameString() { 170 String name; 171 if (namedGlobalVariable == null) { 172 name = Bundle.getMessage("NotConnected"); 173 } else { 174 name = getGlobalVariable().getDisplayName(DisplayOptions.USERNAME_SYSTEMNAME); 175 } 176 return name; 177 } 178 179 @Override 180 protected void update() { 181 if (namedGlobalVariable == null) { 182 return; 183 } 184 getGlobalVariable().setValue(_comboBox.getSelectedItem()); 185 } 186 187 @Override 188 public boolean setEditIconMenu(javax.swing.JPopupMenu popup) { 189 String txt = java.text.MessageFormat.format(Bundle.getMessage("EditItem"), Bundle.getMessage("BeanNameGlobalVariable")); 190 popup.add(new javax.swing.AbstractAction(txt) { 191 @Override 192 public void actionPerformed(ActionEvent e) { 193 edit(); 194 } 195 }); 196 return true; 197 } 198 199 /** 200 * Popup menu iconEditor's ActionListener 201 */ 202 private DefaultListModel<String> _listModel; 203 204 @Override 205 protected void edit() { 206 _iconEditor = new IconAdder("GlobalVariable") { 207 JList<String> list; 208 final JButton bDel = new JButton(Bundle.getMessage("deleteSelection")); 209 final JButton bAdd = new JButton(Bundle.getMessage("addItem")); 210 final JTextField textfield = new JTextField(30); 211 int idx; 212 213 @Override 214 protected void addAdditionalButtons(JPanel p) { 215 _listModel = new DefaultListModel<>(); 216 bDel.addActionListener(a -> { 217 if ( list == null ){ return; } 218 idx = list.getSelectedIndex(); 219 if (idx >= 0) { 220 _listModel.removeElementAt(idx); 221 } 222 }); 223 bAdd.addActionListener(a -> { 224 String text = textfield.getText(); 225 if (text == null || list == null || text.length() == 0 || _listModel.indexOf(text) >= 0) { 226 return; 227 } 228 idx = list.getSelectedIndex(); 229 if (idx < 0) { 230 idx = _listModel.getSize(); 231 } 232 _listModel.add(idx, text); 233 }); 234 for (int i = 0; i < _model.getSize(); i++) { 235 _listModel.add(i, _model.getElementAt(i)); 236 } 237 list = new JList<>(_listModel); 238 JScrollPane scrollPane = new JScrollPane(list); 239 JPanel p1 = new JPanel(); 240 p1.add(new JLabel(Bundle.getMessage("comboList"))); 241 p.add(p1); 242 p.add(scrollPane); 243 p1 = new JPanel(); 244 p1.add(new JLabel(Bundle.getMessage("newItem"), SwingConstants.RIGHT)); 245 textfield.setMaximumSize(textfield.getPreferredSize()); 246 p1.add(textfield); 247 p.add(p1); 248 JPanel p2 = new JPanel(); 249 //p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS)); 250 //p2.setLayout(new FlowLayout(FlowLayout.TRAILING)); 251 p2.add(bDel); 252 p2.add(bAdd); 253 p.add(p2); 254 p.setVisible(true); 255 } 256 }; 257 258 makeIconEditorFrame(this, "GlobalVariable", true, _iconEditor); 259 _iconEditor.setPickList(jmri.jmrit.picker.PickListModel.globalVariablePickModelInstance()); 260 ActionListener addIconAction = a -> editGlobalVariable(); 261 262 _iconEditor.makeIconPanel(false); 263 _iconEditor.complete(addIconAction, false, false, true); 264 _iconEditor.setSelection(getGlobalVariable()); 265 } 266 267 void editGlobalVariable() { 268 jmri.NamedBean bean = _iconEditor.getTableSelection(); 269 setGlobalVariable(bean.getDisplayName()); 270 _model.removeAllElements(); 271 for (int i = 0; i < _listModel.size(); i++) { 272 _model.addElement(_listModel.getElementAt(i)); 273 } 274 setSize(getPreferredSize().width + 1, getPreferredSize().height); 275 _iconEditorFrame.dispose(); 276 _iconEditorFrame = null; 277 _iconEditor = null; 278 validate(); 279 } 280 281 /** 282 * Drive the current state of the display from the state of the GlobalVariable. 283 */ 284 public void displayState() { 285 log.debug("displayState"); 286 if (namedGlobalVariable == null) { // leave alone if not connected yet 287 return; 288 } 289 _model.setSelectedItem(getGlobalVariable().getValue()); 290 } 291 292 @Override 293 public void mouseExited(JmriMouseEvent e) { 294 _comboBox.setFocusable(false); 295 _comboBox.transferFocus(); 296 super.mouseExited(e); 297 } 298 299 @Override 300 void cleanup() { 301 if (namedGlobalVariable != null) { 302 getGlobalVariable().removePropertyChangeListener(this); 303 } 304 if (_comboBox != null) { 305 for (int i = 0; i < _comboBox.getComponentCount(); i++) { 306 java.awt.Component component = _comboBox.getComponent(i); 307 if (component instanceof AbstractButton) { 308 component.removeMouseListener(_mouseListener); 309 component.removeMouseMotionListener(_mouseMotionListener); 310 } 311 } 312 _comboBox.removeMouseListener(_mouseListener); 313 } 314 namedGlobalVariable = null; 315 } 316 317 private final static Logger log = LoggerFactory.getLogger(GlobalVariableComboIcon.class); 318 319}