001package jmri.jmrit.display; 002 003import java.awt.Dimension; 004import java.awt.event.ActionEvent; 005import java.awt.event.ActionListener; 006import java.beans.PropertyChangeListener; 007 008import javax.swing.AbstractAction; 009import javax.swing.JSpinner; 010import javax.swing.SpinnerNumberModel; 011import javax.swing.event.ChangeEvent; 012import javax.swing.event.ChangeListener; 013 014import jmri.InstanceManager; 015import jmri.Memory; 016import jmri.NamedBeanHandle; 017import jmri.NamedBean.DisplayOptions; 018import jmri.util.swing.*; 019 020import org.slf4j.Logger; 021import org.slf4j.LoggerFactory; 022 023/** 024 * An icon to display a status of a Memory in a JSpinner. 025 * <p> 026 * Handles the case of either a String or an Integer in the Memory, preserving 027 * what it finds. 028 * 029 * @author Bob Jacobsen Copyright (c) 2009 030 * @since 2.7.2 031 */ 032public class MemorySpinnerIcon extends PositionableJPanel implements ChangeListener, PropertyChangeListener { 033 034 int _min = 0; 035 int _max = 100; 036 JSpinner spinner = new JSpinner(new SpinnerNumberModel(0, _min, _max, 1)); 037 // the associated Memory object 038 //Memory memory = null; 039 private NamedBeanHandle<Memory> namedMemory; 040 041 private final java.awt.event.MouseListener _mouseListener = JmriMouseListener.adapt(this); 042 private final java.awt.event.MouseMotionListener _mouseMotionListener = JmriMouseMotionListener.adapt(this); 043 044 public MemorySpinnerIcon(Editor editor) { 045 super(editor); 046 setDisplayLevel(Editor.LABELS); 047 048 setLayout(new java.awt.GridBagLayout()); 049 add(spinner, new java.awt.GridBagConstraints()); 050 spinner.addChangeListener(this); 051 javax.swing.JTextField textBox = ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField(); 052 textBox.addMouseMotionListener(_mouseMotionListener); 053 textBox.addMouseListener(_mouseListener); 054 setPopupUtility(new PositionablePopupUtil(this, textBox)); 055 } 056 057 @Override 058 public Positionable deepClone() { 059 MemorySpinnerIcon pos = new MemorySpinnerIcon(_editor); 060 return finishClone(pos); 061 } 062 063 protected Positionable finishClone(MemorySpinnerIcon pos) { 064 pos.setMemory(namedMemory.getName()); 065 return super.finishClone(pos); 066 } 067 068 @Override 069 public javax.swing.JComponent getTextComponent() { 070 return ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField(); 071 } 072 073 @Override 074 public Dimension getSize() { 075 if (log.isDebugEnabled()) { 076 Dimension d = spinner.getSize(); 077 log.debug("spinner width= {}, height= {}", d.width, d.height); 078 java.awt.Rectangle rect = getBounds(null); 079 log.debug("Bounds rect= ({},{}) width= {}, height= {}", 080 rect.x, rect.y, rect.width, rect.height); 081 d = super.getSize(); 082 log.debug("Panel width= {}, height= {}", d.width, d.height); 083 } 084 return super.getSize(); 085 } 086 087 /** 088 * Attached a named Memory to this display item 089 * 090 * @param pName Used as a system/user name to lookup the Memory object 091 */ 092 public void setMemory(String pName) { 093 log.debug("setMemory for memory= {}", pName); 094 if (InstanceManager.getNullableDefault(jmri.MemoryManager.class) != null) { 095 try { 096 Memory memory = InstanceManager.memoryManagerInstance().provideMemory(pName); 097 setMemory(jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(pName, memory)); 098 } catch (IllegalArgumentException e) { 099 log.error("Memory '{}' not available, icon won't see changes", pName); 100 } 101 } else { 102 log.error("No MemoryManager for this protocol, icon won't see changes"); 103 } 104 updateSize(); 105 } 106 107 /** 108 * Attached a named Memory to this display item 109 * 110 * @param m The Memory object 111 */ 112 public void setMemory(NamedBeanHandle<Memory> m) { 113 if (namedMemory != null) { 114 getMemory().removePropertyChangeListener(this); 115 } 116 namedMemory = m; 117 if (namedMemory != null) { 118 getMemory().addPropertyChangeListener(this, namedMemory.getName(), "Memory Spinner Icon"); 119 displayState(); 120 setName(namedMemory.getName()); 121 } 122 } 123 124 public NamedBeanHandle<Memory> getNamedMemory() { 125 return namedMemory; 126 } 127 128 // update icon as state of Memory changes 129 @Override 130 public void propertyChange(java.beans.PropertyChangeEvent e) { 131 if (e.getPropertyName().equals("value")) { 132 displayState(); 133 } 134 } 135 136 public Memory getMemory() { 137 if (namedMemory == null) { 138 return null; 139 } 140 return namedMemory.getBean(); 141 } 142 143 @Override 144 public void stateChanged(ChangeEvent e) { 145 spinnerUpdated(); 146 } 147 148 @Override 149 public String getNameString() { 150 String name; 151 if (namedMemory == null) { 152 name = Bundle.getMessage("NotConnected"); 153 } else { 154 name = getMemory().getDisplayName(DisplayOptions.USERNAME_SYSTEMNAME); 155 } 156 return name; 157 } 158 159 /* 160 public void setSelectable(boolean b) {selectable = b;} 161 public boolean isSelectable() { return selectable;} 162 boolean selectable = false; 163 */ 164 @Override 165 public boolean setEditIconMenu(javax.swing.JPopupMenu popup) { 166 String txt = java.text.MessageFormat.format(Bundle.getMessage("EditItem"), Bundle.getMessage("BeanNameMemory")); 167 popup.add(new AbstractAction(txt) { 168 @Override 169 public void actionPerformed(ActionEvent e) { 170 edit(); 171 } 172 }); 173 return true; 174 } 175 176 @Override 177 protected void edit() { 178 makeIconEditorFrame(this, "Memory", true, null); 179 _iconEditor.setPickList(jmri.jmrit.picker.PickListModel.memoryPickModelInstance()); 180 ActionListener addIconAction = a -> editMemory(); 181 _iconEditor.complete(addIconAction, false, true, true); 182 _iconEditor.setSelection(getMemory()); 183 } 184 185 void editMemory() { 186 setMemory(_iconEditor.getTableSelection().getDisplayName()); 187 setSize(getPreferredSize().width, getPreferredSize().height); 188 _iconEditorFrame.dispose(); 189 _iconEditorFrame = null; 190 _iconEditor = null; 191 invalidate(); 192 } 193 194 /** 195 * Drive the current state of the display from the state of the Memory. 196 */ 197 public void displayState() { 198 log.debug("displayState"); 199 if (namedMemory == null) { // leave alone if not connected yet 200 return; 201 } 202 if (getMemory().getValue() == null) { 203 return; 204 } 205 Integer num = null; 206 if (getMemory().getValue().getClass() == String.class) { 207 try { 208 num = Integer.valueOf((String) getMemory().getValue()); 209 } catch (NumberFormatException e) { 210 return; 211 } 212 } else if (getMemory().getValue().getClass() == Integer.class) { 213 num = ((Number) getMemory().getValue()).intValue(); 214 } else if (getMemory().getValue().getClass() == Float.class) { 215 num = Math.round((Float) getMemory().getValue()); 216 log.debug("num= {}", num); 217 } else { 218 //spinner.setValue(getMemory().getValue()); 219 return; 220 } 221 int n = num; 222 if (n > _max) { 223 num = _max; 224 } else if (n < _min) { 225 num = _min; 226 } 227 spinner.setValue(num); 228 } 229 230 @Override 231 public void mouseExited(JmriMouseEvent e) { 232 spinnerUpdated(); 233 super.mouseExited(e); 234 } 235 236 protected void spinnerUpdated() { 237 if (namedMemory == null) { 238 return; 239 } 240 if (getMemory().getValue() == null) { 241 getMemory().setValue(spinner.getValue()); 242 return; 243 } 244 // Spinner is always an Integer, but memory can contain Integer or String 245 if (getMemory().getValue().getClass() == String.class) { 246 String newValue = "" + spinner.getValue(); 247 if (!getMemory().getValue().equals(newValue)) { 248 getMemory().setValue(newValue); 249 } 250 } else { 251 getMemory().setValue(spinner.getValue()); 252 } 253 } 254 255 public String getValue() { 256 return "" + spinner.getValue(); 257 } 258 259 @Override 260 void cleanup() { 261 if (namedMemory != null) { 262 getMemory().removePropertyChangeListener(this); 263 } 264 if (spinner != null) { 265 spinner.removeChangeListener(this); 266 ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().removeMouseMotionListener(_mouseMotionListener); 267 ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().removeMouseListener(_mouseListener); 268 } 269 namedMemory = null; 270 } 271 272 private final static Logger log = LoggerFactory.getLogger(MemorySpinnerIcon.class); 273}