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