001package jmri.jmrit.display.configurexml;
002
003import java.awt.Color;
004import java.util.HashMap;
005import java.util.List;
006
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.SensorIcon objects.
018 *
019 * @author Bob Jacobsen Copyright: Copyright (c) 2002
020 */
021public class SensorIconXml extends PositionableLabelXml {
022
023    static final HashMap<String, String> _nameMap = new HashMap<>();
024
025    public SensorIconXml() {
026        // map previous store names to property key names
027        _nameMap.put("active", "SensorStateActive");
028        _nameMap.put("inactive", "SensorStateInactive");
029        _nameMap.put("unknown", "BeanStateUnknown");
030        _nameMap.put("inconsistent", "BeanStateInconsistent");
031    }
032
033    /**
034     * Default implementation for storing the contents of a SensorIcon.
035     *
036     * @param o Object to store, of type SensorIcon
037     * @return Element containing the complete info
038     */
039    @Override
040    public Element store(Object o) {
041        SensorIcon p = (SensorIcon) o;
042        if (!p.isActive()) {
043            return null;  // if flagged as inactive, don't store
044        }
045        Element element = new Element("sensoricon");
046        element.setAttribute("sensor", p.getNamedSensor().getName());
047        storeCommonAttributes(p, element);
048        element.setAttribute("momentary", p.getMomentary() ? "true" : "false");
049        element.setAttribute("icon", p.isIcon() ? "yes" : "no");
050
051        storeIconInfo(p, element);
052        storeTextInfo(p, element);
053
054        storeLogixNG_Data(p, element);
055
056        element.setAttribute("class", "jmri.jmrit.display.configurexml.SensorIconXml");
057        return element;
058    }
059
060    protected void storeTextInfo(SensorIcon p, Element element) {
061        if (p.getText() == null) {
062            String s = p.getOriginalText();
063            if (s != null && s.length() > 0) {
064                element.setAttribute("text", s);
065            } else if (p.isText()) {
066                element.setAttribute("text", "");
067            } else {
068                return;
069            }
070        } else {
071            element.setAttribute("text", p.getText());
072        }
073        // get iconic overlay text info
074        super.storeTextInfo(p, element);
075        // get state textual info
076        Element textElement = new Element("activeText");
077        if (p.getActiveText() != null) {
078            textElement.setAttribute("text", p.getActiveText());
079        }
080
081        // always write text color
082        textElement.setAttribute("red", "" + p.getTextActive().getRed());
083        textElement.setAttribute("green", "" + p.getTextActive().getGreen());
084        textElement.setAttribute("blue", "" + p.getTextActive().getBlue());
085
086        if (p.getBackgroundActive() != null) {
087            textElement.setAttribute("redBack", "" + p.getBackgroundActive().getRed());
088            textElement.setAttribute("greenBack", "" + p.getBackgroundActive().getGreen());
089            textElement.setAttribute("blueBack", "" + p.getBackgroundActive().getBlue());
090        }
091        element.addContent(textElement);
092        textElement = new Element("inactiveText");
093        if (p.getInactiveText() != null) {
094            textElement.setAttribute("text", p.getInactiveText());
095        }
096
097        // always write text color
098        textElement.setAttribute("red", "" + p.getTextInActive().getRed());
099        textElement.setAttribute("green", "" + p.getTextInActive().getGreen());
100        textElement.setAttribute("blue", "" + p.getTextInActive().getBlue());
101
102        if (p.getBackgroundInActive() != null) {
103            textElement.setAttribute("redBack", "" + p.getBackgroundInActive().getRed());
104            textElement.setAttribute("greenBack", "" + p.getBackgroundInActive().getGreen());
105            textElement.setAttribute("blueBack", "" + p.getBackgroundInActive().getBlue());
106        }
107        element.addContent(textElement);
108
109        textElement = new Element("unknownText");
110
111        if (p.getUnknownText() != null) {
112            textElement.setAttribute("text", p.getUnknownText());
113        }
114
115        // always write text color
116        textElement.setAttribute("red", "" + p.getTextUnknown().getRed());
117        textElement.setAttribute("green", "" + p.getTextUnknown().getGreen());
118        textElement.setAttribute("blue", "" + p.getTextUnknown().getBlue());
119
120        if (p.getBackgroundUnknown() != null) {
121            textElement.setAttribute("redBack", "" + p.getBackgroundUnknown().getRed());
122            textElement.setAttribute("greenBack", "" + p.getBackgroundUnknown().getGreen());
123            textElement.setAttribute("blueBack", "" + p.getBackgroundUnknown().getBlue());
124        }
125        element.addContent(textElement);
126
127        textElement = new Element("inconsistentText");
128        if (p.getInconsistentText() != null) {
129            textElement.setAttribute("text", p.getInconsistentText());
130        }
131
132        // always write text color
133        textElement.setAttribute("red", "" + p.getTextInconsistent().getRed());
134        textElement.setAttribute("green", "" + p.getTextInconsistent().getGreen());
135        textElement.setAttribute("blue", "" + p.getTextInconsistent().getBlue());
136
137        if (p.getBackgroundInconsistent() != null) {
138            textElement.setAttribute("redBack", "" + p.getBackgroundInconsistent().getRed());
139            textElement.setAttribute("greenBack", "" + p.getBackgroundInconsistent().getGreen());
140            textElement.setAttribute("blueBack", "" + p.getBackgroundInconsistent().getBlue());
141        }
142        element.addContent(textElement);
143    }
144
145    protected void storeIconInfo(SensorIcon p, Element element) {
146        element.addContent(storeIcon("active", p.getIcon("SensorStateActive")));
147        element.addContent(storeIcon("inactive", p.getIcon("SensorStateInactive")));
148        element.addContent(storeIcon("unknown", p.getIcon("BeanStateUnknown")));
149        element.addContent(storeIcon("inconsistent", p.getIcon("BeanStateInconsistent")));
150        Element elem = new Element("iconmaps");
151        String family = p.getFamily();
152        if (family != null) {
153            elem.setAttribute("family", family);
154        }
155        element.addContent(elem);
156    }
157
158    boolean _icon;
159
160    /**
161     * Create a PositionableLabel, then add to a target JLayeredPane.
162     *
163     * @param element Top level Element to unpack.
164     * @param o       an Editor as an Object
165     * @throws JmriConfigureXmlException when a error prevents creating the objects as as
166     *                   required by the input XML
167     */
168    @Override
169    public void load(Element element, Object o) throws JmriConfigureXmlException {
170        Editor ed = (Editor) o;
171        SensorIcon l;
172        String name;
173        Attribute attr = element.getAttribute("sensor");
174        if (attr == null) {
175            log.error("incorrect information for sensor; must use sensor name");
176            ed.loadFailed();
177            return;
178        } else {
179            name = attr.getValue();
180        }
181        _icon = true;
182        if (element.getAttribute("icon") != null) {
183            String yesno = element.getAttribute("icon").getValue();
184            if ((yesno != null) && (!yesno.equals(""))) {
185                if (yesno.equals("yes")) {
186                    _icon = true;
187                } else if (yesno.equals("no")) {
188                    _icon = false;
189                }
190            }
191        }
192
193        if (_icon) {
194            l = new SensorIcon(new NamedIcon("resources/icons/smallschematics/tracksegments/circuit-error.gif",
195                    "resources/icons/smallschematics/tracksegments/circuit-error.gif"),
196                    ed);
197        } else {
198            l = new SensorIcon("  ", ed);
199        }
200        int rotation = 0;
201        try {
202            rotation = element.getAttribute("rotate").getIntValue();
203        } catch (org.jdom2.DataConversionException e) {
204        } catch (NullPointerException e) {  // considered normal if the attributes are not present
205        }
206
207        if (loadSensorIcon("active", rotation, l, element, name, ed) == null) {
208            return;
209        }
210        if (loadSensorIcon("inactive", rotation, l, element, name, ed) == null) {
211            return;
212        }
213        if (loadSensorIcon("unknown", rotation, l, element, name, ed) == null) {
214            return;
215        }
216        if (loadSensorIcon("inconsistent", rotation, l, element, name, ed) == null) {
217            return;
218        }
219        Element elem = element.getChild("iconmaps");
220        if (elem != null) {
221            attr = elem.getAttribute("family");
222            if (attr != null) {
223                l.setFamily(attr.getValue());
224            }
225        }
226
227        Attribute a = element.getAttribute("momentary");
228        if ((a != null) && a.getValue().equals("true")) {
229            l.setMomentary(true);
230        } else {
231            l.setMomentary(false);
232        }
233
234        loadTextInfo(l, element);
235        l.setSensor(name);
236
237        try {
238            ed.putItem(l);
239        } catch (Positionable.DuplicateIdException e) {
240            throw new JmriConfigureXmlException("Positionable id is not unique", e);
241        }
242
243        loadLogixNG_Data(l, element);
244
245        // load individual item's option settings after editor has set its global settings
246        loadCommonAttributes(l, Editor.SENSORS, element);
247        if (l.isIcon() && l.getText()!=null) {
248            l.setOpaque(false);            
249        }
250    }
251
252    private NamedIcon loadSensorIcon(String state, int rotation, SensorIcon l,
253            Element element, String name, Editor ed) {
254        String msg = "SensorIcon \"" + name + "\": icon \"" + state + "\" ";
255        // loadIcon gets icon as an element
256        NamedIcon icon = loadIcon(l, state, element, msg, ed);
257        if (icon == null && _icon) {
258            // old config files may define icons as attributes
259            String iconName;
260            if (element.getAttribute(state) != null
261                    && !(iconName = element.getAttribute(state).getValue()).equals("")) {
262
263                icon = NamedIcon.getIconByName(iconName);
264                if (icon == null) {
265                    icon = ed.loadFailed(msg, iconName);
266                    if (icon == null) {
267                        log.info("{} removed for url= {}", msg, iconName);
268                    }
269                } else {
270                    icon.setRotation(rotation, l);
271                }
272            } else {
273                log.warn("did not locate {} icon file for {}", state, name);
274            }
275        }
276        if (icon == null) {
277            log.info("{} removed", msg);
278        } else {
279            l.setIcon(_nameMap.get(state), icon);
280        }
281        return icon;
282    }
283
284    void loadTextInfo(SensorIcon l, Element element) {
285        super.loadTextInfo(l, element);
286
287        loadSensorTextState("Active", l, element);
288        loadSensorTextState("InActive", l, element);
289        loadSensorTextState("Unknown", l, element);
290        loadSensorTextState("Inconsistent", l, element);
291        if (element.getAttribute("text") != null) {
292            l.setOriginalText(element.getAttribute("text").getValue());
293            l.setText(element.getAttribute("text").getValue());
294        }
295    }
296
297    private void loadSensorTextState(String state, SensorIcon l, Element element) {
298        String name = null;
299        Color clrText = null;
300        Color clrBackground = null;
301        List<Element> textList = element.getChildren(state.toLowerCase() + "Text");
302        if (log.isDebugEnabled()) {
303            log.debug("Found {} {}Text objects", textList.size(), state);
304        }
305        if (textList.size() > 0) {
306            Element elem = textList.get(0);
307            try {
308                name = elem.getAttribute("text").getValue();
309            } catch (NullPointerException e) {  // considered normal if the attributes are not present
310            }
311            try {
312                int red = elem.getAttribute("red").getIntValue();
313                int blue = elem.getAttribute("blue").getIntValue();
314                int green = elem.getAttribute("green").getIntValue();
315                clrText = new Color(red, green, blue);
316            } catch (org.jdom2.DataConversionException e) {
317                log.warn("Could not parse color attributes!");
318            } catch (NullPointerException e) {  // considered normal if the attributes are not present
319            }
320            try {
321                int red = elem.getAttribute("redBack").getIntValue();
322                int blue = elem.getAttribute("blueBack").getIntValue();
323                int green = elem.getAttribute("greenBack").getIntValue();
324                clrBackground = new Color(red, green, blue);
325            } catch (org.jdom2.DataConversionException e) {
326                log.warn("Could not parse color attributes!");
327            } catch (NullPointerException e) {  // considered normal if the attributes are not present
328            }
329
330        } else {
331            if (element.getAttribute(state.toLowerCase()) != null) {
332                name = element.getAttribute(state.toLowerCase()).getValue();
333            }
334            try {
335                int red = element.getAttribute("red" + state).getIntValue();
336                int blue = element.getAttribute("blue" + state).getIntValue();
337                int green = element.getAttribute("green" + state).getIntValue();
338                clrText = new Color(red, green, blue);
339            } catch (org.jdom2.DataConversionException e) {
340                log.warn("Could not parse color attributes!");
341            } catch (NullPointerException e) {  // considered normal if the attributes are not present
342            }
343            try {
344                int red = element.getAttribute("red" + state + "Back").getIntValue();
345                int blue = element.getAttribute("blue" + state + "Back").getIntValue();
346                int green = element.getAttribute("green" + state + "Back").getIntValue();
347                clrBackground = new Color(red, green, blue);
348            } catch (org.jdom2.DataConversionException e) {
349                log.warn("Could not parse color attributes!");
350            } catch (NullPointerException e) {  // considered normal if the attributes are not present
351            }
352        }
353        if (state.equals("Active")) {
354            if (name != null) {
355                l.setActiveText(name);
356            }
357            if (clrText != null) {
358                l.setTextActive(clrText);
359            }
360            if (clrBackground != null) {
361                l.setBackgroundActive(clrBackground);
362            }
363        } else if (state.equals("InActive")) {
364            if (name != null) {
365                l.setInactiveText(name);
366            }
367            if (clrText != null) {
368                l.setTextInActive(clrText);
369            }
370            if (clrBackground != null) {
371                l.setBackgroundInActive(clrBackground);
372            }
373        } else if (state.equals("Unknown")) {
374            if (name != null) {
375                l.setUnknownText(name);
376            }
377            if (clrText != null) {
378                l.setTextUnknown(clrText);
379            }
380            if (clrBackground != null) {
381                l.setBackgroundUnknown(clrBackground);
382            }
383        } else if (state.equals("Inconsistent")) {
384            if (name != null) {
385                l.setInconsistentText(name);
386            }
387            if (clrText != null) {
388                l.setTextInconsistent(clrText);
389            }
390            if (clrBackground != null) {
391                l.setBackgroundInconsistent(clrBackground);
392            }
393        }
394    }
395
396    private final static Logger log = LoggerFactory.getLogger(SensorIconXml.class);
397
398}