001package jmri.jmrit.display.configurexml;
002
003import java.util.HashMap;
004import java.util.List;
005
006import jmri.SignalHead;
007import jmri.configurexml.JmriConfigureXmlException;
008import jmri.jmrit.catalog.NamedIcon;
009import jmri.jmrit.display.*;
010
011import org.jdom2.Attribute;
012import org.jdom2.Element;
013import org.slf4j.Logger;
014import org.slf4j.LoggerFactory;
015
016/**
017 * Handle configuration for display.SignalHeadIcon objects.
018 *
019 * @author Bob Jacobsen Copyright: Copyright (c) 2002
020 */
021public class SignalHeadIconXml extends PositionableLabelXml {
022
023    static final HashMap<String, String> _nameMap = new HashMap<>();
024
025    public SignalHeadIconXml() {
026        // map previous store names to property key names
027        _nameMap.put("red", "SignalHeadStateRed");
028        _nameMap.put("yellow", "SignalHeadStateYellow");
029        _nameMap.put("green", "SignalHeadStateGreen");
030        _nameMap.put("lunar", "SignalHeadStateLunar");
031        _nameMap.put("held", "SignalHeadStateHeld");
032        _nameMap.put("dark", "SignalHeadStateDark");
033        _nameMap.put("flashred", "SignalHeadStateFlashingRed");
034        _nameMap.put("flashyellow", "SignalHeadStateFlashingYellow");
035        _nameMap.put("flashgreen", "SignalHeadStateFlashingGreen");
036        _nameMap.put("flashlunar", "SignalHeadStateFlashingLunar");
037    }
038
039    /**
040     * Default implementation for storing the contents of a SignalHeadIcon
041     *
042     * @param o Object to store, of type SignalHeadIcon
043     * @return Element containing the complete info
044     */
045    @Override
046    public Element store(Object o) {
047
048        SignalHeadIcon p = (SignalHeadIcon) o;
049        if (!p.isActive()) {
050            return null;  // if flagged as inactive, don't store
051        }
052        Element element = new Element("signalheadicon");
053
054        element.setAttribute("signalhead", "" + p.getNamedSignalHead().getName());
055        storeCommonAttributes(p, element);
056        element.setAttribute("clickmode", "" + p.getClickMode());
057        element.setAttribute("litmode", "" + p.getLitMode());
058
059        Element elem = new Element("icons");
060        NamedIcon icon = p.getIcon("SignalHeadStateHeld");
061        if (icon != null) {
062            elem.addContent(storeIcon("held", icon));
063        }
064        icon = p.getIcon("SignalHeadStateDark");
065        if (icon != null) {
066            elem.addContent(storeIcon("dark", icon));
067        }
068        icon = p.getIcon("SignalHeadStateRed");
069        if (icon != null) {
070            elem.addContent(storeIcon("red", icon));
071        }
072        icon = p.getIcon("SignalHeadStateYellow");
073        if (icon != null) {
074            elem.addContent(storeIcon("yellow", icon));
075        }
076        icon = p.getIcon("SignalHeadStateGreen");
077        if (icon != null) {
078            elem.addContent(storeIcon("green", icon));
079        }
080        icon = p.getIcon("SignalHeadStateLunar");
081        if (icon != null) {
082            elem.addContent(storeIcon("lunar", icon));
083        }
084        icon = p.getIcon("SignalHeadStateFlashingRed");
085        if (icon != null) {
086            elem.addContent(storeIcon("flashred", icon));
087        }
088        icon = p.getIcon("SignalHeadStateFlashingYellow");
089        if (icon != null) {
090            elem.addContent(storeIcon("flashyellow", icon));
091        }
092        icon = p.getIcon("SignalHeadStateFlashingGreen");
093        if (icon != null) {
094            elem.addContent(storeIcon("flashgreen", icon));
095        }
096        icon = p.getIcon("SignalHeadStateFlashingLunar");
097        if (icon != null) {
098            elem.addContent(storeIcon("flashlunar", icon));
099        }
100        element.addContent(elem);
101        elem = new Element("iconmaps");
102        String family = p.getFamily();
103        if (family != null) {
104            elem.setAttribute("family", family);
105        }
106        element.addContent(elem);
107
108        storeLogixNG_Data(p, element);
109
110        element.setAttribute("class", "jmri.jmrit.display.configurexml.SignalHeadIconXml");
111        return element;
112    }
113
114    /**
115     * Create a PositionableLabel, then add to a target JLayeredPane
116     *
117     * @param element Top level Element to unpack.
118     * @param o       an Editor as an Object
119     * @throws JmriConfigureXmlException when a error prevents creating the objects as as
120     *                   required by the input XML
121     */
122    @Override
123    public void load(Element element, Object o) throws JmriConfigureXmlException {
124        // create the objects
125        Editor ed = (Editor) o;
126        SignalHeadIcon l = new SignalHeadIcon(ed);
127        String name;
128
129        Attribute attr = element.getAttribute("signalhead");
130        if (attr == null) {
131            log.error("incorrect information for signal head; must use signalhead name");
132            ed.loadFailed();
133            return;
134        } else {
135            name = attr.getValue();
136        }
137
138        SignalHead sh = jmri.InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(name);
139
140        if (sh != null) {
141            l.setSignalHead(name);
142        } else {
143            log.error("SignalHead named '{}' not found.", attr.getValue());
144            //    ed.loadFailed();
145            return;
146        }
147        int rotation = 0;
148        try {
149            attr = element.getAttribute("rotate");
150            rotation = attr.getIntValue();
151        } catch (org.jdom2.DataConversionException e) {
152        } catch (NullPointerException e) {  // considered normal if the attributes are not present
153        }
154
155        List<Element> aspects = element.getChildren();
156        if (aspects.size() > 0) {
157            Element icons = element.getChild("icons");
158            Element elem = element;
159            if (icons != null) {
160                aspects = icons.getChildren();
161                elem = icons;
162            }
163            for (Element value : aspects) {
164                String aspect = value.getName();
165                NamedIcon icon = loadIcon(l, aspect, elem, "SignalHead \"" + name + "\": icon \"" + aspect + "\" ", ed);
166                if (icon != null) {
167                    l.setIcon(_nameMap.get(aspect), icon);
168                } else {
169                    log.info("SignalHead \"{}\": icon \"{}\" removed", name, aspect);
170                }
171            }
172            log.debug("{} icons loaded for {}", aspects.size(), l.getNameString());
173        } else {
174            // old style as attributes - somewhere around pre 2.5.4
175            NamedIcon icon = loadSignalIcon("red", rotation, l, element, name, ed);
176            if (icon != null) {
177                l.setIcon("SignalHeadStateRed", icon);
178            }
179            icon = loadSignalIcon("yellow", rotation, l, element, name, ed);
180            if (icon != null) {
181                l.setIcon("SignalHeadStateYellow", icon);
182            }
183            icon = loadSignalIcon("green", rotation, l, element, name, ed);
184            if (icon != null) {
185                l.setIcon("SignalHeadStateGreen", icon);
186            }
187            icon = loadSignalIcon("lunar", rotation, l, element, name, ed);
188            if (icon != null) {
189                l.setIcon("SignalHeadStateLunar", icon);
190            }
191            icon = loadSignalIcon("held", rotation, l, element, name, ed);
192            if (icon != null) {
193                l.setIcon("SignalHeadStateHeld", icon);
194            }
195            icon = loadSignalIcon("dark", rotation, l, element, name, ed);
196            if (icon != null) {
197                l.setIcon("SignalHeadStateDark", icon);
198            }
199            icon = loadSignalIcon("flashred", rotation, l, element, name, ed);
200            if (icon != null) {
201                l.setIcon("SignalHeadStateFlashingRed", icon);
202            }
203            icon = loadSignalIcon("flashyellow", rotation, l, element, name, ed);
204            if (icon != null) {
205                l.setIcon("SignalHeadStateFlashingYellow", icon);
206            }
207            icon = loadSignalIcon("flashgreen", rotation, l, element, name, ed);
208            if (icon != null) {
209                l.setIcon("SignalHeadStateFlashingGreen", icon);
210            }
211            icon = loadSignalIcon("flashlunar", rotation, l, element, name, ed);
212            if (icon != null) {
213                l.setIcon("SignalHeadStateFlashingLunar", icon);
214            }
215        }
216        Element elem = element.getChild("iconmaps");
217        if (elem != null) {
218            attr = elem.getAttribute("family");
219            if (attr != null) {
220                l.setFamily(attr.getValue());
221            }
222        }
223        try {
224            attr = element.getAttribute("clickmode");
225            if (attr != null) {
226                l.setClickMode(attr.getIntValue());
227            }
228        } catch (org.jdom2.DataConversionException e) {
229            log.error("Failed on clickmode attribute: ", e);
230        }
231
232        try {
233            attr = element.getAttribute("litmode");
234            if (attr != null) {
235                l.setLitMode(attr.getBooleanValue());
236            }
237        } catch (org.jdom2.DataConversionException e) {
238            log.error("Failed on litmode attribute: ", e);
239        }
240
241        try {
242            ed.putItem(l);
243        } catch (Positionable.DuplicateIdException e) {
244            throw new JmriConfigureXmlException("Positionable id is not unique", e);
245        }
246
247        loadLogixNG_Data(l, element);
248
249        // load individual item's option settings after editor has set its global settings
250        loadCommonAttributes(l, Editor.SIGNALS, element);
251    }
252
253    private NamedIcon loadSignalIcon(String aspect, int rotation, SignalHeadIcon l,
254            Element element, String name, Editor ed) {
255        String msg = "SignalHead \"" + name + "\": icon \"" + aspect + "\" ";
256        NamedIcon icon = loadIcon(l, aspect, element, msg, ed);
257        if (icon == null) {
258            if (element.getAttribute(aspect) != null) {
259                String iconName = element.getAttribute(aspect).getValue();
260                icon = NamedIcon.getIconByName(iconName);
261                if (icon == null) {
262                    icon = ed.loadFailed(msg, iconName);
263                    if (icon == null) {
264                        log.info("{} removed for url= {}", msg, iconName);
265                    }
266                }
267                if (icon != null) {
268                    icon.setRotation(rotation, l);
269                }
270            } else {
271                log.info("did not load file aspect {} for SignalHead {}", aspect, name);
272            }
273        }
274        if (icon == null) {
275            log.info("SignalHead Icon \"{}\": icon \"{}\" removed", name, aspect);
276        }
277        return icon;
278    }
279
280    private final static Logger log = LoggerFactory.getLogger(SignalHeadIconXml.class);
281
282}