SVGHMI: Easier way to match HMI tree elements to paths. ForEach widget now looks for paths and indexes of all items, and enforce path to be consistent with ForEach items sub widgets svghmi
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Mon, 23 Mar 2020 21:44:28 +0100
branchsvghmi
changeset 2894 4cf9ad35e6d0
parent 2893 d57a12b8f5db
child 2895 89c02b452717
SVGHMI: Easier way to match HMI tree elements to paths. ForEach widget now looks for paths and indexes of all items, and enforce path to be consistent with ForEach items sub widgets
svghmi/detachable_pages.ysl2
svghmi/gen_index_xhtml.xslt
svghmi/hmi_tree.ysl2
svghmi/widget_foreach.ysl2
--- a/svghmi/detachable_pages.ysl2	Mon Mar 23 15:13:36 2020 +0100
+++ b/svghmi/detachable_pages.ysl2	Mon Mar 23 21:44:28 2020 +0100
@@ -91,13 +91,6 @@
 const "_detachable_elements", "func:detachable_elements($hmi_pages)";
 const "detachable_elements", "$_detachable_elements[not(ancestor::*/@id = $_detachable_elements/@id)]";
 
-def "func:is_descendant_path" {
-    param "descend";
-    param "ancest";
-    result "string-length($ancest) > 0 and starts-with($descend,$ancest)";
-}
-
-
 const "forEach_widgets_ids", "$parsed_widgets/widget[@type = 'ForEach']/@id";
 const "forEach_widgets", "$hmi_elements[@id = $forEach_widgets_ids]";
 const "in_forEach_widget_ids", "func:refered_elements($forEach_widgets)[not(@id = $forEach_widgets_ids)]/@id";
--- a/svghmi/gen_index_xhtml.xslt	Mon Mar 23 15:13:36 2020 +0100
+++ b/svghmi/gen_index_xhtml.xslt	Mon Mar 23 21:44:28 2020 +0100
@@ -74,49 +74,6 @@
       </xsl:with-param>
     </xsl:apply-templates>
   </xsl:template>
-  <func:function name="func:get_hmi_tree_elt">
-    <xsl:param name="path"/>
-    <xsl:param name="root" select="$hmitree"/>
-    <xsl:message>
-      <xsl:text>get_hmi_tree_elt </xsl:text>
-      <xsl:value-of select="$path"/>
-    </xsl:message>
-    <xsl:if test="not(starts-with($path, '/'))">
-      <xsl:message terminate="yes">
-        <xsl:text>Given path "</xsl:text>
-        <xsl:value-of select="$path"/>
-        <xsl:text>" should start with a "/"</xsl:text>
-      </xsl:message>
-    </xsl:if>
-    <xsl:variable name="stripped" select="substring($path, 2)"/>
-    <xsl:variable name="token">
-      <xsl:choose>
-        <xsl:when test="contains($stripped, '/')">
-          <xsl:value-of select="substring-before($stripped, '/')"/>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:value-of select="$stripped"/>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:choose>
-      <xsl:when test="string-length($token) = 0">
-        <func:result select="$root"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:variable name="rest" select="substring-after($stripped, $token)"/>
-        <xsl:variable name="match" select="$root/*[@name = $token]"/>
-        <xsl:choose>
-          <xsl:when test="string-length($rest) &gt; 0">
-            <func:result select="func:get_hmi_tree_el($rest, $match)"/>
-          </xsl:when>
-          <xsl:otherwise>
-            <func:result select="$match"/>
-          </xsl:otherwise>
-        </xsl:choose>
-      </xsl:otherwise>
-    </xsl:choose>
-  </func:function>
   <xsl:template mode="parselabel" match="*">
     <xsl:variable name="label" select="@inkscape:label"/>
     <xsl:variable name="description" select="substring-after($label,'HMI:')"/>
@@ -185,6 +142,11 @@
     <xsl:param name="id"/>
     <func:result select="$parsed_widgets/widget[@id = $id]"/>
   </func:function>
+  <func:function name="func:is_descendant_path">
+    <xsl:param name="descend"/>
+    <xsl:param name="ancest"/>
+    <func:result select="string-length($ancest) &gt; 0 and starts-with($descend,$ancest)"/>
+  </func:function>
   <xsl:template mode="testtree" match="*">
     <xsl:param name="indent" select="''"/>
     <xsl:value-of select="$indent"/>
@@ -362,11 +324,6 @@
   </func:function>
   <xsl:variable name="_detachable_elements" select="func:detachable_elements($hmi_pages)"/>
   <xsl:variable name="detachable_elements" select="$_detachable_elements[not(ancestor::*/@id = $_detachable_elements/@id)]"/>
-  <func:function name="func:is_descendant_path">
-    <xsl:param name="descend"/>
-    <xsl:param name="ancest"/>
-    <func:result select="string-length($ancest) &gt; 0 and starts-with($descend,$ancest)"/>
-  </func:function>
   <xsl:variable name="forEach_widgets_ids" select="$parsed_widgets/widget[@type = 'ForEach']/@id"/>
   <xsl:variable name="forEach_widgets" select="$hmi_elements[@id = $forEach_widgets_ids]"/>
   <xsl:variable name="in_forEach_widget_ids" select="func:refered_elements($forEach_widgets)[not(@id = $forEach_widgets_ids)]/@id"/>
@@ -746,21 +703,28 @@
   <xsl:template mode="widget_defs" match="widget[@type='ForEach']">
     <xsl:param name="hmi_element"/>
     <xsl:variable name="widgets" select="func:refered_elements($forEach_widgets)[not(@id = $forEach_widgets_ids)]"/>
-    <xsl:text>    frequency: 2,
-</xsl:text>
-    <xsl:text>    dispatch: function(value) {
-</xsl:text>
-    <xsl:text>                    // do something
-</xsl:text>
-    <xsl:text>    },
-</xsl:text>
+    <xsl:variable name="class" select="arg[1]/@value"/>
+    <xsl:variable name="base_path" select="path/@value"/>
+    <xsl:variable name="hmi_index_base" select="$indexed_hmitree/*[@hmipath = $base_path]"/>
+    <xsl:variable name="hmi_tree_base" select="$hmitree/descendant-or-self::*[@path = $hmi_index_base/@path]"/>
+    <xsl:variable name="hmi_tree_items" select="$hmi_tree_base/*[@class = $class]"/>
+    <xsl:variable name="hmi_index_items" select="$indexed_hmitree/*[@path = $hmi_tree_items/@path]"/>
+    <xsl:variable name="items_paths" select="$hmi_index_items/@hmipath"/>
     <xsl:text>    index_pool: [
 </xsl:text>
+    <xsl:for-each select="$hmi_index_items">
+      <xsl:text>      </xsl:text>
+      <xsl:value-of select="@index"/>
+      <xsl:if test="position()!=last()">
+        <xsl:text>,</xsl:text>
+      </xsl:if>
+      <xsl:text>
+</xsl:text>
+    </xsl:for-each>
     <xsl:text>    ],
 </xsl:text>
     <xsl:text>    buttons: [
 </xsl:text>
-    <xsl:variable name="class" select="arg[1]/@value"/>
     <xsl:variable name="prefix" select="concat($class,':')"/>
     <xsl:variable name="buttons_regex" select="concat('^',$prefix,'[+\-][0-9]+')"/>
     <xsl:for-each select="$hmi_element/*[regexp:test(@inkscape:label, $buttons_regex)]">
@@ -787,19 +751,18 @@
 </xsl:text>
     <xsl:text>    items: [
 </xsl:text>
-    <xsl:variable name="base_path" select="path/@value"/>
     <xsl:variable name="items_regex" select="concat('^',$prefix,'[0-9]+')"/>
     <xsl:variable name="unordered_items" select="$hmi_element//*[regexp:test(@inkscape:label, $items_regex)]"/>
     <xsl:for-each select="$unordered_items">
       <xsl:variable name="elt_label" select="concat($prefix, string(position()))"/>
       <xsl:variable name="elt" select="$unordered_items[@inkscape:label = $elt_label]"/>
-      <xsl:text>  /* </xsl:text>
-      <xsl:apply-templates mode="testtree" select="func:get_hmi_tree_elt($base_path)"/>
-      <xsl:text> */
-</xsl:text>
-      <xsl:text>      [ /* </xsl:text>
+      <xsl:variable name="pos" select="position()"/>
+      <xsl:variable name="item_path" select="$items_paths[$pos]"/>
+      <xsl:text>      [ /* item="</xsl:text>
       <xsl:value-of select="$elt_label"/>
-      <xsl:text> */
+      <xsl:text>" path="</xsl:text>
+      <xsl:value-of select="$item_path"/>
+      <xsl:text>" */
 </xsl:text>
       <xsl:if test="count($elt)=0">
         <xsl:message terminate="yes">
@@ -810,6 +773,19 @@
         </xsl:message>
       </xsl:if>
       <xsl:for-each select="func:refered_elements($elt)[@id = $hmi_elements/@id][not(@id = $elt/@id)]">
+        <xsl:if test="not(func:is_descendant_path(func:widget(@id)/path/@value, $item_path))">
+          <xsl:message terminate="yes">
+            <xsl:text>Widget id="</xsl:text>
+            <xsl:value-of select="@id"/>
+            <xsl:text>" label="</xsl:text>
+            <xsl:value-of select="@inkscape:label"/>
+            <xsl:text>" is having wrong path. Accroding to ForEach widget ancestor id="</xsl:text>
+            <xsl:value-of select="$hmi_element/@id"/>
+            <xsl:text>", path should be descendant of </xsl:text>
+            <xsl:value-of select="$item_path"/>
+            <xsl:text>.</xsl:text>
+          </xsl:message>
+        </xsl:if>
         <xsl:text>        hmi_widgets["</xsl:text>
         <xsl:value-of select="@id"/>
         <xsl:text>"]</xsl:text>
@@ -832,13 +808,13 @@
   <xsl:template mode="widget_subscribe" match="widget[@type='ForEach']">
     <xsl:text>    sub: function(off){
 </xsl:text>
-    <xsl:text>        subscribe.call(this,off);
+    <xsl:text>        /*subscribe.call(this,off);*/
 </xsl:text>
     <xsl:text>    },
 </xsl:text>
     <xsl:text>    unsub: function(){
 </xsl:text>
-    <xsl:text>        unsubscribe.call(this);
+    <xsl:text>        /*unsubscribe.call(this);*/
 </xsl:text>
     <xsl:text>    },
 </xsl:text>
--- a/svghmi/hmi_tree.ysl2	Mon Mar 23 15:13:36 2020 +0100
+++ b/svghmi/hmi_tree.ysl2	Mon Mar 23 21:44:28 2020 +0100
@@ -52,36 +52,6 @@
     }
 }
 
-def "func:get_hmi_tree_elt" {
-    param "path";
-    param "root", "$hmitree";
-    message > get_hmi_tree_elt «$path»
-    if "not(starts-with($path, '/'))" error > Given path "«$path»" should start with a "/"
-    const "stripped", "substring($path, 2)";
-    const "token" choose {
-        when "contains($stripped, '/')" value "substring-before($stripped, '/')";
-        otherwise value "$stripped";
-    }
-
-    choose {
-        when "string-length($token) = 0"{
-            result "$root";
-        }
-        otherwise{
-            const "rest", "substring-after($stripped, $token)";
-            const "match", "$root/*[@name = $token]";
-            choose {
-                when "string-length($rest) > 0"{
-                    result "func:get_hmi_tree_el($rest, $match)";
-                }
-                otherwise{
-                    result "$match";
-                }
-            }
-        }
-    }
-}
-
 //  Parses:
 //  "HMI:WidgetType:param1:param2@path1@path2"
 //
@@ -139,6 +109,14 @@
 }
 
 
+def "func:is_descendant_path" {
+    param "descend";
+    param "ancest";
+    // TODO : use HMI tree to answer more accurately
+    result "string-length($ancest) > 0 and starts-with($descend,$ancest)";
+}
+
+
 // Debug data
 template "*", mode="testtree"{
     param "indent", "''";
--- a/svghmi/widget_foreach.ysl2	Mon Mar 23 15:13:36 2020 +0100
+++ b/svghmi/widget_foreach.ysl2	Mon Mar 23 21:44:28 2020 +0100
@@ -2,14 +2,21 @@
 template "widget[@type='ForEach']", mode="widget_defs" {
     param "hmi_element";
     const "widgets", "func:refered_elements($forEach_widgets)[not(@id = $forEach_widgets_ids)]";
-    |     frequency: 2,
-    |     dispatch: function(value) {
-    |                     // do something
-    |     },
+
+    const "class","arg[1]/@value";
+
+    const "base_path","path/@value";
+    const "hmi_index_base", "$indexed_hmitree/*[@hmipath = $base_path]";
+    const "hmi_tree_base", "$hmitree/descendant-or-self::*[@path = $hmi_index_base/@path]";
+    const "hmi_tree_items", "$hmi_tree_base/*[@class = $class]";
+    const "hmi_index_items", "$indexed_hmitree/*[@path = $hmi_tree_items/@path]"; 
+    const "items_paths", "$hmi_index_items/@hmipath"; 
     |     index_pool: [
+    foreach "$hmi_index_items" {
+    |       «@index»`if "position()!=last()" > ,`
+    }
     |     ],
     |     buttons: [
-    const "class","arg[1]/@value";
     const "prefix","concat($class,':')";
     const "buttons_regex","concat('^',$prefix,'[+\-][0-9]+')";
     foreach "$hmi_element/*[regexp:test(@inkscape:label, $buttons_regex)]" {
@@ -21,17 +28,18 @@
     |     },
 
     |     items: [
-    const "base_path","path/@value";
     const "items_regex","concat('^',$prefix,'[0-9]+')";
     const "unordered_items","$hmi_element//*[regexp:test(@inkscape:label, $items_regex)]";
     foreach "$unordered_items" {
         const "elt_label","concat($prefix, string(position()))"; 
         const "elt","$unordered_items[@inkscape:label = $elt_label]";
-        
-    |   /* `apply "func:get_hmi_tree_elt($base_path)", mode="testtree";` */
-    |       [ /* «$elt_label» */
+        const "pos","position()";
+        const "item_path", "$items_paths[$pos]";
+    |       [ /* item="«$elt_label»" path="«$item_path»" */
         if "count($elt)=0" error > Missing item labeled «$elt_label» in ForEach widget «$hmi_element/@id»
         foreach "func:refered_elements($elt)[@id = $hmi_elements/@id][not(@id = $elt/@id)]" {
+            if "not(func:is_descendant_path(func:widget(@id)/path/@value, $item_path))"
+                error > Widget id="«@id»" label="«@inkscape:label»" is having wrong path. Accroding to ForEach widget ancestor id="«$hmi_element/@id»", path should be descendant of «$item_path».
     |         hmi_widgets["«@id»"]`if "position()!=last()" > ,`
         }
     |       ]`if "position()!=last()" > ,`
@@ -42,12 +50,12 @@
 template "widget[@type='ForEach']", mode="widget_subscribe"{
     // param "hmi_element";
     |     sub: function(off){
-    |         subscribe.call(this,off);
+    |         /*subscribe.call(this,off);*/
         /* TODO */
     |     },
 
     |     unsub: function(){
-    |         unsubscribe.call(this);
+    |         /*unsubscribe.call(this);*/
         /* TODO */
     |     },
 }