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 updateSize(); 103 } else if (val instanceof jmri.IdTag){ 104 // most IdTags are Reportable objects, so 105 // this needs to be before Reportable 106 setText(((jmri.IdTag)val).getDisplayName()); 107 setIcon(null); 108 _text = true; 109 _icon = false; 110 updateSize(); 111 } else if (val instanceof Reportable) { 112 setText(((Reportable)val).toReportString()); 113 setIcon(null); 114 _text = true; 115 _icon = false; 116 updateSize(); 117 } else { 118 log.warn("can't display current value of {}, val= {} of Class {}", getNamedMemory().getName(), val, val.getClass().getName()); 119 } 120 } else { 121 // map exists, use it 122 NamedIcon newicon = map.get(key.toString()); 123 if (newicon != null) { 124 125 setText(null); 126 super.setIcon(newicon); 127 _text = false; 128 _icon = true; 129 updateSize(); 130 } else { 131 // no match, use default 132 setIcon(getDefaultIcon()); 133 134 setText(null); 135 _text = false; 136 _icon = true; 137 updateSize(); 138 } 139 } 140 } else { 141 setIcon(null); 142 setText(defaultText); 143 _text = true; 144 _icon = false; 145 updateSize(); 146 } 147 } 148 149 private final JCheckBoxMenuItem updateBlockItem = new JCheckBoxMenuItem("Update Block Details"); 150 151 // force a redisplay when content changes 152 @Override 153 public void propertyChange(java.beans.PropertyChangeEvent e) { 154 super.propertyChange(e); 155 panel.redrawPanel(); 156 } 157 158 @Override 159 public boolean showPopUp(JPopupMenu popup) { 160 if (isEditable()) { 161 popup.add(updateBlockItem); 162 updateBlockItem.setSelected(updateBlockValueOnChange()); 163 updateBlockItem.addActionListener((java.awt.event.ActionEvent e) -> updateBlockValueOnChange(updateBlockItem.isSelected())); 164 } // end of selectable 165 return super.showPopUp(popup); 166 } 167 168 @Override 169 public void setMemory(String pName) { 170 super.setMemory(pName); 171 lBlock = jmri.InstanceManager.getDefault(LayoutBlockManager.class).getBlockWithMemoryAssigned(getMemory()); 172 } 173 174 @Override 175 protected void setValue(Object obj) { 176 if (updateBlockValue && lBlock != null) { 177 lBlock.getBlock().setValue(obj); 178 } else { 179 getMemory().setValue(obj); 180 updateSize(); 181 } 182 } 183 184 @Override 185 protected void addRosterToIcon(RosterEntry roster) { 186 if (!jmri.InstanceManager.getDefault(LayoutBlockManager.class).isAdvancedRoutingEnabled() || lBlock == null) { 187 super.addRosterToIcon(roster); 188 return; 189 } 190 191 int paths = lBlock.getNumberOfThroughPaths(); 192 jmri.Block srcBlock = null; 193 jmri.Block desBlock = null; 194 for (int i = 0; i < paths; i++) { 195 if (lBlock.isThroughPathActive(i)) { 196 srcBlock = lBlock.getThroughPathSource(i); 197 desBlock = lBlock.getThroughPathDestination(i); 198 break; 199 } 200 } 201 int dirA; 202 int dirB; 203 if (srcBlock != null && desBlock != null) { 204 dirA = lBlock.getNeighbourDirection(srcBlock); 205 dirB = lBlock.getNeighbourDirection(desBlock); 206 } else { 207 dirA = jmri.Path.EAST; 208 dirB = jmri.Path.WEST; 209 } 210 211 Object[] options = {"Facing " + jmri.Path.decodeDirection(dirB), 212 "Facing " + jmri.Path.decodeDirection(dirA), 213 "Do Not Add"}; 214 int n = JmriJOptionPane.showOptionDialog(this, 215 "Would you like to assign loco " 216 + roster.titleString() + " to this location", 217 "Assign Loco", 218 JmriJOptionPane.DEFAULT_OPTION, 219 JmriJOptionPane.QUESTION_MESSAGE, 220 null, 221 options, 222 options[2]); 223 if (n == 2 || n==JmriJOptionPane.CLOSED_OPTION ) { // array position 2, Do Not Add 224 return; 225 } 226 if (n == 0) { // array position 0, facing DirB 227 flipRosterIcon = true; 228 if (updateBlockValue) { 229 lBlock.getBlock().setDirection(dirB); 230 } 231 } else { 232 flipRosterIcon = false; 233 if (updateBlockValue) { 234 lBlock.getBlock().setDirection(dirA); 235 } 236 } 237 if (getMemory().getValue() == roster) { 238 //No change in the loco but a change in direction facing might have occurred 239 updateIconFromRosterVal(roster); 240 } else { 241 setValue(roster); 242 } 243 } 244 245 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MemoryIcon.class); 246}