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