001package jmri.jmrit.display.configurexml;
002
003import jmri.util.gui.GuiLafPreferencesManager;
004
005import java.awt.Color;
006import java.awt.Font;
007
008import jmri.InstanceManager;
009import jmri.configurexml.AbstractXmlAdapter;
010import jmri.configurexml.JmriConfigureXmlException;
011import jmri.jmrit.catalog.NamedIcon;
012import jmri.jmrit.display.Editor;
013import jmri.jmrit.display.Positionable;
014import jmri.jmrit.display.PositionableLabel;
015import jmri.jmrit.display.PositionablePopupUtil;
016import jmri.jmrit.display.ToolTip;
017import jmri.jmrit.logixng.LogixNG_Manager;
018
019import org.jdom2.Attribute;
020import org.jdom2.DataConversionException;
021import org.jdom2.Element;
022import org.slf4j.Logger;
023import org.slf4j.LoggerFactory;
024
025/**
026 * Handle configuration for display.PositionableLabel objects
027 *
028 * @author Bob Jacobsen Copyright: Copyright (c) 2002
029 */
030public class PositionableLabelXml extends AbstractXmlAdapter {
031
032    public PositionableLabelXml() {
033    }
034
035    /**
036     * Default implementation for storing the contents of a PositionableLabel
037     *
038     * @param o Object to store, of type PositionableLabel
039     * @return Element containing the complete info
040     */
041    @Override
042    public Element store(Object o) {
043        PositionableLabel p = (PositionableLabel) o;
044
045        if (!p.isActive()) {
046            return null;  // if flagged as inactive, don't store
047        }
048        Element element = new Element("positionablelabel");
049        storeCommonAttributes(p, element);
050
051        if (p.isText()) {
052            if (p.getUnRotatedText() != null) {
053                element.setAttribute("text", p.getUnRotatedText());
054            }
055            storeTextInfo(p, element);
056        }
057
058        if (p.isIcon() && p.getIcon() != null) {
059            element.setAttribute("icon", "yes");
060            element.addContent(storeIcon("icon", (NamedIcon) p.getIcon()));
061        }
062
063        storeLogixNG_Data(p, element);
064
065        element.setAttribute("class", "jmri.jmrit.display.configurexml.PositionableLabelXml");
066        return element;
067    }
068
069    /**
070     * Store the text formatting information.
071     * <p>
072     * This is always stored, even if the icon isn't in text mode, because some
073     * uses (subclasses) of PositionableLabel flip back and forth between icon
074     * and text, and want to remember their formatting.
075     *
076     * @param p       the icon to store
077     * @param element the XML representation of the icon
078     */
079    protected void storeTextInfo(Positionable p, Element element) {
080        //if (p.getText()!=null) element.setAttribute("text", p.getText());
081        PositionablePopupUtil util = p.getPopupUtility();
082
083        GuiLafPreferencesManager manager = InstanceManager.getDefault(GuiLafPreferencesManager.class);
084        String defaultFontName = manager.getDefaultFont().getFontName();
085
086        String fontName = util.getFont().getFontName();
087        if (!fontName.equals(defaultFontName)) {
088            element.setAttribute("fontFamily", "" + util.getFont().getFamily());
089            String storedfontname = simplifyFontname(fontName, util.getFontStyle());
090            element.setAttribute("fontname", "" + storedfontname);
091        }
092
093        element.setAttribute("size", "" + util.getFontSize());
094        element.setAttribute("style", "" + util.getFontStyle());
095
096        // always write the foreground (text) color
097        element.setAttribute("red", "" + util.getForeground().getRed());
098        element.setAttribute("green", "" + util.getForeground().getGreen());
099        element.setAttribute("blue", "" + util.getForeground().getBlue());
100
101        element.setAttribute("hasBackground", util.hasBackground() ? "yes" : "no");
102        if (util.hasBackground()) {
103            element.setAttribute("redBack", "" + util.getBackground().getRed());
104            element.setAttribute("greenBack", "" + util.getBackground().getGreen());
105            element.setAttribute("blueBack", "" + util.getBackground().getBlue());
106        }
107
108        if (util.getMargin() != 0) {
109            element.setAttribute("margin", "" + util.getMargin());
110        }
111        if (util.getBorderSize() != 0) {
112            element.setAttribute("borderSize", "" + util.getBorderSize());
113            element.setAttribute("redBorder", "" + util.getBorderColor().getRed());
114            element.setAttribute("greenBorder", "" + util.getBorderColor().getGreen());
115            element.setAttribute("blueBorder", "" + util.getBorderColor().getBlue());
116        }
117        if (util.getFixedWidth() != 0) {
118            element.setAttribute("fixedWidth", "" + util.getFixedWidth());
119        }
120        if (util.getFixedHeight() != 0) {
121            element.setAttribute("fixedHeight", "" + util.getFixedHeight());
122        }
123
124        String just;
125        switch (util.getJustification()) {
126            case 0x02:
127                just = "right";
128                break;
129            case 0x04:
130                just = "centre";
131                break;
132            default:
133                just = "left";
134                break;
135        }
136        element.setAttribute("justification", just);
137
138        if (util.getOrientation() != PositionablePopupUtil.HORIZONTAL) {
139            String ori;
140            switch (util.getOrientation()) {
141                case PositionablePopupUtil.VERTICAL_DOWN:
142                    ori = "vertical_down";
143                    break;
144                case PositionablePopupUtil.VERTICAL_UP:
145                    ori = "vertical_up";
146                    break;
147                default:
148                    ori = "horizontal";
149                    break;
150            }
151            element.setAttribute("orientation", ori);
152        }
153        //return element;
154    }
155
156    /**
157     * Default implementation for storing the common contents of an Icon
158     *
159     * @param p       the icon to store
160     * @param element the XML representation of the icon
161     */
162    public void storeCommonAttributes(Positionable p, Element element) {
163
164        if (p.getId() != null) element.setAttribute("id", p.getId());
165
166        var classes = p.getClasses();
167        if (!classes.isEmpty()) {
168            StringBuilder classNames = new StringBuilder();
169            for (String className : classes) {
170                if (className.contains(",")) {
171                    throw new UnsupportedOperationException("Comma is not allowed in class names");
172                }
173                if (classNames.length() > 0) classNames.append(",");
174                classNames.append(className);
175            }
176            element.setAttribute("classes", classNames.toString());
177        }
178
179        element.setAttribute("x", "" + p.getX());
180        element.setAttribute("y", "" + p.getY());
181        element.setAttribute("level", String.valueOf(p.getDisplayLevel()));
182        element.setAttribute("forcecontroloff", !p.isControlling() ? "true" : "false");
183        element.setAttribute("hidden", p.isHidden() ? "yes" : "no");
184        if (p.isEmptyHidden()) {
185            element.setAttribute("emptyHidden", "yes");
186        }
187        if (p.isValueEditDisabled()) {
188            element.setAttribute("valueEditDisabled", "yes");
189        }
190        element.setAttribute("positionable", p.isPositionable() ? "true" : "false");
191        element.setAttribute("showtooltip", p.showToolTip() ? "true" : "false");
192        element.setAttribute("editable", p.isEditable() ? "true" : "false");
193        ToolTip tip = p.getToolTip();
194        if (tip != null) {
195            if (tip.getPrependToolTipWithDisplayName()) {
196                element.addContent(
197                        new Element("tooltip_prependWithDisplayName")
198                                .addContent("yes"));
199            }
200            String txt = tip.getText();
201            if (txt != null) {
202                Element elem = new Element("tooltip").addContent(txt); // was written as "toolTip" 3.5.1 and before
203                element.addContent(elem);
204            }
205        }
206        if (p.getDegrees() != 0) {
207            element.setAttribute("degrees", "" + p.getDegrees());
208        }
209    }
210
211    public Element storeIcon(String elemName, NamedIcon icon) {
212        if (icon == null) {
213            return null;
214        }
215        Element element = new Element(elemName);
216        element.setAttribute("url", icon.getURL());
217        element.setAttribute("degrees", String.valueOf(icon.getDegrees()));
218        element.setAttribute("scale", String.valueOf(icon.getScale()));
219
220        // the "rotate" attribute was deprecated in 2.9.4, replaced by the "rotation" element
221        element.addContent(new Element("rotation").addContent(String.valueOf(icon.getRotation())));
222
223        return element;
224    }
225
226    public void storeLogixNG_Data(Positionable p, Element element) {
227        if (p.getLogixNG() == null) return;
228
229        // Don't save LogixNG data if we don't have any ConditionalNGs
230        if (p.getLogixNG().getNumConditionalNGs() == 0) return;
231        Element logixNG_Element = new Element("LogixNG");
232        logixNG_Element.addContent(new Element("InlineLogixNG_SystemName").addContent(p.getLogixNG().getSystemName()));
233        element.addContent(logixNG_Element);
234    }
235
236    @Override
237    public boolean load(Element shared, Element perNode) {
238        log.error("Invalid method called");
239        return false;
240    }
241
242    /**
243     * Create a PositionableLabel, then add to a target JLayeredPane
244     *
245     * @param element Top level Element to unpack.
246     * @param o       Editor as an Object
247     * @throws JmriConfigureXmlException when a error prevents creating the objects as as
248     *                   required by the input XML
249     */
250    @Override
251    public void load(Element element, Object o) throws JmriConfigureXmlException {
252        // create the objects
253        PositionableLabel l = null;
254
255        // get object class and determine editor being used
256        Editor editor = (Editor) o;
257        if (element.getAttribute("icon") != null) {
258            NamedIcon icon;
259            String name = element.getAttribute("icon").getValue();
260//            if (log.isDebugEnabled()) log.debug("icon attribute= "+name);
261            if (name.equals("yes")) {
262                icon = getNamedIcon("icon", element, "PositionableLabel ", editor);
263            } else {
264                icon = NamedIcon.getIconByName(name);
265                if (icon == null) {
266                    icon = editor.loadFailed("PositionableLabel", name);
267                    if (icon == null) {
268                        log.info("PositionableLabel icon removed for url= {}", name);
269                        return;
270                    }
271                }
272            }
273            // abort if name != yes and have null icon
274            if (icon == null && !name.equals("yes")) {
275                log.info("PositionableLabel icon removed for url= {}", name);
276                return;
277            }
278            l = new PositionableLabel(icon, editor);
279            try {
280                Attribute a = element.getAttribute("rotate");
281                if (a != null && icon != null) {
282                    int rotation = element.getAttribute("rotate").getIntValue();
283                    icon.setRotation(rotation, l);
284                }
285            } catch (org.jdom2.DataConversionException e) {
286            }
287
288            if (name.equals("yes")) {
289                NamedIcon nIcon = loadIcon(l, "icon", element, "PositionableLabel ", editor);
290                if (nIcon != null) {
291                    l.updateIcon(nIcon);
292                } else {
293                    log.info("PositionableLabel icon removed for url= {}", name);
294                    return;
295                }
296            } else {
297                l.updateIcon(icon);
298            }
299        }
300
301        if (element.getAttribute("text") != null) {
302            if (l == null) {
303                l = new PositionableLabel(element.getAttribute("text").getValue(), editor);
304            }
305            loadTextInfo(l, element);
306
307        } else if (l == null) {
308            log.error("PositionableLabel is null!");
309            if (log.isDebugEnabled()) {
310                java.util.List<Attribute> attrs = element.getAttributes();
311                log.debug("\tElement Has {} Attributes:", attrs.size());
312                for (Attribute a : attrs) {
313                    log.debug("  attribute:  {} = {}", a.getName(), a.getValue());
314                }
315                java.util.List<Element> kids = element.getChildren();
316                log.debug("\tElementHas {} children:", kids.size());
317                for (Element e : kids) {
318                    log.debug("  child:  {} = \"{}\"", e.getName(), e.getValue());
319                }
320            }
321            editor.loadFailed();
322            return;
323        }
324        try {
325            editor.putItem(l);
326        } catch (Positionable.DuplicateIdException e) {
327            // This should never happen
328            log.error("Editor.putItem() with null id has thrown DuplicateIdException", e);
329        }
330
331        loadLogixNG_Data(l, element);
332
333        // load individual item's option settings after editor has set its global settings
334        loadCommonAttributes(l, Editor.LABELS, element);
335    }
336
337    protected void loadTextInfo(Positionable l, Element element) {
338        if (log.isDebugEnabled()) {
339            log.debug("loadTextInfo");
340        }
341        jmri.jmrit.display.PositionablePopupUtil util = l.getPopupUtility();
342        if (util == null) {
343            log.warn("PositionablePopupUtil is null! {}", element);
344            return;
345        }
346
347        Attribute a = element.getAttribute("size");
348        try {
349            if (a != null) {
350                util.setFontSize(a.getFloatValue());
351            }
352        } catch (DataConversionException ex) {
353            log.warn("invalid size attribute value");
354        }
355
356        a = element.getAttribute("style");
357        try {
358            if (a != null) {
359                int style = a.getIntValue();
360                int drop = 0;
361                switch (style) {
362                    case 0:  //0 Normal
363                    case 2:  // italic
364                        drop = 1;
365                        break;
366                    default:
367                        break;
368                }
369                util.setFontStyle(style, drop);
370            }
371        } catch (DataConversionException ex) {
372            log.warn("invalid style attribute value");
373        }
374
375        a = element.getAttribute("fontname");
376        try {
377            if (a != null) {
378                util.setFont(new Font(a.getValue(), util.getFontStyle(), util.getFontSize()));
379                // Reset util to the new instance
380                // The setFont process clones the current util instance but the rest of loadTextInfo used the orignal instance.
381                util = l.getPopupUtility();
382            }
383        } catch (NullPointerException e) {  // considered normal if the attributes are not present
384        }
385
386        // set color if needed
387        try {
388            int red = element.getAttribute("red").getIntValue();
389            int blue = element.getAttribute("blue").getIntValue();
390            int green = element.getAttribute("green").getIntValue();
391            util.setForeground(new Color(red, green, blue));
392        } catch (org.jdom2.DataConversionException e) {
393            log.warn("Could not parse color attributes!");
394        } catch (NullPointerException e) {  // considered normal if the attributes are not present
395        }
396
397        a = element.getAttribute("hasBackground");
398        if (a != null) {
399            util.setHasBackground("yes".equals(a.getValue()));
400        } else {
401            util.setHasBackground(true);
402        }
403        if (util.hasBackground()) {
404            try {
405                int red = element.getAttribute("redBack").getIntValue();
406                int blue = element.getAttribute("blueBack").getIntValue();
407                int green = element.getAttribute("greenBack").getIntValue();
408                util.setBackgroundColor(new Color(red, green, blue));
409            } catch (org.jdom2.DataConversionException e) {
410                log.warn("Could not parse background color attributes!");
411            } catch (NullPointerException e) {
412                util.setHasBackground(false);// if the attributes are not listed, we consider the background as clear.
413            }
414        }
415
416        int fixedWidth = 0;
417        int fixedHeight = 0;
418        try {
419            fixedHeight = element.getAttribute("fixedHeight").getIntValue();
420        } catch (org.jdom2.DataConversionException e) {
421            log.warn("Could not parse fixed Height attributes!");
422        } catch (NullPointerException e) {  // considered normal if the attributes are not present
423        }
424
425        try {
426            fixedWidth = element.getAttribute("fixedWidth").getIntValue();
427        } catch (org.jdom2.DataConversionException e) {
428            log.warn("Could not parse fixed Width attribute!");
429        } catch (NullPointerException e) {  // considered normal if the attributes are not present
430        }
431        if (!(fixedWidth == 0 && fixedHeight == 0)) {
432            util.setFixedSize(fixedWidth, fixedHeight);
433        }
434        if ((util.getFixedWidth() == 0) || (util.getFixedHeight() == 0)) {
435            try {
436                util.setMargin(element.getAttribute("margin").getIntValue());
437            } catch (org.jdom2.DataConversionException e) {
438                log.warn("Could not parse margin attribute!");
439            } catch (NullPointerException e) {  // considered normal if the attributes are not present
440            }
441        }
442        try {
443            util.setBorderSize(element.getAttribute("borderSize").getIntValue());
444            int red = element.getAttribute("redBorder").getIntValue();
445            int blue = element.getAttribute("blueBorder").getIntValue();
446            int green = element.getAttribute("greenBorder").getIntValue();
447            util.setBorderColor(new Color(red, green, blue));
448        } catch (org.jdom2.DataConversionException e) {
449            log.warn("Could not parse border attributes!");
450        } catch (NullPointerException e) {  // considered normal if the attribute not present
451        }
452
453        a = element.getAttribute("justification");
454        if (a != null) {
455            util.setJustification(a.getValue());
456        } else {
457            util.setJustification("left");
458        }
459        a = element.getAttribute("orientation");
460        if (a != null) {
461            util.setOrientation(a.getValue());
462        } else {
463            util.setOrientation("horizontal");
464        }
465
466        int deg = 0;
467        try {
468            a = element.getAttribute("degrees");
469            if (a != null) {
470                deg = a.getIntValue();
471                l.rotate(deg);
472            }
473        } catch (DataConversionException ex) {
474            log.warn("invalid 'degrees' value (non integer)");
475        }
476        if (deg == 0 && util.hasBackground()) {
477            l.setOpaque(true);
478        }
479    }
480
481    public void loadCommonAttributes(Positionable l, int defaultLevel, Element element)
482            throws JmriConfigureXmlException {
483
484        if (element.getAttribute("id") != null) {
485            try {
486                l.setId(element.getAttribute("id").getValue());
487            } catch (Positionable.DuplicateIdException e) {
488                throw new JmriConfigureXmlException("Positionable id is not unique", e);
489            }
490        }
491
492        if (element.getAttribute("classes") != null) {
493            String classes = element.getAttribute("classes").getValue();
494            for (String className : classes.split(",")) {
495                if (!className.isBlank()) {
496                    l.addClass(className);
497                }
498            }
499        }
500
501        try {
502            l.setControlling(!element.getAttribute("forcecontroloff").getBooleanValue());
503        } catch (DataConversionException e1) {
504            log.warn("unable to convert positionable label forcecontroloff attribute");
505        } catch (Exception e) {
506        }
507
508        // find coordinates
509        int x = 0;
510        int y = 0;
511        try {
512            x = element.getAttribute("x").getIntValue();
513            y = element.getAttribute("y").getIntValue();
514        } catch (org.jdom2.DataConversionException e) {
515            log.error("failed to convert positional attribute");
516        }
517        l.setLocation(x, y);
518
519        // find display level
520        int level = defaultLevel;
521        try {
522            level = element.getAttribute("level").getIntValue();
523        } catch (org.jdom2.DataConversionException e) {
524            log.warn("Could not parse level attribute!");
525        } catch (NullPointerException e) {
526            // considered normal if the attribute not present
527        }
528        l.setDisplayLevel(level);
529
530        try {
531            boolean value = element.getAttribute("hidden").getBooleanValue();
532            l.setHidden(value);
533            l.setVisible(!value);
534        } catch (DataConversionException e) {
535            log.warn("unable to convert positionable label hidden attribute");
536        } catch (NullPointerException e) {
537            // considered normal if the attribute not present
538        }
539
540        try {
541            boolean value = element.getAttribute("emptyHidden").getBooleanValue();
542            l.setEmptyHidden(value);
543        } catch (DataConversionException e) {
544            log.warn("unable to convert positionable label emptyHidden attribute");
545        } catch (NullPointerException e) {
546            // considered normal if the attribute not present
547        }
548
549        try {
550            boolean value = element.getAttribute("valueEditDisabled").getBooleanValue();
551            l.setValueEditDisabled(value);
552        } catch (DataConversionException e) {
553            log.warn("unable to convert positionable label valueEditDisabled attribute");
554        } catch (NullPointerException e) {
555            // considered normal if the attribute not present
556        }
557
558        try {
559            l.setPositionable(element.getAttribute("positionable").getBooleanValue());
560        } catch (DataConversionException e) {
561            log.warn("unable to convert positionable label positionable attribute");
562        } catch (NullPointerException e) {
563            // considered normal if the attribute not present
564        }
565        try {
566            l.setShowToolTip(element.getAttribute("showtooltip").getBooleanValue());
567        } catch (DataConversionException e) {
568            log.warn("unable to convert positionable label showtooltip attribute");
569        } catch (NullPointerException e) {
570            // considered normal if the attribute not present
571        }
572        try {
573            l.setEditable(element.getAttribute("editable").getBooleanValue());
574        } catch (DataConversionException e) {
575            log.warn("unable to convert positionable label editable attribute");
576        } catch (NullPointerException e) {
577            // considered normal if the attribute not present
578        }
579
580        Attribute a = element.getAttribute("degrees");
581        if (a != null && l instanceof PositionableLabel) {
582            try {
583                int deg = a.getIntValue();
584                ((PositionableLabel) l).setDegrees(deg);
585            } catch (org.jdom2.DataConversionException dce) {
586            }
587        }
588
589        Element elem = element.getChild("tooltip_prependWithDisplayName");
590        if (elem != null) {
591            ToolTip tip = l.getToolTip();
592            if (tip != null) {
593                tip.setPrependToolTipWithDisplayName("yes".equals(elem.getText()));
594            }
595        }
596
597        elem = element.getChild("tooltip");
598        if (elem == null) {
599            elem = element.getChild("toolTip"); // pre JMRI 3.5.2
600        }
601        if (elem != null) {
602            ToolTip tip = l.getToolTip();
603            if (tip != null) {
604                tip.setText(elem.getText());
605            }
606        }
607    }
608
609    /**
610     * Remove verbose and redundant information from fontname field
611     * unless that's been disabled in preferences
612     *
613     * @param fontname The system-specific font name with a possible trailing .plain, etc
614     * @param style  From the Font class static style values
615     * @return A font name without trailing modifiers
616     */
617    String simplifyFontname(String fontname, int style) {
618        var loadAndStorePreferences = InstanceManager.getDefault(jmri.configurexml.LoadAndStorePreferences.class);
619        if (! loadAndStorePreferences.isExcludeFontExtensions() ) { 
620            log.trace("Returning early from simplifyFontname with {}", fontname);
621            return fontname;
622        }
623
624        if (fontname.endsWith(".plain")) {
625            if (style == Font.PLAIN) {
626                return fontname.substring(0, fontname.length()-(".plain".length()));
627            } else {
628                log.warn("fontname {} is not consistent with style {}", fontname, style);
629                return fontname;
630            }
631        } else if (fontname.endsWith(".bold")) {
632            if (style == Font.BOLD) {
633                return fontname.substring(0, fontname.length()-(".bold".length()));
634            } else {
635                log.warn("fontname {} is not consistent with style {}", fontname, style);
636                return fontname;
637            }
638        } else if (fontname.endsWith(".italic")) {
639            if (style == Font.ITALIC) {
640                return fontname.substring(0, fontname.length()-(".italic".length()));
641            } else {
642                log.warn("fontname {} is not consistent with style {}", fontname, style);
643                return fontname;
644            }
645        } else if (fontname.endsWith(".bolditalic")) {
646            if (style == Font.BOLD+Font.ITALIC) {
647                return fontname.substring(0, fontname.length()-(".bolditalic".length()));
648            } else {
649                log.warn("fontname {} is not consistent with style {}", fontname, style);
650                return fontname;
651            }
652        } else {
653            return fontname;
654        }
655    }
656    
657    public NamedIcon loadIcon(PositionableLabel l, String attrName, Element element,
658            String name, Editor ed) {
659        NamedIcon icon = getNamedIcon(attrName, element, name, ed);
660        if (icon != null) {
661            try {
662                int deg = 0;
663                double scale = 1.0;
664                Element elem = element.getChild(attrName);
665                if (elem != null) {
666                    Attribute a = elem.getAttribute("degrees");
667                    if (a != null) {
668                        deg = a.getIntValue();
669                    }
670                    a = elem.getAttribute("scale");
671                    if (a != null) {
672                        scale = elem.getAttribute("scale").getDoubleValue();
673                    }
674                    icon.setLoad(deg, scale, l);
675                    if (deg == 0) {
676                        // "rotate" attribute is JMRI 2.9.3 and before
677                        a = elem.getAttribute("rotate");
678                        if (a != null) {
679                            int rotation = a.getIntValue();
680                            // 2.9.3 and before, only unscaled icons rotate
681                            if (scale == 1.0) {
682                                icon.setRotation(rotation, l);
683                            }
684                        }
685                        // "rotation" element is JMRI 2.9.4 and after
686                        Element e = elem.getChild("rotation");
687                        if (e != null) {
688                            // ver 2.9.4 allows orthogonal rotations of scaled icons
689                            int rotation = Integer.parseInt(e.getText());
690                            icon.setRotation(rotation, l);
691                        }
692                    }
693                }
694            } catch (org.jdom2.DataConversionException dce) {
695            }
696        }
697        return icon;
698    }
699
700    protected NamedIcon getNamedIcon(String childName, Element element,
701            String name, Editor ed) {
702        NamedIcon icon = null;
703        Element elem = element.getChild(childName);
704        if (elem != null) {
705            String iconName = elem.getAttribute("url").getValue();
706            icon = NamedIcon.getIconByName(iconName);
707            if (icon == null) {
708                icon = ed.loadFailed(name, iconName);
709                if (icon == null) {
710                    log.info("{} removed for url= {}", name, iconName);
711                }
712            }
713        } else {
714            log.debug("getNamedIcon: child element \"{}\" not found in element {}", childName, element.getName());
715        }
716        return icon;
717    }
718
719    public void loadLogixNG_Data(Positionable p, Element element) {
720        Element logixNG_Element = element.getChild("LogixNG");
721        if (logixNG_Element == null) return;
722        Element inlineLogixNG = logixNG_Element.getChild("InlineLogixNG_SystemName");
723        if (inlineLogixNG != null) {
724            String systemName = inlineLogixNG.getTextTrim();
725            p.setLogixNG_SystemName(systemName);
726            InstanceManager.getDefault(LogixNG_Manager.class).registerSetupTask(() -> {
727                p.setupLogixNG();
728            });
729        }
730    }
731
732    private final static Logger log = LoggerFactory.getLogger(PositionableLabelXml.class);
733}