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