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 void stateChanged(ChangeEvent e) { 146 spinnerUpdated(); 147 } 148 149 @Override 150 @Nonnull 151 public String getTypeString() { 152 return Bundle.getMessage("PositionableType_MemorySpinnerIcon"); 153 } 154 155 @Override 156 public String getNameString() { 157 String name; 158 if (namedMemory == null) { 159 name = Bundle.getMessage("NotConnected"); 160 } else { 161 name = getMemory().getDisplayName(DisplayOptions.USERNAME_SYSTEMNAME); 162 } 163 return name; 164 } 165 166 /* 167 public void setSelectable(boolean b) {selectable = b;} 168 public boolean isSelectable() { return selectable;} 169 boolean selectable = false; 170 */ 171 @Override 172 public boolean setEditIconMenu(javax.swing.JPopupMenu popup) { 173 String txt = java.text.MessageFormat.format(Bundle.getMessage("EditItem"), Bundle.getMessage("BeanNameMemory")); 174 popup.add(new AbstractAction(txt) { 175 @Override 176 public void actionPerformed(ActionEvent e) { 177 edit(); 178 } 179 }); 180 return true; 181 } 182 183 @Override 184 protected void edit() { 185 makeIconEditorFrame(this, "Memory", true, null); 186 _iconEditor.setPickList(jmri.jmrit.picker.PickListModel.memoryPickModelInstance()); 187 ActionListener addIconAction = a -> editMemory(); 188 _iconEditor.complete(addIconAction, false, true, true); 189 _iconEditor.setSelection(getMemory()); 190 } 191 192 void editMemory() { 193 setMemory(_iconEditor.getTableSelection().getDisplayName()); 194 setSize(getPreferredSize().width, getPreferredSize().height); 195 _iconEditorFrame.dispose(); 196 _iconEditorFrame = null; 197 _iconEditor = null; 198 invalidate(); 199 } 200 201 /** 202 * Drive the current state of the display from the state of the Memory. 203 */ 204 public void displayState() { 205 log.debug("displayState"); 206 if (namedMemory == null) { // leave alone if not connected yet 207 return; 208 } 209 if (getMemory().getValue() == null) { 210 return; 211 } 212 Integer num = null; 213 if (getMemory().getValue().getClass() == String.class) { 214 try { 215 num = Integer.valueOf((String) getMemory().getValue()); 216 } catch (NumberFormatException e) { 217 return; 218 } 219 } else if (getMemory().getValue().getClass() == Integer.class) { 220 num = ((Number) getMemory().getValue()).intValue(); 221 } else if (getMemory().getValue().getClass() == Float.class) { 222 num = Math.round((Float) getMemory().getValue()); 223 log.debug("num= {}", num); 224 } else { 225 //spinner.setValue(getMemory().getValue()); 226 return; 227 } 228 int n = num; 229 if (n > _max) { 230 num = _max; 231 } else if (n < _min) { 232 num = _min; 233 } 234 spinner.setValue(num); 235 } 236 237 @Override 238 public void mouseExited(JmriMouseEvent e) { 239 spinnerUpdated(); 240 super.mouseExited(e); 241 } 242 243 protected void spinnerUpdated() { 244 if (namedMemory == null) { 245 return; 246 } 247 if (getMemory().getValue() == null) { 248 getMemory().setValue(spinner.getValue()); 249 return; 250 } 251 // Spinner is always an Integer, but memory can contain Integer or String 252 if (getMemory().getValue().getClass() == String.class) { 253 String newValue = "" + spinner.getValue(); 254 if (!getMemory().getValue().equals(newValue)) { 255 getMemory().setValue(newValue); 256 } 257 } else { 258 getMemory().setValue(spinner.getValue()); 259 } 260 } 261 262 public String getValue() { 263 return "" + spinner.getValue(); 264 } 265 266 @Override 267 void cleanup() { 268 if (namedMemory != null) { 269 getMemory().removePropertyChangeListener(this); 270 } 271 if (spinner != null) { 272 spinner.removeChangeListener(this); 273 ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().removeMouseMotionListener(_mouseMotionListener); 274 ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().removeMouseListener(_mouseListener); 275 } 276 namedMemory = null; 277 } 278 279 private final static Logger log = LoggerFactory.getLogger(MemorySpinnerIcon.class); 280}