001package jmri.jmrit.display.layoutEditor; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004 005import javax.swing.JCheckBoxMenuItem; 006import javax.swing.JPopupMenu; 007 008import jmri.Reportable; 009import jmri.jmrit.catalog.NamedIcon; 010import jmri.jmrit.roster.RosterEntry; 011import jmri.util.swing.JmriJOptionPane; 012 013/** 014 * An icon to display a status of a Memory. 015 * 016 * This is the same name as display.MemoryIcon, but a very 017 * separate class. That's not good. Unfortunately, it's too 018 * hard to disentangle that now because it's resident in the 019 * panel file that have been written out, so we just annotated 020 * the fact, but now we want to leave it on the list to fix. 021 */ 022@SuppressFBWarnings(value = "NM_SAME_SIMPLE_NAME_AS_SUPERCLASS", justification="Cannot rename for user data compatiblity reasons.") 023public class MemoryIcon extends jmri.jmrit.display.MemoryIcon { 024 025 private final String defaultText = " "; 026 027 public MemoryIcon(String s, LayoutEditor panel) { 028 super(s, panel); 029 this.panel = panel; 030 log.debug("MemoryIcon ctor= {}", MemoryIcon.class.getName()); 031 } 032 033 LayoutEditor panel; 034 035 @Override 036 public void setText(String text) { 037 if (text == null || text.isEmpty()) { 038 super.setText(defaultText); 039 } else { 040 super.setText(text); 041 } 042 } 043 044 private LayoutBlock lBlock = null; 045 046 public LayoutBlock getLayoutBlock() { 047 return lBlock; 048 } 049 050 public void setLayoutBlock(LayoutBlock lb) { 051 lBlock = lb; 052 } 053 054 @Override 055 public void displayState() { 056 log.debug("displayState"); 057 if (getMemory() == null) { // use default if not connected yet 058 setText(defaultText); 059 updateSize(); 060 return; 061 } 062 if (re != null) { 063 jmri.InstanceManager.throttleManagerInstance().removeListener(re.getDccLocoAddress(), this); 064 re = null; 065 } 066 Object key = getMemory().getValue(); 067 if (key != null) { 068 java.util.HashMap<String, NamedIcon> map = getMap(); 069 if (map == null) { 070 // no map, attempt to show object directly 071 Object val = key; 072 if (val instanceof jmri.jmrit.roster.RosterEntry) { 073 jmri.jmrit.roster.RosterEntry roster = (jmri.jmrit.roster.RosterEntry) val; 074 val = updateIconFromRosterVal(roster); 075 flipRosterIcon = false; 076 if (val == null) { 077 return; 078 } 079 } 080 if (val instanceof String) { 081 if (((String)val).isEmpty()) { 082 setText(defaultText); 083 } else { 084 setText((String) val); 085 } 086 setIcon(null); 087 _text = true; 088 _icon = false; 089 setAttributes(getPopupUtility(), this); 090 updateSize(); 091 } else if (val instanceof javax.swing.ImageIcon) { 092 setIcon((javax.swing.ImageIcon) val); 093 setText(null); 094 _text = false; 095 _icon = true; 096 updateSize(); 097 } else if (val instanceof Number) { 098 setText(val.toString()); 099 setIcon(null); 100 _text = true; 101 _icon = false; 102 setAttributes(getPopupUtility(), this); 103 updateSize(); 104 } else if (val instanceof jmri.IdTag){ 105 // most IdTags are Reportable objects, so 106 // this needs to be before Reportable 107 setText(((jmri.IdTag)val).getDisplayName()); 108 setIcon(null); 109 _text = true; 110 _icon = false; 111 updateSize(); 112 } else if (val instanceof Reportable) { 113 setText(((Reportable)val).toReportString()); 114 setIcon(null); 115 _text = true; 116 _icon = false; 117 updateSize(); 118 } else { 119 log.warn("can't display current value of {}, val= {} of Class {}", getNamedMemory().getName(), val, val.getClass().getName()); 120 } 121 } else { 122 // map exists, use it 123 NamedIcon newicon = map.get(key.toString()); 124 if (newicon != null) { 125 126 setText(null); 127 super.setIcon(newicon); 128 _text = false; 129 _icon = true; 130 updateSize(); 131 } else { 132 // no match, use default 133 setIcon(getDefaultIcon()); 134 135 setText(null); 136 _text = false; 137 _icon = true; 138 updateSize(); 139 } 140 } 141 } else { 142 setIcon(null); 143 setText(defaultText); 144 _text = true; 145 _icon = false; 146 updateSize(); 147 } 148 } 149 150 private final JCheckBoxMenuItem updateBlockItem = new JCheckBoxMenuItem("Update Block Details"); 151 152 // force a redisplay when content changes 153 @Override 154 public void propertyChange(java.beans.PropertyChangeEvent e) { 155 super.propertyChange(e); 156 panel.redrawPanel(); 157 } 158 159 @Override 160 public boolean showPopUp(JPopupMenu popup) { 161 if (isEditable()) { 162 popup.add(updateBlockItem); 163 updateBlockItem.setSelected(updateBlockValueOnChange()); 164 updateBlockItem.addActionListener((java.awt.event.ActionEvent e) -> updateBlockValueOnChange(updateBlockItem.isSelected())); 165 } // end of selectable 166 return super.showPopUp(popup); 167 } 168 169 @Override 170 public void setMemory(String pName) { 171 super.setMemory(pName); 172 lBlock = jmri.InstanceManager.getDefault(LayoutBlockManager.class).getBlockWithMemoryAssigned(getMemory()); 173 } 174 175 @Override 176 protected void setValue(Object obj) { 177 if (updateBlockValue && lBlock != null) { 178 lBlock.getBlock().setValue(obj); 179 } else { 180 getMemory().setValue(obj); 181 updateSize(); 182 } 183 } 184 185 @Override 186 protected void addRosterToIcon(RosterEntry roster) { 187 if (!jmri.InstanceManager.getDefault(LayoutBlockManager.class).isAdvancedRoutingEnabled() || lBlock == null) { 188 super.addRosterToIcon(roster); 189 return; 190 } 191 192 int paths = lBlock.getNumberOfThroughPaths(); 193 jmri.Block srcBlock = null; 194 jmri.Block desBlock = null; 195 for (int i = 0; i < paths; i++) { 196 if (lBlock.isThroughPathActive(i)) { 197 srcBlock = lBlock.getThroughPathSource(i); 198 desBlock = lBlock.getThroughPathDestination(i); 199 break; 200 } 201 } 202 int dirA; 203 int dirB; 204 if (srcBlock != null && desBlock != null) { 205 dirA = lBlock.getNeighbourDirection(srcBlock); 206 dirB = lBlock.getNeighbourDirection(desBlock); 207 } else { 208 dirA = jmri.Path.EAST; 209 dirB = jmri.Path.WEST; 210 } 211 212 Object[] options = {"Facing " + jmri.Path.decodeDirection(dirB), 213 "Facing " + jmri.Path.decodeDirection(dirA), 214 "Do Not Add"}; 215 int n = JmriJOptionPane.showOptionDialog(this, 216 "Would you like to assign loco " 217 + roster.titleString() + " to this location", 218 "Assign Loco", 219 JmriJOptionPane.DEFAULT_OPTION, 220 JmriJOptionPane.QUESTION_MESSAGE, 221 null, 222 options, 223 options[2]); 224 if (n == 2 || n==JmriJOptionPane.CLOSED_OPTION ) { // array position 2, Do Not Add 225 return; 226 } 227 if (n == 0) { // array position 0, facing DirB 228 flipRosterIcon = true; 229 if (updateBlockValue) { 230 lBlock.getBlock().setDirection(dirB); 231 } 232 } else { 233 flipRosterIcon = false; 234 if (updateBlockValue) { 235 lBlock.getBlock().setDirection(dirA); 236 } 237 } 238 if (getMemory().getValue() == roster) { 239 //No change in the loco but a change in direction facing might have occurred 240 updateIconFromRosterVal(roster); 241 } else { 242 setValue(roster); 243 } 244 } 245 246 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MemoryIcon.class); 247}