2 Copyright 2008, 2009 Free Software Foundation, Inc.
3 This file is part of GNU Radio
5 GNU Radio Companion is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 GNU Radio Companion is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 from .. base import ParseXML, odict
23 from Element import Element as _Element
24 from FlowGraph import FlowGraph as _FlowGraph
25 from Connection import Connection as _Connection
26 from Block import Block as _Block
27 from Port import Port as _Port
28 from Param import Param as _Param
29 from Constants import BLOCK_TREE_DTD, FLOW_GRAPH_DTD
31 class Platform(_Element):
33 def __init__(self, name, version, key,
34 block_paths, block_dtd, default_flow_graph, generator,
35 license='', website=None, colors=[]):
37 Make a platform from the arguments.
38 @param name the platform name
39 @param version the version string
40 @param key the unique platform key
41 @param block_paths the file paths to blocks in this platform
42 @param block_dtd the dtd validator for xml block wrappers
43 @param default_flow_graph the default flow graph file path
44 @param generator the generator class for this platform
45 @param colors a list of title, color_spec tuples
46 @param license a multi-line license (first line is copyright)
47 @param website the website url for this platform
48 @return a platform object
50 _Element.__init__(self)
52 self._version = version
54 self._license = license
55 self._website = website
56 self._block_paths = block_paths
57 self._block_dtd = block_dtd
58 self._default_flow_graph = default_flow_graph
59 self._generator = generator
61 #create a dummy flow graph for the blocks
62 self._flow_graph = _Element(self)
63 #search for *.xml files in the given search path
65 for block_path in self._block_paths:
66 if os.path.isfile(block_path): xml_files.append(block_path)
67 elif os.path.isdir(block_path):
68 for dirpath, dirnames, filenames in os.walk(block_path):
69 for filename in sorted(filter(lambda f: f.endswith('.xml'), filenames)):
70 xml_files.append(os.path.join(dirpath, filename))
72 self._blocks = odict()
73 self._blocks_n = odict()
74 self._block_tree_files = list()
75 for xml_file in xml_files:
76 try: #try to add the xml file as a block wrapper
77 ParseXML.validate_dtd(xml_file, self._block_dtd)
78 n = ParseXML.from_file(xml_file).find('block')
79 #inject block wrapper path
80 n['block_wrapper_path'] = xml_file
81 block = self.Block(self._flow_graph, n)
83 #test against repeated keys
85 assert key not in self.get_block_keys()
87 self._blocks[key] = block
88 self._blocks_n[key] = n
89 except AssertionError:
90 print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s'%(key, xml_file)
91 except ParseXML.XMLSyntaxError, e:
92 try: #try to add the xml file as a block tree
93 ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD)
94 self._block_tree_files.append(xml_file)
95 except ParseXML.XMLSyntaxError, e:
96 print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file)
98 print >> sys.stderr, 'Warning: Block loading failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file)
100 def parse_flow_graph(self, flow_graph_file):
102 Parse a saved flow graph file.
103 Ensure that the file exists, and passes the dtd check.
104 @param flow_graph_file the flow graph file
106 @throws exception if the validation fails
108 flow_graph_file = flow_graph_file or self._default_flow_graph
109 open(flow_graph_file, 'r') #test open
110 ParseXML.validate_dtd(flow_graph_file, FLOW_GRAPH_DTD)
111 return ParseXML.from_file(flow_graph_file)
113 def load_block_tree(self, block_tree):
115 Load a block tree with categories and blocks.
116 Step 1: Load all blocks from the xml specification.
117 Step 2: Load blocks with builtin category specifications.
118 @param block_tree the block tree object
120 #recursive function to load categories and blocks
121 def load_category(cat_n, parent=[]):
123 parent = parent + [cat_n.find('name')]
124 block_tree.add_block(parent)
125 #recursive call to load sub categories
126 map(lambda c: load_category(c, parent), cat_n.findall('cat'))
127 #add blocks in this category
128 for block_key in cat_n.findall('block'):
129 if block_key not in self.get_block_keys():
130 print >> sys.stderr, 'Warning: Block key "%s" not found when loading category tree.'%(block_key)
132 block = self.get_block(block_key)
133 #if it exists, the block's category overrides the block tree
134 if not block.get_category(): block_tree.add_block(parent, block)
136 for block_tree_file in self._block_tree_files:
137 #recursivly add all blocks in the tree
138 load_category(ParseXML.from_file(block_tree_file).find('cat'))
139 #add all other blocks, use the catgory tag
140 for block in self.get_blocks():
141 #blocks with empty categories are in the xml block tree or hidden
142 if not block.get_category(): continue
143 block_tree.add_block(block.get_category(), block)
145 def __str__(self): return 'Platform - %s(%s)'%(self.get_key(), self.get_name())
147 def is_platform(self): return True
149 def get_new_flow_graph(self): return self.FlowGraph(self)
151 def get_generator(self): return self._generator
153 ##############################################
155 ##############################################
156 def get_block_keys(self): return self._blocks.keys()
157 def get_block(self, key): return self._blocks[key]
158 def get_blocks(self): return self._blocks.values()
159 def get_new_block(self, flow_graph, key): return self.Block(flow_graph, n=self._blocks_n[key])
161 def get_name(self): return self._name
162 def get_version(self): return self._version
163 def get_key(self): return self._key
164 def get_license(self): return self._license
165 def get_website(self): return self._website
166 def get_colors(self): return self._colors
168 ##############################################
170 ##############################################
171 FlowGraph = _FlowGraph
172 Connection = _Connection