diff options
author | Sebastian Koslowski <koslowski@kit.edu> | 2016-04-05 22:03:43 +0200 |
---|---|---|
committer | Sebastian Koslowski <koslowski@kit.edu> | 2016-05-27 21:58:27 +0200 |
commit | 1937f756fd4027ace86316fc6fb1433cd832e6eb (patch) | |
tree | f4dfcf25ae5033db66484498c1864eb002c0aed3 | |
parent | cc02c4b22a2e17eddfc05863a9f17fb9a5778361 (diff) |
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.
-rw-r--r-- | grc/core/Block.py | 9 | ||||
-rw-r--r-- | grc/core/Constants.py | 1 | ||||
-rw-r--r-- | grc/core/Platform.py | 82 | ||||
-rw-r--r-- | grc/core/utils/odict.py | 4 | ||||
-rw-r--r-- | grc/gui/ActionHandler.py | 5 | ||||
-rw-r--r-- | grc/gui/BlockTreeWindow.py | 41 |
6 files changed, 68 insertions, 74 deletions
diff --git a/grc/core/Block.py b/grc/core/Block.py index f67d990857..8a683a2b6b 100644 --- a/grc/core/Block.py +++ b/grc/core/Block.py @@ -79,7 +79,8 @@ class Block(Element): sinks = n.findall('sink') self._name = n.find('name') self._key = n.find('key') - self._category = n.find('category') or '' + category = (n.find('category') or '').split('/') + self.category = [cat.strip() for cat in category if cat.strip()] self._flags = n.find('flags') or '' # Backwards compatibility if n.find('throttle') and BLOCK_FLAG_THROTTLE not in self._flags: @@ -594,12 +595,6 @@ class Block(Element): def get_key(self): return self._key - def get_category(self): - return self._category - - def set_category(self, cat): - self._category = cat - def get_ports(self): return self.get_sources() + self.get_sinks() diff --git a/grc/core/Constants.py b/grc/core/Constants.py index 462049cc73..eeb1d7f848 100644 --- a/grc/core/Constants.py +++ b/grc/core/Constants.py @@ -37,6 +37,7 @@ FLOW_GRAPH_FILE_FORMAT_VERSION = 1 # Param tabs DEFAULT_PARAM_TAB = "General" ADVANCED_PARAM_TAB = "Advanced" +DEFAULT_BLOCK_MODULE_NAME = '(no module specified)' # Port domains GR_STREAM_DOMAIN = "gr_stream" 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(): diff --git a/grc/core/utils/odict.py b/grc/core/utils/odict.py index 20970e947c..85927e869f 100644 --- a/grc/core/utils/odict.py +++ b/grc/core/utils/odict.py @@ -109,3 +109,7 @@ class odict(DictMixin): if isinstance(obj, list): return obj return [obj] + + def clear(self): + self._data.clear() + del self._keys[:]
\ No newline at end of file diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 2b39079f76..11e81c4613 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -607,9 +607,8 @@ class ActionHandler: elif action == Actions.PAGE_CHANGE: # pass and run the global actions pass elif action == Actions.RELOAD_BLOCKS: - self.platform.load_blocks() - main.btwin.clear() - self.platform.load_block_tree(main.btwin) + self.platform.build_block_library() + main.btwin.repopulate() Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(bool( ParseXML.xml_failures)) Messages.send_xml_errors_if_any(ParseXML.xml_failures) diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py index 4279e8c61d..6ba5144fa4 100644 --- a/grc/gui/BlockTreeWindow.py +++ b/grc/gui/BlockTreeWindow.py @@ -124,33 +124,42 @@ class BlockTreeWindow(gtk.VBox): # map categories to iters, automatic mapping for root self._categories = {tuple(): None} self._categories_search = {tuple(): None} - # add blocks and categories - self.platform.load_block_tree(self) self.platform.block_docstrings_loaded_callback = self.update_docs + self.repopulate() def clear(self): - self.treestore.clear(); - self._categories = {tuple(): None} + self.treestore.clear() + self._categories = {(): None} + + def repopulate(self): + self.clear() + for block in self.platform.blocks.itervalues(): + if block.category: + self.add_block(block) + self.expand_module_in_tree() + + def expand_module_in_tree(self, module_name='Core'): + self.treeview.collapse_all() + core_module_iter = self._categories.get((module_name,)) + if core_module_iter: + self.treeview.expand_row(self.treestore.get_path(core_module_iter), False) ############################################################ ## Block Tree Methods ############################################################ - def add_block(self, category, block=None, treestore=None, categories=None): + def add_block(self, block, treestore=None, categories=None): """ Add a block with category to this selection window. Add only the category when block is None. Args: - category: the category list or path string block: the block object or None """ - if treestore is None: - treestore = self.treestore - if categories is None: - categories = self._categories + treestore = treestore or self.treestore + categories = categories or self._categories + + category = tuple(filter(str, block.category)) # tuple is hashable, remove empty cats - if isinstance(category, (str, unicode)): category = category.split('/') - category = tuple(filter(lambda x: x, category)) # tuple is hashable # add category and all sub categories for i, cat_name in enumerate(category): sub_category = category[:i+1] @@ -160,9 +169,8 @@ class BlockTreeWindow(gtk.VBox): treestore.set_value(iter_, KEY_INDEX, '') treestore.set_value(iter_, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name)) categories[sub_category] = iter_ + # add block - if block is None: - return iter_ = treestore.insert_before(categories[category], None) treestore.set_value(iter_, NAME_INDEX, block.get_name()) treestore.set_value(iter_, KEY_INDEX, block.get_key()) @@ -226,7 +234,7 @@ class BlockTreeWindow(gtk.VBox): key = widget.get_text().lower() if not key: self.treeview.set_model(self.treestore) - self.treeview.collapse_all() + self.expand_module_in_tree() else: matching_blocks = filter(lambda b: key in b.get_key().lower() or key in b.get_name().lower(), self.platform.blocks.values()) @@ -234,8 +242,7 @@ class BlockTreeWindow(gtk.VBox): self.treestore_search.clear() self._categories_search = {tuple(): None} for block in matching_blocks: - self.add_block(block.get_category() or 'None', block, - self.treestore_search, self._categories_search) + self.add_block(block, self.treestore_search, self._categories_search) self.treeview.set_model(self.treestore_search) self.treeview.expand_all() |