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 static public 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 @SuppressFBWarnings(value="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification="Portals always have userNames") 152 public void setPortal(Portal portal) { 153 if (portal == null) { 154 return; 155 } 156 if (_portal != null) { 157 _portal.removePropertyChangeListener(this); 158 } 159 _portal = portal; 160 _portal.addPropertyChangeListener(this); 161 setToolTip(new ToolTip(_portal.getDescription(), 0, 0, this)); 162 } 163 164 public void setStatus(String status) { 165 // if (log.isDebugEnabled()) log.debug("Icon "+getPortal().getName()+" setStatus("+status+") regular="+_regular+" icon= "+_iconMap.get(status)); 166 setIcon(_iconMap.get(status)); 167 _status = status; 168 updateSize(); 169 repaint(); 170 } 171 172 public String getStatus() { 173 return _status; 174 } 175 176 @Override 177 public void remove() { 178 ((ControlPanelEditor)_editor).getCircuitBuilder().deletePortalIcon(this); 179 super.remove(); 180 } 181 182 @Override 183 public void displayState(int state) { 184 switch (state) { 185 case 0x02: 186 if (_hide) { 187 setStatus(HIDDEN); 188 } else { 189 setStatus(TO_ARROW); 190 } 191 break; 192 case 0x04: 193 if (_hide) { 194 setStatus(HIDDEN); 195 } else { 196 setStatus(FROM_ARROW); 197 } 198 break; 199 case 0x10: 200 setStatus(VISIBLE); 201 break; 202 case 0x20: 203 setStatus(PATH); 204 break; 205 default: 206 setStatus(HIDDEN); 207 break; 208 } 209 } 210 211 @Override 212 public void propertyChange(PropertyChangeEvent e) { 213 Object source = e.getSource(); 214// if (log.isDebugEnabled()) log.debug("Icon "+getPortal().getName()+" PropertyChange= "+e.getPropertyName()+ 215// " oldValue= "+e.getOldValue().toString()+" newValue= "+e.getNewValue().toString()); 216 if (source instanceof Portal) { 217 String propertyName = e.getPropertyName(); 218 if ("Direction".equals(propertyName)) { 219 if (_hide) { 220 setStatus(HIDDEN); 221 return; 222 } 223 switch (((Integer) e.getNewValue())) { 224 case Portal.UNKNOWN: 225 setStatus(HIDDEN); 226 break; 227 case Portal.ENTER_TO_BLOCK: 228 setStatus(TO_ARROW); 229 break; 230 case Portal.ENTER_FROM_BLOCK: 231 setStatus(FROM_ARROW); 232 break; 233 default: 234 log.warn("Unhandled portal value: {}", e.getNewValue() ); 235 } 236 } else if ("NameChange".equals(propertyName)) { 237 setName((String) e.getNewValue()); 238 } else if ("portalDelete".equals(propertyName)) { 239 remove(); 240 } 241 } 242 } 243 244 @Override 245 @Nonnull 246 public String getTypeString() { 247 return Bundle.getMessage("PositionableType_PortalIcon"); 248 } 249 250 @Override 251 @Nonnull 252 public String getNameString() { 253 Portal p = getPortal(); 254 if (p == null) return "No Portal Defined"; 255 return p.getDescription(); 256 } 257 258 /** 259 * Disable popup items that apply to whole selection Group. 260 * @see jmri.jmrit.display.PositionableLabel#doViemMenu() 261 */ 262 @Override 263 public boolean doViemMenu() { 264 return false; 265 } 266 267 private void setRemoveMenu(JPopupMenu popup) { 268 popup.add(new AbstractAction(Bundle.getMessage("Remove")) { 269 @Override 270 public void actionPerformed(ActionEvent e) { 271 remove(); 272 } 273 }); 274 } 275 276 /** 277 * Use this call to set actions that will not affect whole selection Group. 278 * @see jmri.jmrit.display.PositionableLabel#setEditItemMenu(javax.swing.JPopupMenu) 279 */ 280 @Override 281 public boolean showPopUp(JPopupMenu popup) { 282 popup.add(getNameString()); 283 _editor.setPositionableMenu(this, popup); 284 if (isPositionable()) { 285 _editor.setShowCoordinatesMenu(this, popup); 286 } 287 _editor.setDisplayLevelMenu(this, popup); 288 popup.addSeparator(); 289 popup.add(CoordinateEdit.getScaleEditAction(this)); 290 popup.add(CoordinateEdit.getRotateEditAction(this)); 291 popup.addSeparator(); 292 setRemoveMenu(popup); 293 return true; 294 } 295 296 @Override 297 public void setLocation(int x, int y ) { 298 ControlPanelEditor cpe = (ControlPanelEditor)_editor; 299 if (cpe.getCircuitBuilder().portalIconMove(this, x, y)) { 300 super.setLocation(x, y); 301 } 302 } 303 304 @Override 305 public boolean setRotateMenu(@Nonnull JPopupMenu popup) { 306 return false; 307 } 308 309 @Override 310 public boolean setScaleMenu(@Nonnull JPopupMenu popup) { 311 return false; 312 } 313 314 @Override 315 public boolean setEditItemMenu(@Nonnull JPopupMenu popup) { 316 return false; 317 } 318 319 private final static Logger log = LoggerFactory.getLogger(PortalIcon.class); 320 321}