SVGHMI: be a bit more tolerant with missing HMI paths or missing elements in widgets : continue build (with warning) and fail silently at runtime. svghmi
authorEdouard Tisserant
Tue, 11 Feb 2020 13:56:48 +0100
branchsvghmi
changeset 2834 6ac6a9dff594
parent 2833 e74123b966ac
child 2835 bc666f020ab3
SVGHMI: be a bit more tolerant with missing HMI paths or missing elements in widgets : continue build (with warning) and fail silently at runtime.
XSLTransform.py
svghmi/gen_index_xhtml.xslt
svghmi/gen_index_xhtml.ysl2
svghmi/svghmi.js
svghmi/svghmi.py
--- a/XSLTransform.py	Thu Jan 30 14:33:06 2020 +0100
+++ b/XSLTransform.py	Tue Feb 11 13:56:48 2020 +0100
@@ -22,4 +22,7 @@
         # print(self.xslt.error_log)
         return res
 
+    def get_error_log(self):
+        return self.xslt.error_log
 
+
--- a/svghmi/gen_index_xhtml.xslt	Thu Jan 30 14:33:06 2020 +0100
+++ b/svghmi/gen_index_xhtml.xslt	Tue Feb 11 13:56:48 2020 +0100
@@ -230,20 +230,24 @@
       <xsl:for-each select="$widget/path">
         <xsl:variable name="hmipath" select="@value"/>
         <xsl:variable name="hmitree_match" select="$indexed_hmitree/*[@hmipath = $hmipath]"/>
-        <xsl:if test="count($hmitree_match) = 0">
-          <xsl:message terminate="yes">
-            <xsl:text>No match for path "</xsl:text>
-            <xsl:value-of select="$hmipath"/>
-            <xsl:text>" in HMI tree</xsl:text>
-          </xsl:message>
-        </xsl:if>
-        <xsl:text>        </xsl:text>
-        <xsl:value-of select="$hmitree_match/@index"/>
-        <xsl:if test="position()!=last()">
-          <xsl:text>,</xsl:text>
-        </xsl:if>
-        <xsl:text>
-</xsl:text>
+        <xsl:choose>
+          <xsl:when test="count($hmitree_match) = 0">
+            <xsl:message terminate="no">
+              <xsl:text>No match for path "</xsl:text>
+              <xsl:value-of select="$hmipath"/>
+              <xsl:text>" in HMI tree</xsl:text>
+            </xsl:message>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:text>        </xsl:text>
+            <xsl:value-of select="$hmitree_match/@index"/>
+            <xsl:if test="position()!=last()">
+              <xsl:text>,</xsl:text>
+            </xsl:if>
+            <xsl:text>
+</xsl:text>
+          </xsl:otherwise>
+        </xsl:choose>
       </xsl:for-each>
       <xsl:text>    ],
 </xsl:text>
@@ -360,32 +364,30 @@
 </xsl:text>
     <xsl:text>function dispatch_value_to_widget(widget, index, value, oldval) {
 </xsl:text>
-    <xsl:text>    let idxidx = widget.indexes.indexOf(index);
-</xsl:text>
-    <xsl:text>    if(idxidx == -1){
-</xsl:text>
-    <xsl:text>        throw new Error("Dispatching to widget not interested, should not happen.");
+    <xsl:text>    try {
+</xsl:text>
+    <xsl:text>        let idxidx = widget.indexes.indexOf(index);
+</xsl:text>
+    <xsl:text>        let d = widget.dispatch;
+</xsl:text>
+    <xsl:text>        if(typeof(d) == "function" &amp;&amp; idxidx == 0){
+</xsl:text>
+    <xsl:text>            d.call(widget, value, oldval);
+</xsl:text>
+    <xsl:text>        }else if(typeof(d) == "object" &amp;&amp; d.length &gt;= idxidx){
+</xsl:text>
+    <xsl:text>            d[idxidx].call(widget, value, oldval);
+</xsl:text>
+    <xsl:text>        }/* else dispatch_0, ..., dispatch_n ? */
+</xsl:text>
+    <xsl:text>        /*else {
+</xsl:text>
+    <xsl:text>            throw new Error("Dunno how to dispatch to widget at index = " + index);
+</xsl:text>
+    <xsl:text>        }*/
 </xsl:text>
     <xsl:text>    }
 </xsl:text>
-    <xsl:text>    let d = widget.dispatch;
-</xsl:text>
-    <xsl:text>    if(typeof(d) == "function" &amp;&amp; idxidx == 0){
-</xsl:text>
-    <xsl:text>        return d.call(widget, value, oldval);
-</xsl:text>
-    <xsl:text>    }else if(typeof(d) == "object" &amp;&amp; d.length &gt;= idxidx){
-</xsl:text>
-    <xsl:text>        return d[idxidx].call(widget, value, oldval);
-</xsl:text>
-    <xsl:text>    }/* else dispatch_0, ..., dispatch_n ? */
-</xsl:text>
-    <xsl:text>    /*else {
-</xsl:text>
-    <xsl:text>        throw new Error("Dunno how to dispatch to widget at index = " + index);
-</xsl:text>
-    <xsl:text>    }*/
-</xsl:text>
     <xsl:text>}
 </xsl:text>
     <xsl:text>
@@ -426,7 +428,17 @@
 </xsl:text>
     <xsl:text>        if(typeof(init) == "function"){
 </xsl:text>
-    <xsl:text>            return init.call(widget);
+    <xsl:text>            try {
+</xsl:text>
+    <xsl:text>                init.call(widget);
+</xsl:text>
+    <xsl:text>            } catch(err) {
+</xsl:text>
+    <xsl:text>                console.log("Widget initialization error : "+err.message);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>            }
 </xsl:text>
     <xsl:text>        }
 </xsl:text>
@@ -913,12 +925,14 @@
     <xsl:param name="labels" select="''"/>
     <xsl:param name="mandatory" select="'yes'"/>
     <xsl:param name="hmi_element"/>
+    <xsl:variable name="widget_type" select="@type"/>
     <xsl:for-each select="str:split($labels)">
       <xsl:variable name="name" select="."/>
       <xsl:variable name="elt_id" select="$hmi_element//*[@inkscape:label=$name][1]/@id"/>
       <xsl:if test="$mandatory='yes' and not($elt_id)">
-        <xsl:message terminate="yes">
-          <xsl:text>Meter widget must have a </xsl:text>
+        <xsl:message terminate="no">
+          <xsl:value-of select="$widget_type"/>
+          <xsl:text> widget must have a </xsl:text>
           <xsl:value-of select="$name"/>
           <xsl:text> element</xsl:text>
         </xsl:message>
@@ -942,7 +956,7 @@
 </xsl:text>
       </xsl:when>
       <xsl:otherwise>
-        <xsl:message terminate="yes">
+        <xsl:message terminate="no">
           <xsl:text>Display widget as a group not implemented</xsl:text>
         </xsl:message>
       </xsl:otherwise>
--- a/svghmi/gen_index_xhtml.ysl2	Thu Jan 30 14:33:06 2020 +0100
+++ b/svghmi/gen_index_xhtml.ysl2	Tue Feb 11 13:56:48 2020 +0100
@@ -227,9 +227,14 @@
             foreach "$widget/path" {
                 const "hmipath","@value";
                 const "hmitree_match","$indexed_hmitree/*[@hmipath = $hmipath]";
-                if "count($hmitree_match) = 0"
-                    error > No match for path "«$hmipath»" in HMI tree
+                choose {
+                    when "count($hmitree_match) = 0" {
+                        warning > No match for path "«$hmipath»" in HMI tree
+                    }
+                    otherwise {
             |         «$hmitree_match/@index»`if "position()!=last()" > ,`
+                    }
+                }
             }
             |     ],
             |     element: document.getElementById("«@id»"),
@@ -328,10 +333,12 @@
         param "labels","''";
         param "mandatory","'yes'";
         param "hmi_element";
+        const "widget_type","@type";
         foreach "str:split($labels)" {
             const "name",".";
             const "elt_id","$hmi_element//*[@inkscape:label=$name][1]/@id";
-            if "$mandatory='yes' and not($elt_id)" error > Meter widget must have a «$name» element
+            if "$mandatory='yes' and not($elt_id)"
+                warning > «$widget_type» widget must have a «$name» element
             | «$name»_elt: document.getElementById("«$elt_id»"),
         }
     }
@@ -347,7 +354,7 @@
         |   this.element.textContent = String(value);
             }
             otherwise {
-                error > Display widget as a group not implemented
+                warning > Display widget as a group not implemented
             }
         }
         | },
--- a/svghmi/svghmi.js	Thu Jan 30 14:33:06 2020 +0100
+++ b/svghmi/svghmi.js	Tue Feb 11 13:56:48 2020 +0100
@@ -3,19 +3,18 @@
 var cache = hmitree_types.map(_ignored => undefined);
 
 function dispatch_value_to_widget(widget, index, value, oldval) {
-    let idxidx = widget.indexes.indexOf(index);
-    if(idxidx == -1){
-        throw new Error("Dispatching to widget not interested, should not happen.");
-    }
-    let d = widget.dispatch;
-    if(typeof(d) == "function" && idxidx == 0){
-        return d.call(widget, value, oldval);
-    }else if(typeof(d) == "object" && d.length >= idxidx){
-        return d[idxidx].call(widget, value, oldval);
-    }/* else dispatch_0, ..., dispatch_n ? */
-    /*else {
-        throw new Error("Dunno how to dispatch to widget at index = " + index);
-    }*/
+    try {
+        let idxidx = widget.indexes.indexOf(index);
+        let d = widget.dispatch;
+        if(typeof(d) == "function" && idxidx == 0){
+            d.call(widget, value, oldval);
+        }else if(typeof(d) == "object" && d.length >= idxidx){
+            d[idxidx].call(widget, value, oldval);
+        }/* else dispatch_0, ..., dispatch_n ? */
+        /*else {
+            throw new Error("Dunno how to dispatch to widget at index = " + index);
+        }*/
+    }
 }
 
 function dispatch_value(index, value) {
@@ -36,7 +35,12 @@
         let widget = hmi_widgets[id];
         let init = widget.init;
         if(typeof(init) == "function"){
-            return init.call(widget);
+            try {
+                init.call(widget);
+            } catch(err) {
+                console.log("Widget initialization error : "+err.message);
+
+            }
         }
     });
 };
--- a/svghmi/svghmi.py	Thu Jan 30 14:33:06 2020 +0100
+++ b/svghmi/svghmi.py	Tue Feb 11 13:56:48 2020 +0100
@@ -475,10 +475,14 @@
             svgdom = etree.parse(svgfile)
 
             # call xslt transform on Inkscape's SVG to generate XHTML
-            try:
+            try: 
                 result = transform.transform(svgdom)
             except XSLTApplyError as e:
                 self.FatalError("SVGHMI " + view_name  + ": " + e.message)
+            finally:
+                for entry in transform.get_error_log():
+                    message = "SVGHMI: "+ entry.message + "\n" 
+                    self.GetCTRoot().logger.write_warning(message)
 
             result.write(target_file, encoding="utf-8")
             # print(str(result))
@@ -508,7 +512,7 @@
              svghmi_cmds[thing] = (
                 "Popen(" +
                 repr(shlex.split(given_command.format(port="8008", name=view_name))) +
-                ")") if given_command else "# no command given"
+                ")") if given_command else "pass # no command given"
 
         runtimefile_path = os.path.join(buildpath, "runtime_svghmi1_%s.py" % location_str)
         runtimefile = open(runtimefile_path, 'w')