001package jmri.jmrit.swing.meter.configurexml;
002
003import java.awt.GraphicsEnvironment;
004import java.util.List;
005import java.util.UUID;
006
007import jmri.InstanceManager;
008import jmri.Meter;
009import jmri.MeterManager;
010import jmri.configurexml.JmriConfigureXmlException;
011import jmri.jmrit.swing.meter.MeterFrame;
012import jmri.jmrit.swing.meter.MeterFrameManager;
013
014import org.jdom2.Attribute;
015import org.jdom2.Element;
016
017import javax.annotation.Nonnull;
018
019/**
020 * Stores MeterFrames to the panel file.
021 * @author Daniel Bergqvist Copyright (c) 2020
022 */
023public class MeterFrameManagerXml extends jmri.configurexml.AbstractXmlAdapter {
024
025    private final EnumIO<MeterFrame.Unit> unitEnumMap = new EnumIoNames<>(MeterFrame.Unit.class);
026
027    public MeterFrameManagerXml() {
028    }
029    
030    @Override
031    public Element store(Object o) {
032        Element meterFrames = new Element("meterFrames");
033        setStoreElementClass(meterFrames);
034        
035        var frames = MeterFrameManager.getInstance().getMeterFrames();
036        if (frames.isEmpty()) return null;
037        
038        boolean empty = true;
039        for (MeterFrame frame : frames) {
040            var meterElement = storeMeterFrame(frame);
041            if (meterElement == null) continue;
042            empty = false;
043            meterFrames.addContent(meterElement);
044        }
045        
046        if (empty) return null;
047        return meterFrames;
048    }
049    
050    public Element storeMeterFrame(MeterFrame frame) {
051        Element e = new Element("meterFrame");
052        
053        Element e2 = new Element("uuid");
054        e2.addContent(frame.getUUID().toString());
055        e.addContent(e2);
056        
057        e2 = new Element("meter");
058        if (frame.getMeter() == null) {
059            return null; // apparently user did not assign a real world meter; do not save
060        }
061        e2.addContent(frame.getMeter().getSystemName()); // this should be a NamedBeanHandle
062        e.addContent(e2);
063        
064        e.setAttribute("unit", unitEnumMap.outputFromEnum(frame.getUnit()));
065        e.setAttribute("integer-digits", Integer.toString(frame.getNumIntegerDigits()));
066        e.setAttribute("decimal-digits", Integer.toString(frame.getNumDecimalDigits()));
067        e.setAttribute("x", Integer.toString(frame.getX()));
068        e.setAttribute("y", Integer.toString(frame.getY()));
069        e.setAttribute("width", Integer.toString(frame.getWidth()));
070        e.setAttribute("height", Integer.toString(frame.getHeight()));
071        
072        return e;
073    }
074    
075    /**
076     * Subclass provides implementation to create the correct top element,
077     * including the type information. Default implementation is to use the
078     * local class here.
079     *
080     * @param meterFrames The top-level element being created
081     */
082    public void setStoreElementClass(Element meterFrames) {
083        meterFrames.setAttribute("class", this.getClass().getName());  // NOI18N
084    }
085    
086    /** {@inheritDoc} */
087    @Override
088    public boolean load(@Nonnull Element shared, Element perNode) throws JmriConfigureXmlException {
089        // Don't create frames if headless
090        if (GraphicsEnvironment.isHeadless()) return true;
091        
092        List<Element> frames = shared.getChildren("meterFrame");
093        
094        for (Element elem : frames) {
095            String uuidStr = elem.getChild("uuid").getText();
096            String meterSystemName = elem.getChild("meter").getText();      // This should be a NamedBeanHandle, but may not exist yet
097            Meter meter = InstanceManager.getDefault(MeterManager.class).getBySystemName(meterSystemName);
098            UUID uuid = UUID.fromString(uuidStr);
099            MeterFrame frame = MeterFrameManager.getInstance().getByUUID(uuid);
100            if (frame == null) {
101                log.debug("creating frame for uuid: {}, selected meter: {}", uuidStr, meterSystemName);
102                frame = new MeterFrame(uuid);
103                frame.initComponents();
104            }
105            if (meter != null) {
106                frame.setMeter(meter);
107            } else {
108                log.debug("selected meter '{}' not (yet) defined, remembering for later.", meterSystemName);                
109                frame.setInitialMeterName(meterSystemName);
110            }
111            
112            Attribute a = elem.getAttribute("unit");
113            if (a != null) frame.setUnit(unitEnumMap.inputFromAttribute(a));
114            
115            frame.setNumIntegerDigits(getAttributeIntegerValue(elem, "integer-digits", 3));
116            frame.setNumDecimalDigits(getAttributeIntegerValue(elem, "decimal-digits", 0));
117            
118            frame.setLocation(
119                    Integer.parseInt(elem.getAttributeValue("x")),
120                    Integer.parseInt(elem.getAttributeValue("y")));
121            frame.setSize(
122                    Integer.parseInt(elem.getAttributeValue("width")),
123                    Integer.parseInt(elem.getAttributeValue("height")));
124            frame.setVisible(true);
125        }
126        
127        return true;
128    }
129
130    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MeterFrameManagerXml.class);
131
132}