001package jmri.jmrit.display; 002 003import java.awt.event.ActionEvent; 004import java.awt.event.ActionListener; 005import java.util.Map; 006 007import javax.annotation.Nonnull; 008import javax.swing.AbstractAction; 009import javax.swing.JPopupMenu; 010import javax.swing.JSeparator; 011 012import jmri.Block; 013import jmri.InstanceManager; 014import jmri.NamedBeanHandle; 015import jmri.NamedBean.DisplayOptions; 016import jmri.jmrit.catalog.NamedIcon; 017import jmri.jmrit.throttle.ThrottleFrame; 018import jmri.jmrit.throttle.ThrottleFrameManager; 019import jmri.util.swing.JmriJOptionPane; 020import jmri.util.swing.JmriMouseEvent; 021 022/** 023 * An icon to display the value contained within a Block. 024 * 025 * @author Bob Jacobsen Copyright (c) 2004 026 */ 027public class BlockContentsIcon extends MemoryIcon { 028 029 private NamedIcon defaultIcon = null; 030 private NamedBeanHandle<Block> namedBlock; 031 032 public BlockContentsIcon(String s, Editor editor) { 033 super(s, editor); 034 BlockContentsIcon.this.resetDefaultIcon(); 035 _namedIcon = defaultIcon; 036 //By default all text objects are left justified 037 _popupUtil.setJustification(LEFT); 038 this.setTransferHandler(new TransferHandler()); 039 } 040 041 public BlockContentsIcon(NamedIcon s, Editor editor) { 042 super(s, editor); 043 setDisplayLevel(Editor.LABELS); 044 defaultIcon = s; 045 _popupUtil.setJustification(LEFT); 046 log.debug("BlockContentsIcon ctor= {}", BlockContentsIcon.class.getName()); 047 this.setTransferHandler(new TransferHandler()); 048 } 049 050 @Override 051 @Nonnull 052 public Positionable deepClone() { 053 BlockContentsIcon pos = new BlockContentsIcon("", _editor); 054 return finishClone(pos); 055 } 056 057 protected Positionable finishClone(BlockContentsIcon pos) { 058 pos.setBlock(namedBlock); 059 pos.setOriginalLocation(getOriginalX(), getOriginalY()); 060 if (map != null) { 061 for (Map.Entry<String, NamedIcon> entry : map.entrySet()) { 062 String url = entry.getValue().getName(); 063 pos.addKeyAndIcon(NamedIcon.getIconByName(url), entry.getKey()); 064 } 065 } 066 return super.finishClone(pos); 067 } 068 069 @Override 070 public void resetDefaultIcon() { 071 defaultIcon = new NamedIcon("resources/icons/misc/X-red.gif", 072 "resources/icons/misc/X-red.gif"); 073 } 074 075 /** 076 * Attach a named Block to this display item. 077 * 078 * @param pName Used as a system/user name to lookup the Block object 079 */ 080 public void setBlock(String pName) { 081 if (InstanceManager.getNullableDefault(jmri.BlockManager.class) != null) { 082 Block block = InstanceManager.getDefault(jmri.BlockManager.class). 083 provideBlock(pName); 084 setBlock(jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(pName, block)); 085 } else { 086 log.error("No Block Manager for this protocol, icon won't see changes"); 087 } 088 updateSize(); 089 } 090 091 /** 092 * Attach a named Block to this display item. 093 * 094 * @param m The Block object 095 */ 096 public void setBlock(NamedBeanHandle<Block> m) { 097 if (namedBlock != null) { 098 getBlock().removePropertyChangeListener(this); 099 } 100 namedBlock = m; 101 if (namedBlock != null) { 102 getBlock().addPropertyChangeListener(this, namedBlock.getName(), "Block Icon"); 103 displayState(); 104 setName(namedBlock.getName()); 105 } 106 } 107 108 public NamedBeanHandle<Block> getNamedBlock() { 109 return namedBlock; 110 } 111 112 public Block getBlock() { 113 if (namedBlock == null) { 114 return null; 115 } 116 return namedBlock.getBean(); 117 } 118 119 @Override 120 public jmri.NamedBean getNamedBean() { 121 return getBlock(); 122 } 123 124 @Override 125 public java.util.HashMap<String, NamedIcon> getMap() { 126 return map; 127 } 128 129 @Override 130 @Nonnull 131 public String getTypeString() { 132 return Bundle.getMessage("PositionableType_BlockContentsIcon"); 133 } 134 135 @Override 136 @Nonnull 137 public String getNameString() { 138 String name; 139 if (namedBlock == null) { 140 name = Bundle.getMessage("NotConnected"); 141 } else { 142 name = getBlock().getDisplayName(DisplayOptions.USERNAME_SYSTEMNAME); 143 } 144 return name; 145 } 146 147 @Override 148 public boolean showPopUp(JPopupMenu popup) { 149 if (isEditable() && selectable) { 150 popup.add(new JSeparator()); 151 152 for (String key : map.keySet()) { 153 //String value = ((NamedIcon)map.get(key)).getName(); 154 popup.add(new AbstractAction(key) { 155 @Override 156 public void actionPerformed(ActionEvent e) { 157 String key = e.getActionCommand(); 158 setValue(key); 159 } 160 }); 161 } 162 return true; 163 } // end of selectable 164 final jmri.jmrit.dispatcher.DispatcherFrame df = 165 jmri.InstanceManager.getNullableDefault(jmri.jmrit.dispatcher.DispatcherFrame.class); 166 final jmri.jmrit.dispatcher.ActiveTrain at; 167 if (df != null) { 168 if (re != null) { 169 at = df.getActiveTrainForRoster(re); 170 } else { 171 at = df.getActiveTrainForName(this.getText()); 172 } 173 } else { 174 at = null; 175 } 176 if (at != null && df != null) { 177 // we have active train, with or without auto train with or without roster entry 178 if (at.getAutoActiveTrain() != null ) { 179 if( re == null ) { 180 popup.add(new AbstractAction("Open Throttle") { 181 @Override 182 public void actionPerformed(ActionEvent e) { 183 ThrottleFrame tf = InstanceManager.getDefault(ThrottleFrameManager.class).createThrottleFrame(); 184 tf.toFront(); 185 tf.getAddressPanel().setAddress(at.getAutoActiveTrain().getDccAddress().getNumber(), 186 at.getAutoActiveTrain().getDccAddress().isLongAddress()); 187 } 188 }); 189 } else { 190 popup.add(new AbstractAction("Open Throttle") { 191 @Override 192 public void actionPerformed(ActionEvent e) { 193 ThrottleFrame tf = InstanceManager.getDefault(ThrottleFrameManager.class).createThrottleFrame(); 194 tf.toFront(); 195 tf.getAddressPanel().setAddress(at.getAutoActiveTrain().getDccAddress().getNumber(), 196 at.getAutoActiveTrain().getDccAddress().isLongAddress()); 197 } 198 }); 199 } 200 } 201 popup.add(new AbstractAction(Bundle.getMessage("MenuTerminateTrain")) { 202 @Override 203 public void actionPerformed(ActionEvent e) { 204 df.terminateActiveTrain(at, true, false); 205 } 206 }); 207 popup.add(new AbstractAction(Bundle.getMessage("MenuAllocateExtra")) { 208 @Override 209 public void actionPerformed(ActionEvent e) { 210 //Just brings up the standard allocate extra frame, this could be expanded in the future 211 //As a point and click operation. 212 df.allocateExtraSection(e, at); 213 } 214 }); 215 if (at.getStatus() == jmri.jmrit.dispatcher.ActiveTrain.DONE) { 216 popup.add(new AbstractAction("Restart") { 217 @Override 218 public void actionPerformed(ActionEvent e) { 219 at.allocateAFresh(); 220 } 221 }); 222 } 223 return true; 224 } else if (re != null) { 225 // No active train, but have a roster, therefore a throttle can be created 226 popup.add(new AbstractAction("Open Throttle") { 227 @Override 228 public void actionPerformed(ActionEvent e) { 229 ThrottleFrame tf = InstanceManager.getDefault(ThrottleFrameManager.class).createThrottleFrame(); 230 tf.toFront(); 231 tf.getAddressPanel().setRosterEntry(re); 232 } 233 }); 234 // if dispatcher exists we can create a new train. 235 if (df != null) { 236 popup.add(new AbstractAction(Bundle.getMessage("MenuNewTrain")) { 237 @Override 238 public void actionPerformed(ActionEvent e) { 239 if (!df.getNewTrainActive()) { 240 df.getActiveTrainFrame().initiateTrain(e, re, getBlock()); 241 df.setNewTrainActive(true); 242 } else { 243 df.getActiveTrainFrame().showActivateFrame(re); 244 } 245 } 246 247 }); 248 } 249 return true; 250 } 251 return false; 252 } 253 254 /** 255 * Text edits cannot be done to Block text - override. 256 */ 257 @Override 258 public boolean setTextEditMenu(JPopupMenu popup) { 259 popup.add(new AbstractAction(Bundle.getMessage("EditBlockValue")) { 260 @Override 261 public void actionPerformed(ActionEvent e) { 262 editBlockValue(); 263 } 264 }); 265 return true; 266 } 267 268 /** 269 * Drive the current state of the display from the state of the Block Value. 270 */ 271 @Override 272 public void displayState() { 273 log.debug("displayState"); 274 if (namedBlock == null) { // use default if not connected yet 275 setIcon(defaultIcon); 276 updateSize(); 277 return; 278 } 279 if (re != null) { 280 jmri.InstanceManager.throttleManagerInstance().removeListener(re.getDccLocoAddress(), this); 281 re = null; 282 } 283 Object key = getBlock().getValue(); 284 displayState(key); 285 } 286 287 @Override 288 public boolean setEditIconMenu(JPopupMenu popup) { 289 String txt = java.text.MessageFormat.format(Bundle.getMessage("EditItem"), Bundle.getMessage("BeanNameBlock")); 290 popup.add(new AbstractAction(txt) { 291 @Override 292 public void actionPerformed(ActionEvent e) { 293 edit(); 294 } 295 }); 296 return true; 297 } 298 299 @Override 300 protected void edit() { 301 makeIconEditorFrame(this, "Block", true, null); // NOI18N 302 _iconEditor.setPickList(jmri.jmrit.picker.PickListModel.blockPickModelInstance()); 303 ActionListener addIconAction = a -> editBlock(); 304 _iconEditor.complete(addIconAction, false, true, true); 305 _iconEditor.setSelection(getBlock()); 306 } 307 308 void editBlock() { 309 setBlock(_iconEditor.getTableSelection().getDisplayName()); 310 updateSize(); 311 _iconEditorFrame.dispose(); 312 _iconEditorFrame = null; 313 _iconEditor = null; 314 invalidate(); 315 } 316 317 @Override 318 public void dispose() { 319 if (getBlock() != null) { 320 getBlock().removePropertyChangeListener(this); 321 } 322 namedBlock = null; 323 if (re != null) { 324 jmri.InstanceManager.throttleManagerInstance().removeListener(re.getDccLocoAddress(), this); 325 re = null; 326 } 327 super.dispose(); 328 } 329 330 @Override 331 public void doMouseClicked(JmriMouseEvent e) { 332 if (e.getClickCount() == 2) { // double click? 333 if (!getEditor().isEditable() && isValueEditDisabled()) { 334 log.debug("Double click block value edit disabled"); 335 return; 336 } 337 editBlockValue(); 338 } 339 } 340 341 protected void editBlockValue() { 342 343 String reval = (String)JmriJOptionPane.showInputDialog(this, 344 Bundle.getMessage("EditCurrentBlockValue", namedBlock.getName()), 345 getBlock().getValue()); 346 347 setValue(reval); 348 updateSize(); 349 } 350 351 @Override 352 protected Object getValue() { 353 if (getBlock() == null) { 354 return null; 355 } 356 return getBlock().getValue(); 357 } 358 359 @Override 360 protected void setValue(Object val) { 361 getBlock().setValue(val); 362 } 363 364 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BlockContentsIcon.class); 365 366}