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 if (re != null) { 165 popup.add(new AbstractAction("Open Throttle") { 166 @Override 167 public void actionPerformed(ActionEvent e) { 168 ThrottleFrame tf = InstanceManager.getDefault(ThrottleFrameManager.class).createThrottleFrame(); 169 tf.toFront(); 170 tf.getAddressPanel().setRosterEntry(re); 171 } 172 }); 173 174 final jmri.jmrit.dispatcher.DispatcherFrame df = jmri.InstanceManager.getNullableDefault(jmri.jmrit.dispatcher.DispatcherFrame.class); 175 if (df != null) { 176 final jmri.jmrit.dispatcher.ActiveTrain at = df.getActiveTrainForRoster(re); 177 if (at != null) { 178 popup.add(new AbstractAction(Bundle.getMessage("MenuTerminateTrain")) { 179 @Override 180 public void actionPerformed(ActionEvent e) { 181 df.terminateActiveTrain(at,true,false); 182 } 183 }); 184 popup.add(new AbstractAction(Bundle.getMessage("MenuAllocateExtra")) { 185 @Override 186 public void actionPerformed(ActionEvent e) { 187 //Just brings up the standard allocate extra frame, this could be expanded in the future 188 //As a point and click operation. 189 df.allocateExtraSection(e, at); 190 } 191 }); 192 if (at.getStatus() == jmri.jmrit.dispatcher.ActiveTrain.DONE) { 193 popup.add(new AbstractAction("Restart") { 194 @Override 195 public void actionPerformed(ActionEvent e) { 196 at.allocateAFresh(); 197 } 198 }); 199 } 200 } else { 201 popup.add(new AbstractAction(Bundle.getMessage("MenuNewTrain")) { 202 @Override 203 public void actionPerformed(ActionEvent e) { 204 if (!df.getNewTrainActive()) { 205 df.getActiveTrainFrame().initiateTrain(e, re, getBlock()); 206 df.setNewTrainActive(true); 207 } else { 208 df.getActiveTrainFrame().showActivateFrame(re); 209 } 210 } 211 212 }); 213 } 214 } 215 return true; 216 } 217 return false; 218 } 219 220 /** 221 * Text edits cannot be done to Block text - override. 222 */ 223 @Override 224 public boolean setTextEditMenu(JPopupMenu popup) { 225 popup.add(new AbstractAction(Bundle.getMessage("EditBlockValue")) { 226 @Override 227 public void actionPerformed(ActionEvent e) { 228 editBlockValue(); 229 } 230 }); 231 return true; 232 } 233 234 /** 235 * Drive the current state of the display from the state of the Block Value. 236 */ 237 @Override 238 public void displayState() { 239 log.debug("displayState"); 240 if (namedBlock == null) { // use default if not connected yet 241 setIcon(defaultIcon); 242 updateSize(); 243 return; 244 } 245 if (re != null) { 246 jmri.InstanceManager.throttleManagerInstance().removeListener(re.getDccLocoAddress(), this); 247 re = null; 248 } 249 Object key = getBlock().getValue(); 250 displayState(key); 251 } 252 253 @Override 254 public boolean setEditIconMenu(JPopupMenu popup) { 255 String txt = java.text.MessageFormat.format(Bundle.getMessage("EditItem"), Bundle.getMessage("BeanNameBlock")); 256 popup.add(new AbstractAction(txt) { 257 @Override 258 public void actionPerformed(ActionEvent e) { 259 edit(); 260 } 261 }); 262 return true; 263 } 264 265 @Override 266 protected void edit() { 267 makeIconEditorFrame(this, "Block", true, null); // NOI18N 268 _iconEditor.setPickList(jmri.jmrit.picker.PickListModel.blockPickModelInstance()); 269 ActionListener addIconAction = a -> editBlock(); 270 _iconEditor.complete(addIconAction, false, true, true); 271 _iconEditor.setSelection(getBlock()); 272 } 273 274 void editBlock() { 275 setBlock(_iconEditor.getTableSelection().getDisplayName()); 276 updateSize(); 277 _iconEditorFrame.dispose(); 278 _iconEditorFrame = null; 279 _iconEditor = null; 280 invalidate(); 281 } 282 283 @Override 284 public void dispose() { 285 if (getBlock() != null) { 286 getBlock().removePropertyChangeListener(this); 287 } 288 namedBlock = null; 289 if (re != null) { 290 jmri.InstanceManager.throttleManagerInstance().removeListener(re.getDccLocoAddress(), this); 291 re = null; 292 } 293 super.dispose(); 294 } 295 296 @Override 297 public void doMouseClicked(JmriMouseEvent e) { 298 if (e.getClickCount() == 2) { // double click? 299 if (!getEditor().isEditable() && isValueEditDisabled()) { 300 log.debug("Double click block value edit disabled"); 301 return; 302 } 303 editBlockValue(); 304 } 305 } 306 307 protected void editBlockValue() { 308 309 String reval = (String)JmriJOptionPane.showInputDialog(this, 310 Bundle.getMessage("EditCurrentBlockValue", namedBlock.getName()), 311 getBlock().getValue()); 312 313 setValue(reval); 314 updateSize(); 315 } 316 317 @Override 318 protected Object getValue() { 319 if (getBlock() == null) { 320 return null; 321 } 322 return getBlock().getValue(); 323 } 324 325 @Override 326 protected void setValue(Object val) { 327 getBlock().setValue(val); 328 } 329 330 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BlockContentsIcon.class); 331 332}