001package jmri.web.servlet.panel;
002
003import java.util.ArrayList;
004import java.util.Comparator;
005import java.util.List;
006import javax.servlet.annotation.WebServlet;
007import javax.servlet.http.HttpServlet;
008import javax.swing.JFrame;
009
010import jmri.jmrit.display.IndicatorTrackIcon;
011import jmri.jmrit.display.IndicatorTurnoutIcon;
012import jmri.jmrit.display.Positionable;
013import jmri.jmrit.display.controlPanelEditor.ControlPanelEditor;
014import org.jdom2.Document;
015import org.jdom2.Element;
016import org.jdom2.output.Format;
017import org.jdom2.output.XMLOutputter;
018import org.openide.util.lookup.ServiceProvider;
019import org.slf4j.Logger;
020import org.slf4j.LoggerFactory;
021
022/**
023 * Return xml (for specified ControlPanel) suitable for use by external clients.
024 * <p>
025 * See JMRI Web Server - Panel Servlet Help in help/en/html/web/PanelServlet.shtml for an example description of
026 * the interaction between the Web Servlets, the Web Browser and the JMRI application.
027 *
028 * @author Randall Wood (C) 2016
029 */
030@WebServlet(name = "ControlPanelServlet",
031        urlPatterns = {"/panel/ControlPanel"})
032@ServiceProvider(service = HttpServlet.class)
033public class ControlPanelServlet extends AbstractPanelServlet {
034
035    @Override
036    protected String getPanelType() {
037        return "ControlPanel";
038    }
039
040    @Override
041    protected String getXmlPanel(String name) {
042        log.debug("Getting {} for {}", getPanelType(), name);
043        ControlPanelEditor editor = (ControlPanelEditor) getEditor(name);
044        if (editor == null) {
045            log.warn("Requested ControlPanel [{}] does not exist.", name);
046            return "ERROR Requested panel [" + name + "] does not exist.";
047        }
048
049        Element panel = new Element("panel");
050
051        JFrame frame = editor.getTargetFrame();
052
053        panel.setAttribute("name", name);
054        panel.setAttribute("height", Integer.toString(frame.getContentPane().getHeight()));
055        panel.setAttribute("width", Integer.toString(frame.getContentPane().getWidth()));
056        panel.setAttribute("panelheight", Integer.toString(editor.getTargetPanel().getHeight()));
057        panel.setAttribute("panelwidth", Integer.toString(editor.getTargetPanel().getWidth()));
058
059        panel.setAttribute("showtooltips", (editor.showToolTip()) ? "yes" : "no");
060        panel.setAttribute("controlling", (editor.allControlling()) ? "yes" : "no");
061        if (editor.getBackgroundColor() != null) {
062            Element color = new Element("backgroundColor");
063            color.setAttribute("red", Integer.toString(editor.getBackgroundColor().getRed()));
064            color.setAttribute("green", Integer.toString(editor.getBackgroundColor().getGreen()));
065            color.setAttribute("blue", Integer.toString(editor.getBackgroundColor().getBlue()));
066            panel.addContent(color);
067        }
068
069        // include contents, sorted by display level (z-order) so the web client,
070        // which draws elements in document order onto a single canvas, reproduces
071        // the desktop stacking order. Lower-level elements are emitted first and
072        // higher-level elements last. A stable sort preserves the existing relative
073        // order of elements that share a display level. See JMRI/JMRI#12794.
074        List<Positionable> contents = new ArrayList<>(editor.getContents());
075        contents.sort(Comparator.comparingInt(Positionable::getDisplayLevel));
076        log.debug("N elements: {}", contents.size());
077        for (Positionable sub : contents) {
078            if (sub != null) {
079                Element e = new Element("temp");
080                try {
081                    e = positionableElement(sub);
082                } catch (Exception ex) {
083                    log.error("Error storing panel element: {}", ex, ex);
084                }
085                // where required, add special stuff to positionable here to use in Web Server
086                switch (e.getName()) {
087                    case "indicatorturnouticon" :
088                        // if separate occ.sensor was set on icon, names for sensor plus the turnout were
089                        // already copied to e as part of 'contents'
090                        Element elem = new Element("oblocksysname");
091                        if (((IndicatorTurnoutIcon) sub).getOccBlock() != null) { // optional for CPE, not read on load
092                            String itoioblock = ((IndicatorTurnoutIcon) sub).getOccBlock().getSystemName();
093                            elem.addContent(itoioblock);
094                            log.debug("CP-SERVLET ITOI = {}", itoioblock);
095                        } else {
096                            elem.addContent("none"); // NOI18N
097                            log.debug("no oblocksensor configured on ITOI {}", sub.getNameString());
098                        }
099                        e.addContent(elem);
100                        break;
101                    case "indicatortrackicon" :
102                        // if separate occ.sensor was set on icon, its name was already copied to e as part of 'contents'
103                        elem = new Element("oblocksysname");
104                        if (((IndicatorTrackIcon) sub).getOccBlock() != null) { // optional for CPE, not read on load
105                            String itioblock = ((IndicatorTrackIcon) sub).getOccBlock().getSystemName();
106                            elem.addContent(itioblock);
107                            log.debug("CP-SERVLET ITI = {}", itioblock);
108                        } else {
109                            elem.addContent("none"); // NOI18N
110                            log.debug("no oblocksensor configured on ITI {}", sub.getNameString());
111                        }
112                        e.addContent(elem);
113                        break;
114                    case "" :
115                    default :
116                        // nothing extra
117                }
118                panel.addContent(e);
119            }
120        }
121
122        Document doc = new Document(panel);
123        XMLOutputter out = new XMLOutputter();
124        out.setFormat(Format.getPrettyFormat()
125                .setLineSeparator(System.getProperty("line.separator"))
126                .setTextMode(Format.TextMode.TRIM));
127
128        return out.outputString(doc);
129    }
130
131    @Override
132    protected String getJsonPanel(String name) {
133        // TODO Auto-generated method stub
134        return "ERROR JSON support not implemented";
135    }
136
137    private static final Logger log = LoggerFactory.getLogger(ControlPanelServlet.class);
138
139}