001package jmri.jmrit.display.controlPanelEditor; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004import java.awt.event.ActionEvent; 005import java.beans.PropertyChangeEvent; 006import java.beans.PropertyChangeListener; 007import java.util.HashMap; 008 009import javax.annotation.Nonnull; 010import javax.swing.AbstractAction; 011import javax.swing.JPopupMenu; 012 013import jmri.jmrit.catalog.NamedIcon; 014import jmri.jmrit.display.CoordinateEdit; 015import jmri.jmrit.display.Editor; 016import jmri.jmrit.display.Positionable; 017import jmri.jmrit.display.PositionableIcon; 018import jmri.jmrit.display.ToolTip; 019import jmri.jmrit.display.palette.ItemPalette; 020import jmri.jmrit.logix.Portal; 021import org.slf4j.Logger; 022import org.slf4j.LoggerFactory; 023 024/** 025 * @author Pete Cressman Copyright (C) 2011 026 */ 027public class PortalIcon extends PositionableIcon implements PropertyChangeListener { 028 029 public static final String HIDDEN = "hidden"; 030 public static final String VISIBLE = "block"; 031 public static final String PATH = "path"; 032 public static final String TO_ARROW = "toArrow"; 033 public static final String FROM_ARROW = "fromArrow"; 034 035// private NamedBeanHandle<Portal> _portalHdl; 036 private Portal _portal; 037 private String _status; 038 private boolean _regular = true; // true when TO_ARROW shows entry into ToBlock 039 private boolean _hide = false; // true when arrow should NOT show entry into ToBlock 040 041 public PortalIcon(Editor editor) { 042 super(editor); 043 _status = PortalIcon.HIDDEN; 044 makeIconMap(); 045 } 046 047 public PortalIcon(Editor editor, Portal portal) { 048 this(editor); 049 setPortal(portal); 050 } 051 052 public static HashMap<String, NamedIcon> getPaletteMap() { 053 HashMap<String, HashMap<String, NamedIcon>> families = ItemPalette.getFamilyMaps("Portal"); 054 if (families.keySet().isEmpty()) { 055 log.debug("Adding missing PortalIconMap"); 056 ItemPalette.loadMissingItemType("Portal"); 057 families = ItemPalette.getFamilyMaps("Portal"); 058 } 059 HashMap<String, NamedIcon> iconMap = families.get("Standard"); 060 if (iconMap == null) { 061 for (HashMap<String, NamedIcon> map : families.values()) { 062 iconMap = map; 063 break; 064 } 065 } 066 // return a copy, not ItemPalette's map! 067 return cloneMap(iconMap, null); 068 } 069 070 public void makeIconMap() { 071 _iconMap = ((ControlPanelEditor)_editor).getPortalIconMap(); 072 int deg = getDegrees(); 073 if (!_regular) { 074 NamedIcon a = _iconMap.get(TO_ARROW); 075 NamedIcon b = _iconMap.get(FROM_ARROW); 076 _iconMap.put(FROM_ARROW, a); 077 _iconMap.put(TO_ARROW, b); 078 } 079 setScale(getScale()); 080 rotate(deg); 081 setIcon(_iconMap.get(HIDDEN)); 082 } 083 084 /** 085 * PortalIcon family is managed by editor, ignoring per icon setting if any. 086 * @return the family name as set in editor. 087 */ 088 @Override 089 public String getFamily() { 090 return ((ControlPanelEditor)_editor).getPortalIconFamily(); 091 } 092 093 protected void setMap(HashMap<String, NamedIcon> map) { 094 _iconMap = map; 095 } 096 097 @Override 098 @Nonnull 099 public Positionable deepClone() { 100 PortalIcon pos = new PortalIcon(_editor, getPortal()); 101 return finishClone(pos); 102 } 103 104 protected Positionable finishClone(PortalIcon pos) { 105 pos._regular = _regular; 106 pos._hide = _hide; 107 pos._status = _status; 108 return super.finishClone(pos); 109 } 110 111 public void setIcon(String name, NamedIcon ic) { 112 if (log.isDebugEnabled()) { 113 log.debug("Icon {} put icon key= \"{}\" icon= {}", getPortal().getName(), name, ic); 114 } 115 NamedIcon icon = cloneIcon(ic, this); 116 icon.scale(getScale(), this); 117 icon.rotate(getDegrees(), this); 118 _iconMap.put(name, icon); 119 } 120 121 /** 122 * Set direction of portal icon, renamed in 4.21.5 123 * @param set true for regular, false for opposite (flipped in edit frame) 124 */ 125 public void setArrowOrientation(boolean set) { 126 if (log.isDebugEnabled()) { 127 log.debug("Icon {} setArrowOrientation regular={} from {}", getPortal().getName(), set, _regular); 128 } 129 _regular = set; 130 } 131 132 public void setHideArrows(boolean set) { 133 if (log.isDebugEnabled()) { 134 log.debug("Icon {} setHideArrows hide={} from {}", getPortal().getName(), set, _hide); 135 } 136 _hide = set; 137 } 138 139 public boolean getArrowSwitch() { 140 return _regular; 141 } 142 143 public boolean getArrowHide() { 144 return _hide; 145 } 146 147 public Portal getPortal() { 148 return _portal; 149 } 150 151 @Override 152 public jmri.NamedBean getNamedBean() { 153 return null; 154 } 155 156 @SuppressFBWarnings(value="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification="Portals always have userNames") 157 public void setPortal(Portal portal) { 158 if (portal == null) { 159 return; 160 } 161 if (_portal != null) { 162 _portal.removePropertyChangeListener(this); 163 } 164 _portal = portal; 165 _portal.addPropertyChangeListener(this); 166 setToolTip(new ToolTip(_portal.getDescription(), 0, 0, this)); 167 } 168 169 public void setStatus(String status) { 170 // if (log.isDebugEnabled()) log.debug("Icon "+getPortal().getName()+" setStatus("+status+") regular="+_regular+" icon= "+_iconMap.get(status)); 171 setIcon(_iconMap.get(status)); 172 _status = status; 173 updateSize(); 174 repaint(); 175 } 176 177 public String getStatus() { 178 return _status; 179 } 180 181 @Override 182 public void remove() { 183 ((ControlPanelEditor)_editor).getCircuitBuilder().deletePortalIcon(this); 184 super.remove(); 185 } 186 187 @Override 188 public void displayState(int state) { 189 switch (state) { 190 case 0x02: 191 if (_hide) { 192 setStatus(HIDDEN); 193 } else { 194 setStatus(TO_ARROW); 195 } 196 break; 197 case 0x04: 198 if (_hide) { 199 setStatus(HIDDEN); 200 } else { 201 setStatus(FROM_ARROW); 202 } 203 break; 204 case 0x10: 205 setStatus(VISIBLE); 206 break; 207 case 0x20: 208 setStatus(PATH); 209 break; 210 default: 211 setStatus(HIDDEN); 212 break; 213 } 214 } 215 216 @Override 217 public void propertyChange(PropertyChangeEvent e) { 218 Object source = e.getSource(); 219// if (log.isDebugEnabled()) log.debug("Icon "+getPortal().getName()+" PropertyChange= "+e.getPropertyName()+ 220// " oldValue= "+e.getOldValue().toString()+" newValue= "+e.getNewValue().toString()); 221 if (source instanceof Portal) { 222 String propertyName = e.getPropertyName(); 223 if ("Direction".equals(propertyName)) { 224 if (_hide) { 225 setStatus(HIDDEN); 226 return; 227 } 228 switch (((Integer) e.getNewValue())) { 229 case Portal.UNKNOWN: 230 setStatus(HIDDEN); 231 break; 232 case Portal.ENTER_TO_BLOCK: 233 setStatus(TO_ARROW); 234 break; 235 case Portal.ENTER_FROM_BLOCK: 236 setStatus(FROM_ARROW); 237 break; 238 default: 239 log.warn("Unhandled portal value: {}", e.getNewValue() ); 240 } 241 } else if ("NameChange".equals(propertyName)) { 242 setName((String) e.getNewValue()); 243 } else if ("portalDelete".equals(propertyName)) { 244 remove(); 245 } 246 } 247 } 248 249 @Override 250 @Nonnull 251 public String getTypeString() { 252 return Bundle.getMessage("PositionableType_PortalIcon"); 253 } 254 255 @Override 256 @Nonnull 257 public String getNameString() { 258 Portal p = getPortal(); 259 if (p == null) return "No Portal Defined"; 260 return p.getDescription(); 261 } 262 263 /** 264 * Disable popup items that apply to whole selection Group. 265 * @see jmri.jmrit.display.PositionableLabel#doViemMenu() 266 */ 267 @Override 268 public boolean doViemMenu() { 269 return false; 270 } 271 272 private void setRemoveMenu(JPopupMenu popup) { 273 popup.add(new AbstractAction(Bundle.getMessage("Remove")) { 274 @Override 275 public void actionPerformed(ActionEvent e) { 276 remove(); 277 } 278 }); 279 } 280 281 /** 282 * Use this call to set actions that will not affect whole selection Group. 283 * @see jmri.jmrit.display.PositionableLabel#setEditItemMenu(javax.swing.JPopupMenu) 284 */ 285 @Override 286 public boolean showPopUp(JPopupMenu popup) { 287 popup.add(getNameString()); 288 _editor.setPositionableMenu(this, popup); 289 if (isPositionable()) { 290 _editor.setShowCoordinatesMenu(this, popup); 291 } 292 _editor.setDisplayLevelMenu(this, popup); 293 popup.addSeparator(); 294 popup.add(CoordinateEdit.getScaleEditAction(this)); 295 popup.add(CoordinateEdit.getRotateEditAction(this)); 296 popup.addSeparator(); 297 setRemoveMenu(popup); 298 return true; 299 } 300 301 @Override 302 public void setLocation(int x, int y ) { 303 ControlPanelEditor cpe = (ControlPanelEditor)_editor; 304 if (cpe.getCircuitBuilder().portalIconMove(this, x, y)) { 305 super.setLocation(x, y); 306 } 307 } 308 309 @Override 310 public boolean setRotateMenu(@Nonnull JPopupMenu popup) { 311 return false; 312 } 313 314 @Override 315 public boolean setScaleMenu(@Nonnull JPopupMenu popup) { 316 return false; 317 } 318 319 @Override 320 public boolean setEditItemMenu(@Nonnull JPopupMenu popup) { 321 return false; 322 } 323 324 private static final Logger log = LoggerFactory.getLogger(PortalIcon.class); 325 326}