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.BoxLayout; 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 @Nonnull 163 public String getTypeString() { 164 return Bundle.getMessage("PositionableType_MemoryComboIcon"); 165 } 166 167 @Override 168 public String getNameString() { 169 String name; 170 if (namedMemory == null) { 171 name = Bundle.getMessage("NotConnected"); 172 } else { 173 name = getMemory().getDisplayName(DisplayOptions.USERNAME_SYSTEMNAME); 174 } 175 return name; 176 } 177 178 @Override 179 protected void update() { 180 if (namedMemory == null) { 181 return; 182 } 183 getMemory().setValue(_comboBox.getSelectedItem()); 184 } 185 186 @Override 187 public boolean setEditIconMenu(javax.swing.JPopupMenu popup) { 188 String txt = java.text.MessageFormat.format(Bundle.getMessage("EditItem"), Bundle.getMessage("BeanNameMemory")); 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 private DefaultListModel<String> _listModel; 202 203 @Override 204 protected void edit() { 205 _iconEditor = new IconAdder("Memory") { 206 JList<String> list; 207 final JButton bDel = new JButton(Bundle.getMessage("deleteSelection")); 208 final JButton bAdd = new JButton(Bundle.getMessage("addItem")); 209 final JTextField textfield = new JTextField(30); 210 int idx; 211 212 @Override 213 protected void addAdditionalButtons(JPanel p) { 214 _listModel = new DefaultListModel<>(); 215 bDel.addActionListener(a -> { 216 if ( list == null ){ return; } 217 idx = list.getSelectedIndex(); 218 if (idx >= 0) { 219 _listModel.removeElementAt(idx); 220 } 221 }); 222 bAdd.addActionListener(a -> { 223 String text = textfield.getText(); 224 if (text == null || list == null || text.length() == 0 || _listModel.indexOf(text) >= 0) { 225 return; 226 } 227 idx = list.getSelectedIndex(); 228 if (idx < 0) { 229 idx = _listModel.getSize(); 230 } 231 _listModel.add(idx, text); 232 }); 233 for (int i = 0; i < _model.getSize(); i++) { 234 _listModel.add(i, _model.getElementAt(i)); 235 } 236 list = new JList<>(_listModel); 237 JScrollPane scrollPane = new JScrollPane(list); 238 JPanel p1 = new JPanel(); 239 p1.add(new JLabel(Bundle.getMessage("comboList"))); 240 p.add(p1); 241 p.add(scrollPane); 242 p1 = new JPanel(); 243 JPanel pInner1 = new JPanel(); 244 pInner1.setLayout(new BoxLayout(pInner1, BoxLayout.X_AXIS)); 245 pInner1.add(new JLabel(Bundle.getMessage("newItem"), SwingConstants.RIGHT)); 246 pInner1.add(textfield); 247 p1.add(pInner1); 248 p.add(p1); 249 JPanel p2 = new JPanel(); 250 //p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS)); 251 //p2.setLayout(new FlowLayout(FlowLayout.TRAILING)); 252 p2.add(bDel); 253 p2.add(bAdd); 254 p.add(p2); 255 p.setVisible(true); 256 } 257 }; 258 259 makeIconEditorFrame(this, "Memory", true, _iconEditor); 260 _iconEditor.setPickList(jmri.jmrit.picker.PickListModel.memoryPickModelInstance()); 261 ActionListener addIconAction = a -> editMemory(); 262 263 _iconEditor.makeIconPanel(false); 264 _iconEditor.complete(addIconAction, false, true, true); 265 _iconEditor.setSelection(getMemory()); 266 } 267 268 void editMemory() { 269 jmri.NamedBean bean = _iconEditor.getTableSelection(); 270 setMemory(bean.getDisplayName()); 271 _model.removeAllElements(); 272 for (int i = 0; i < _listModel.size(); i++) { 273 _model.addElement(_listModel.getElementAt(i)); 274 } 275 setSize(getPreferredSize().width + 1, getPreferredSize().height); 276 _iconEditorFrame.dispose(); 277 _iconEditorFrame = null; 278 _iconEditor = null; 279 validate(); 280 } 281 282 /** 283 * Drive the current state of the display from the state of the Memory. 284 */ 285 public void displayState() { 286 log.debug("displayState"); 287 if (namedMemory == null) { // leave alone if not connected yet 288 return; 289 } 290 _model.setSelectedItem(getMemory().getValue()); 291 } 292 293 @Override 294 public void mouseExited(JmriMouseEvent e) { 295 _comboBox.setFocusable(false); 296 _comboBox.transferFocus(); 297 super.mouseExited(e); 298 } 299 300 @Override 301 void cleanup() { 302 if (namedMemory != null) { 303 getMemory().removePropertyChangeListener(this); 304 } 305 if (_comboBox != null) { 306 for (int i = 0; i < _comboBox.getComponentCount(); i++) { 307 java.awt.Component component = _comboBox.getComponent(i); 308 if (component instanceof AbstractButton) { 309 component.removeMouseListener(_mouseListener); 310 component.removeMouseMotionListener(_mouseMotionListener); 311 } 312 } 313 _comboBox.removeMouseListener(_mouseListener); 314 } 315 namedMemory = null; 316 } 317 318 private final static Logger log = LoggerFactory.getLogger(MemoryComboIcon.class); 319 320}