From 1937f756fd4027ace86316fc6fb1433cd832e6eb Mon Sep 17 00:00:00 2001
From: Sebastian Koslowski <koslowski@kit.edu>
Date: Tue, 5 Apr 2016 22:03:43 +0200
Subject: grc: separate core and OOT block trees via the category of each block

Each block get assigned a module based on the root of its category.
The category is set via a block_tree.xml or else from its <category> tag.
The category root is only interpreted as module name if it is in square brackets.
Else the default module 'Others' is used.
---
 grc/core/Platform.py | 82 ++++++++++++++++++++++------------------------------
 1 file changed, 35 insertions(+), 47 deletions(-)

(limited to 'grc/core/Platform.py')

diff --git a/grc/core/Platform.py b/grc/core/Platform.py
index 5bcf79c4b2..9b25e67d65 100644
--- a/grc/core/Platform.py
+++ b/grc/core/Platform.py
@@ -67,15 +67,15 @@ class Platform(Element):
         self._flow_graph = Element(self)
         self._flow_graph.connections = []
 
-        self.blocks = None
-        self._blocks_n = None
-        self._category_trees_n = None
+        self.blocks = odict()
+        self._blocks_n = odict()
+        self._block_categories = {}
         self.domains = {}
         self.connection_templates = {}
 
         self._auto_hier_block_generate_chain = set()
 
-        self.load_blocks()
+        self.build_block_library()
 
     def __str__(self):
         return 'Platform - {}({})'.format(self.config.key, self.config.name)
@@ -133,16 +133,17 @@ class Platform(Element):
         self.load_block_xml(generator.get_file_path_xml())
         return True
 
-    def load_blocks(self):
+    def build_block_library(self):
         """load the blocks and block tree from the search paths"""
         self._docstring_extractor.start()
         # Reset
-        self.blocks = odict()
-        self._blocks_n = odict()
-        self._category_trees_n = list()
+        self.blocks.clear()
+        self._blocks_n.clear()
+        self._block_categories.clear()
         self.domains.clear()
         self.connection_templates.clear()
         ParseXML.xml_failures.clear()
+
         # Try to parse and load blocks
         for xml_file in self.iter_xml_files():
             try:
@@ -158,6 +159,19 @@ class Platform(Element):
             except Exception as e:
                 print >> sys.stderr, 'Warning: XML parsing failed:\n\t%r\n\tIgnoring: %s' % (e, xml_file)
 
+        # Add blocks to block tree
+        for key, block in self.blocks.iteritems():
+            category = self._block_categories.get(key, block.category)
+            # Blocks with empty categories are hidden
+            if not category:
+                continue
+            root = category[0]
+            if root.startswith('[') and root.endswith(']'):
+                category[0] = root[1:-1]
+            else:
+                category.insert(0, Constants.DEFAULT_BLOCK_MODULE_NAME)
+            block.category = category
+
         self._docstring_extractor.finish()
         # self._docstring_extractor.wait()
 
@@ -195,8 +209,19 @@ class Platform(Element):
     def load_category_tree_xml(self, xml_file):
         """Validate and parse category tree file and add it to list"""
         ParseXML.validate_dtd(xml_file, Constants.BLOCK_TREE_DTD)
-        n = ParseXML.from_file(xml_file).find('cat')
-        self._category_trees_n.append(n)
+        xml = ParseXML.from_file(xml_file)
+        path = []
+
+        def load_category(cat_n):
+            path.append(cat_n.find('name').strip())
+            for block_key in cat_n.findall('block'):
+                if block_key not in self._block_categories:
+                    self._block_categories[block_key] = list(path)
+            for sub_cat_n in cat_n.findall('cat'):
+                load_category(sub_cat_n)
+            path.pop()
+
+        load_category(xml.find('cat'))
 
     def load_domain_xml(self, xml_file):
         """Load a domain properties and connection templates from XML"""
@@ -241,43 +266,6 @@ class Platform(Element):
             else:
                 self.connection_templates[key] = connection_n.find('make') or ''
 
-    def load_block_tree(self, block_tree):
-        """
-        Load a block tree with categories and blocks.
-        Step 1: Load all blocks from the xml specification.
-        Step 2: Load blocks with builtin category specifications.
-
-        Args:
-            block_tree: the block tree object
-        """
-        # Recursive function to load categories and blocks
-        def load_category(cat_n, parent=None):
-            # Add this category
-            parent = (parent or []) + [cat_n.find('name')]
-            block_tree.add_block(parent)
-            # Recursive call to load sub categories
-            map(lambda c: load_category(c, parent), cat_n.findall('cat'))
-            # Add blocks in this category
-            for block_key in cat_n.findall('block'):
-                if block_key not in self.blocks:
-                    print >> sys.stderr, 'Warning: Block key "{}" not found when loading category tree.'.format(block_key)
-                    continue
-                block = self.blocks[block_key]
-                # If it exists, the block's category shall not be overridden by the xml tree
-                if not block.get_category():
-                    block.set_category(parent)
-
-        # Recursively load the category trees and update the categories for each block
-        for category_tree_n in self._category_trees_n:
-            load_category(category_tree_n)
-
-        # Add blocks to block tree
-        for block in self.blocks.itervalues():
-            # Blocks with empty categories are hidden
-            if not block.get_category():
-                continue
-            block_tree.add_block(block.get_category(), block)
-
     def _save_docstring_extraction_result(self, key, docstrings):
         docs = {}
         for match, docstring in docstrings.iteritems():
-- 
cgit v1.2.3