001package jmri.jmrit.display.switchboardEditor.configurexml;
002
003import java.awt.Color;
004import java.awt.Dimension;
005import java.awt.Point;
006import java.util.List;
007import javax.swing.JFrame;
008import jmri.ConfigureManager;
009import jmri.InstanceManager;
010import jmri.configurexml.AbstractXmlAdapter;
011import jmri.configurexml.XmlAdapter;
012import jmri.jmrit.display.EditorManager;
013import jmri.jmrit.display.switchboardEditor.SwitchboardEditor;
014import jmri.jmrit.display.switchboardEditor.SwitchBoardLabelDisplays;
015import jmri.util.ColorUtil;
016
017import org.jdom2.Attribute;
018import org.jdom2.Element;
019import org.slf4j.Logger;
020import org.slf4j.LoggerFactory;
021
022/**
023 * Handle configuration for {@link SwitchboardEditor} panes.
024 *
025 * @author Bob Jacobsen Copyright (c) 2002
026 * @author Egbert Broerse Copyright (c) 2017, 2020
027 */
028public class SwitchboardEditorXml extends AbstractXmlAdapter {
029
030    public SwitchboardEditorXml() {
031    }
032
033    /**
034     * Default implementation for storing the contents of a SwitchboardEditor.
035     * Storing of beanswitch properties for use on web panel
036     * {@link SwitchboardEditorXml}
037     *
038     * @param o Object to store, of type SwitchboardEditor
039     * @return Element containing the complete info
040     */
041    @Override
042    public Element store(Object o) {
043        SwitchboardEditor p = (SwitchboardEditor) o;
044        Element panel = new Element("switchboardeditor");
045
046        JFrame frame = p.getTargetFrame();
047
048        panel.setAttribute("class", "jmri.jmrit.display.switchboardEditor.configurexml.SwitchboardEditorXml");
049        panel.setAttribute("name", "" + frame.getTitle());
050        // size and position are managed by Prefsmanager
051        panel.setAttribute("editable", "" + (p.isEditable() ? "yes" : "no"));
052        panel.setAttribute("showtooltips", "" + (p.showToolTip() ? "yes" : "no"));
053        panel.setAttribute("controlling", "" + (p.allControlling() ? "yes" : "no"));
054        panel.setAttribute("hide", p.isVisible() ? "no" : "yes");
055        panel.setAttribute("panelmenu", p.isPanelMenuVisible() ? "yes" : "no");
056        panel.setAttribute("scrollable", p.getScrollable());
057        panel.setAttribute("hideunconnected", "" + (p.hideUnconnected() ? "yes" : "no"));
058        panel.setAttribute("autoitemrange", "" + (p.autoItemRange() ? "yes" : "no"));
059        panel.setAttribute("rangemin", "" + p.getPanelMenuRangeMin());
060        panel.setAttribute("rangemax", "" + p.getPanelMenuRangeMax());
061        panel.setAttribute("type", p.getSwitchType());
062        panel.setAttribute("connection", p.getSwitchManu());
063        panel.setAttribute("shape", p.getSwitchShape());
064        panel.setAttribute("rows", "" + p.getRows());
065        panel.setAttribute("total", "" + p.getTotal()); // total number of items displayed
066        panel.setAttribute("showusername", "" + p.showUserName());
067        panel.setAttribute("iconscale", "" + p.getIconScale());
068        panel.setAttribute("defaulttextcolor", p.getDefaultTextColor());
069        panel.setAttribute("activecolor", p.getActiveSwitchColor()); // fetched directly from Editor by Servlet
070        panel.setAttribute("inactivecolor", p.getInactiveSwitchColor()); // user-settable since 4.21.3
071        if (p.getBackgroundColor() != null) {
072            panel.setAttribute("redBackground", "" + p.getBackgroundColor().getRed());
073            panel.setAttribute("greenBackground", "" + p.getBackgroundColor().getGreen());
074            panel.setAttribute("blueBackground", "" + p.getBackgroundColor().getBlue());
075        }
076
077        // include contents (not used to store Switchboards on disk as
078        // all config is stored at Panel level).
079        return panel;
080    }
081
082    @Override
083    public void load(Element element, Object o) {
084        log.error("Invalid method called");
085    }
086
087    /**
088     * Create a SwitchboardEditor object, then register and fill it, then pop it
089     * in a JFrame.
090     *
091     * @param shared Top level Element to unpack.
092     * @return true if successful
093     */
094    @Override
095    public boolean load(Element shared, Element perNode) {
096        if (java.awt.GraphicsEnvironment.isHeadless()) {
097            return true;
098        }
099
100        boolean result = true;
101        Attribute a;
102        // find coordinates
103        int x = 0;
104        int y = 0;
105        int height = 400;
106        int width = 300;
107        int rangemin = 1;
108        int rangemax = 32;
109        int rows = 4;
110        int iconscale = 100;
111        String type;
112        String connection;
113        String shape;
114        String name;
115
116        try {
117            if ((a = shared.getAttribute("x")) != null) {
118                x = a.getIntValue();
119            }
120            if ((a = shared.getAttribute("y")) != null) {
121                y = a.getIntValue();
122            }
123            if ((a = shared.getAttribute("height")) != null) {
124                height = a.getIntValue();
125            }
126            if ((a = shared.getAttribute("width")) != null) {
127                width = a.getIntValue();
128            }
129        } catch (org.jdom2.DataConversionException e) {
130            log.error("failed to convert Switchboard's attribute");
131            result = false;
132        }
133        // find the name
134        name = "Switchboard"; // this will be replaced by the name as stored NOI18N
135        if (shared.getAttribute("name") != null) {
136            name = shared.getAttribute("name").getValue();
137        }
138        // confirm that panel hasn't already been loaded
139        if (InstanceManager.getDefault(EditorManager.class).contains(name)) {
140            log.warn("File contains a panel with the same name ({}) as an existing panel", name);
141            result = false;
142        }
143
144        // If available, override location and size with machine dependent values
145        if (!InstanceManager.getDefault(jmri.util.gui.GuiLafPreferencesManager.class).isEditorUseOldLocSize()) {
146            jmri.UserPreferencesManager prefsMgr = InstanceManager.getNullableDefault(jmri.UserPreferencesManager.class);
147            if (prefsMgr != null) {
148
149                Point prefsWindowLocation = prefsMgr.getWindowLocation(name);
150                if (prefsWindowLocation != null) {
151                    x = (int) prefsWindowLocation.getX();
152                    y = (int) prefsWindowLocation.getY();
153                }
154
155                Dimension prefsWindowSize = prefsMgr.getWindowSize(name);
156                if (prefsWindowSize != null && prefsWindowSize.getHeight() != 0 && prefsWindowSize.getWidth() != 0) {
157                    height = (int) prefsWindowSize.getHeight();
158                    width = (int) prefsWindowSize.getWidth();
159                }
160            }
161        }
162
163        SwitchboardEditor panel = new SwitchboardEditor(name);
164        //panel.makeFrame(name);
165        InstanceManager.getDefault(EditorManager.class).add(panel);
166        panel.getTargetFrame().setLocation(x, y);
167        panel.getTargetFrame().setSize(width, height);
168
169        panel.setTitle();
170
171        // Load editor option flags. This has to be done before the content
172        // items are loaded, to preserve the individual item settings.
173        boolean value = true;
174
175        if ((a = shared.getAttribute("editable")) != null && a.getValue().equals("no")) {
176            value = false;
177        }
178        panel.setAllEditable(value);
179        value = (a = shared.getAttribute("showtooltips")) == null || !a.getValue().equals("no");
180        panel.setAllShowToolTip(value);
181        value = (a = shared.getAttribute("controlling")) == null || !a.getValue().equals("no");
182        panel.setAllControlling(value);
183        value = (a = shared.getAttribute("hide")) != null && a.getValue().equals("yes");
184        panel.setShowHidden(value);
185        value = (a = shared.getAttribute("panelmenu")) == null || !a.getValue().equals("no");
186        panel.setPanelMenuVisible(value);
187
188        String state = "both";
189        if ((a = shared.getAttribute("scrollable")) != null) {
190            state = a.getValue();
191        }
192        panel.setScroll(state);
193        value = (a = shared.getAttribute("hideunconnected")) != null && a.getValue().equals("yes");
194        panel.setHideUnconnected(value);
195        value = (a = shared.getAttribute("autoitemrange")) == null || !a.getValue().equals("no");
196        panel.setAutoItemRange(value);
197
198        try {
199            rangemin = shared.getAttribute("rangemin").getIntValue();
200            rangemax = shared.getAttribute("rangemax").getIntValue();
201        } catch (org.jdom2.DataConversionException e) {
202            log.error("failed to convert Switchboard's range");
203            result = false;
204        }
205        panel.setPanelMenuRangeMin(rangemin);
206        panel.setPanelMenuRangeMax(rangemax);
207
208        type = shared.getAttribute("type").getValue();
209        panel.setSwitchType(type);
210
211        connection = shared.getAttribute("connection").getValue();
212        panel.setSwitchManu(connection);
213        log.debug("SwitchBoard connection choice set to {}", connection);
214
215        shape = shared.getAttribute("shape").getValue();
216        panel.setSwitchShape(shape);
217
218        if (shared.getAttribute("columns") != null) {
219            try { // migration of old naming, dropped since 4.21.2
220                rows = shared.getAttribute("columns").getIntValue();
221            } catch (org.jdom2.DataConversionException e) {
222                log.error("failed to convert Switchboard's row (formerly column) count");
223                result = false;
224            }
225        }
226        if (shared.getAttribute("rows") != null) {
227            try {
228                rows = shared.getAttribute("rows").getIntValue();
229            } catch (org.jdom2.DataConversionException e) {
230                log.error("failed to convert Switchboard's row count");
231                result = false;
232            }
233        }
234        panel.setRows(rows); // if 0, autoRows is selected (handled in Editor)
235
236        a = shared.getAttribute("showusername");
237        if (a == null || a.getValue().equals("yes")) {
238            panel.setShowUserName(SwitchBoardLabelDisplays.BOTH_NAMES); // default and migration
239        } else if (a.getValue().equals("no")) {
240            panel.setShowUserName(SwitchBoardLabelDisplays.SYSTEM_NAME); // only how system name
241        } else {
242            panel.setShowUserName(SwitchBoardLabelDisplays.USER_NAME); // display name (one, prefer user name)
243        }
244
245        if (shared.getAttribute("iconscale") != null) {
246            try {
247                iconscale = shared.getAttribute("iconscale").getIntValue();
248            } catch (org.jdom2.DataConversionException e) {
249                log.error("failed to convert Switchboard's icon scale setting");
250                result = false;
251            }
252        }
253        panel.setIconScale(iconscale);
254
255        Color defaultTextColor = Color.BLACK;
256        if (shared.getAttribute("defaulttextcolor") != null) {
257            String color = shared.getAttribute("defaulttextcolor").getValue();
258            try {
259                defaultTextColor = ColorUtil.stringToColor(color);
260            } catch (IllegalArgumentException ex) {
261                log.error("Invalid defaulttextcolor {} using black", color);
262            }
263        }
264        panel.setDefaultTextColor(defaultTextColor);
265        // set color if needed
266        try {
267            int red = shared.getAttribute("redBackground").getIntValue();
268            int blue = shared.getAttribute("blueBackground").getIntValue();
269            int green = shared.getAttribute("greenBackground").getIntValue();
270            panel.setDefaultBackgroundColor(new Color(red, green, blue));
271        } catch (org.jdom2.DataConversionException e) {
272            log.warn("Could not parse color attributes!");
273        } catch (NullPointerException e) {  // considered normal if the attributes are not present
274        }
275        // activecolor
276        Color activeColor = Color.RED;
277        if (shared.getAttribute("activecolor") != null) {
278            String color = shared.getAttribute("activecolor").getValue();
279            try {
280                activeColor = ColorUtil.stringToColor(color);
281            } catch (IllegalArgumentException ex) {
282                log.error("Invalid activecolor {}, using red", color);
283            }
284        }
285        panel.setDefaultActiveColor(activeColor);
286        // inactivecolor
287        Color inactiveColor = Color.GREEN;
288        if (shared.getAttribute("inactivecolor") != null) {
289            String color = shared.getAttribute("inactivecolor").getValue();
290            try {
291                inactiveColor = ColorUtil.stringToColor(color);
292            } catch (IllegalArgumentException ex) {
293                log.error("Invalid inactivecolor {}, using green", color);
294            }
295        }
296        panel.setDefaultInactiveColor(inactiveColor);
297        // set the (global) editor display widgets to their flag settings
298        panel.initView();
299
300        // load the contents with their individual option settings
301        List<Element> panelItems = shared.getChildren();
302        for (Element item : panelItems) {
303            // get the class, hence the adapter object to do loading
304            String adapterName = item.getAttribute("class").getValue();
305            log.debug("load via {}", adapterName);
306            try {
307                XmlAdapter adapter = (XmlAdapter) Class.forName(adapterName).getDeclaredConstructor().newInstance();
308                // and do it
309                adapter.load(item, panel);
310                if (!panel.loadOK()) {
311                    result = false;
312                }
313            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException
314                    | jmri.configurexml.JmriConfigureXmlException
315                    | java.lang.reflect.InvocationTargetException e) {
316                log.error("Exception while loading {}", item.getName(), e);
317                result = false;
318            }
319        }
320        panel.disposeLoadData();     // dispose of url correction data
321
322        // display the results, with the editor in back
323        panel.pack();
324        panel.setAllEditable(panel.isEditable());
325
326        // we don't pack the target frame here, because size was specified
327        // TODO: Work out why, when calling this method, panel size is increased
328        // vertically (at least on MS Windows)
329        panel.getTargetFrame().setVisible(true); // always show the panel
330
331        // register the resulting panel for later configuration
332        ConfigureManager cm = InstanceManager.getNullableDefault(jmri.ConfigureManager.class);
333        if (cm != null) {
334            cm.registerUser(panel);
335        }
336
337        // reset the size and position, in case the display caused it to change
338        panel.getTargetFrame().setLocation(x, y);
339        panel.getTargetFrame().setSize(width, height);
340        panel.updatePressed(); // required, picks up panel color
341        log.debug("Switchboard ready");
342        return result;
343    }
344
345    @Override
346    public int loadOrder() {
347        return jmri.Manager.PANELFILES;
348    }
349
350    private final static Logger log = LoggerFactory.getLogger(SwitchboardEditorXml.class);
351
352}