001package jmri.jmrit.display.configurexml;
002
003import jmri.jmrit.audio.AudioBuffer;
004import jmri.jmrit.audio.AudioSource;
005import jmri.configurexml.JmriConfigureXmlException;
006import jmri.jmrit.catalog.NamedIcon;
007import jmri.jmrit.display.*;
008
009import org.jdom2.Attribute;
010import org.jdom2.Element;
011
012/**
013 * Handle configuration for display.AudioIcon objects.
014 *
015 * @author Daniel Bergqvist (C) 2023
016 */
017public class AudioIconXml extends PositionableLabelXml {
018
019    /**
020     * Default implementation for storing the contents of a AudioIcon
021     *
022     * @param o Object to store, of type AudioIcon
023     * @return Element containing the complete info
024     */
025    @Override
026    public Element store(Object o) {
027        AudioIcon p = (AudioIcon) o;
028
029        if (!p.isActive()) {
030            return null;  // if flagged as inactive, don't store
031        }
032        Element element = new Element("audioicon");
033        storeCommonAttributes(p, element);
034
035        element.addContent(new Element("Identity").addContent(Integer.toString(p.getIdentity())));
036
037        AudioSource source = (AudioSource)p.getAudio();
038        if (source != null) {
039            element.setAttribute("audio", source.getSystemName());
040
041            AudioBuffer buffer = (AudioBuffer) jmri.InstanceManager.getDefault(jmri.AudioManager.class)
042                    .getAudio(source.getAssignedBufferName());
043            if (buffer != null) {
044                // We need to use the attribute "sound" instead of the element "sound"
045                // since the method jmri.web.server.WebServer.portablePathToURI()
046                // converts paths in attributes to portable paths, but not paths
047                // in elements.
048                element.setAttribute("sound", buffer.getURL());
049            }
050        }
051
052        if (p.isText()) {
053            if (p.getUnRotatedText() != null) {
054                element.setAttribute("text", p.getUnRotatedText());
055            }
056            storeTextInfo(p, element);
057        }
058
059        if (p.isIcon() && p.getIcon() != null) {
060            element.setAttribute("icon", "yes");
061            element.addContent(storeIcon("icon", (NamedIcon) p.getIcon()));
062        }
063
064        element.setAttribute("onClickOperation", p.getOnClickOperation().name());
065        element.setAttribute("playSoundWhenJmriPlays", p.getPlaySoundWhenJmriPlays() ? "yes" : "no");
066        element.setAttribute("stopSoundWhenJmriStops", p.getStopSoundWhenJmriStops() ? "yes" : "no");
067
068        storeLogixNG_Data(p, element);
069
070        element.setAttribute("class", "jmri.jmrit.display.configurexml.AudioIconXml");
071        return element;
072    }
073
074    /**
075     * Create a AudioIcon, then add to a target JLayeredPane
076     *
077     * @param element Top level Element to unpack.
078     * @param o       Editor as an Object
079     * @throws JmriConfigureXmlException when a error prevents creating the objects as as
080     *                   required by the input XML
081     */
082    @Override
083    public void load(Element element, Object o) throws JmriConfigureXmlException {
084        // create the objects
085        AudioIcon l = null;
086
087        int identity = Integer.parseInt(element.getChildText("Identity"));
088
089        // get object class and determine editor being used
090        Editor editor = (Editor) o;
091
092        String audioName;
093        Attribute attr = element.getAttribute("audio");
094        if (attr == null) {
095            log.error("incorrect information for audio; must use audio name");
096            editor.loadFailed();
097            return;
098        } else {
099            audioName = attr.getValue();
100        }
101
102        if (element.getAttribute("icon") != null) {
103            NamedIcon icon;
104            String name = element.getAttribute("icon").getValue();
105            if (name.equals("yes")) {
106                icon = getNamedIcon("icon", element, "AudioIcon ", editor);
107            } else {
108                icon = NamedIcon.getIconByName(name);
109                if (icon == null) {
110                    icon = editor.loadFailed("AudioIcon", name);
111                    if (icon == null) {
112                        log.info("AudioIcon icon removed for url= {}", name);
113                        return;
114                    }
115                }
116            }
117            // abort if name != yes and have null icon
118            if (icon == null && !name.equals("yes")) {
119                log.info("AudioIcon icon removed for url= {}", name);
120                return;
121            }
122            l = new AudioIcon(identity, icon, editor);
123            try {
124                Attribute a = element.getAttribute("rotate");
125                if (a != null && icon != null) {
126                    int rotation = element.getAttribute("rotate").getIntValue();
127                    icon.setRotation(rotation, l);
128                }
129            } catch (org.jdom2.DataConversionException e) {
130            }
131
132            if (name.equals("yes")) {
133                NamedIcon nIcon = loadIcon(l, "icon", element, "AudioIcon ", editor);
134                if (nIcon != null) {
135                    l.updateIcon(nIcon);
136                } else {
137                    log.info("AudioIcon icon removed for url= {}", name);
138                    return;
139                }
140            } else {
141                l.updateIcon(icon);
142            }
143        }
144
145        if (element.getAttribute("text") != null) {
146            if (l == null) {
147                l = new AudioIcon(identity, element.getAttribute("text").getValue(), editor);
148            }
149            loadTextInfo(l, element);
150
151        } else if (l == null) {
152            log.error("AudioIcon is null!");
153            if (log.isDebugEnabled()) {
154                java.util.List<Attribute> attrs = element.getAttributes();
155                log.debug("\tElement Has {} Attributes:", attrs.size());
156                for (Attribute a : attrs) {
157                    log.debug("  attribute:  {} = {}", a.getName(), a.getValue());
158                }
159                java.util.List<Element> kids = element.getChildren();
160                log.debug("\tElementHas {} children:", kids.size());
161                for (Element e : kids) {
162                    log.debug("  child:  {} = \"{}\"", e.getName(), e.getValue());
163                }
164            }
165            editor.loadFailed();
166            return;
167        }
168
169        l.setAudio(audioName);
170
171        String onClickOperation = element.getAttribute("onClickOperation").getValue();
172        l.setOnClickOperation(AudioIcon.OnClickOperation.valueOf(onClickOperation));
173
174        String yesno = element.getAttribute("playSoundWhenJmriPlays").getValue();
175        if ((yesno != null) && (!yesno.equals(""))) {
176            l.setPlaySoundWhenJmriPlays(yesno.equals("yes"));
177        }
178
179        yesno = element.getAttribute("stopSoundWhenJmriStops").getValue();
180        if ((yesno != null) && (!yesno.equals(""))) {
181            l.setStopSoundWhenJmriStops(yesno.equals("yes"));
182        }
183
184        try {
185            editor.putItem(l);
186        } catch (Positionable.DuplicateIdException e) {
187            // This should never happen
188            log.error("Editor.putItem() with null id has thrown DuplicateIdException", e);
189        }
190
191        loadLogixNG_Data(l, element);
192
193        // load individual item's option settings after editor has set its global settings
194        loadCommonAttributes(l, Editor.LABELS, element);
195    }
196
197    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AudioIconXml.class);
198}