SVGHMI: be a bit more tolerant with missing HMI paths or missing elements in widgets : continue build (with warning) and fail silently at runtime.
--- 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" && idxidx == 0){
+</xsl:text>
+ <xsl:text> d.call(widget, value, oldval);
+</xsl:text>
+ <xsl:text> }else if(typeof(d) == "object" && d.length >= 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" && idxidx == 0){
-</xsl:text>
- <xsl:text> return d.call(widget, value, oldval);
-</xsl:text>
- <xsl:text> }else if(typeof(d) == "object" && d.length >= 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')