Imported Upstream version 3.2.2
[debian/gnuradio] / grc / base / Platform.py
1 """
2 Copyright 2008, 2009 Free Software Foundation, Inc.
3 This file is part of GNU Radio
4
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.
9
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.
14
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
18 """
19
20 import os
21 import sys
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
30
31 class Platform(_Element):
32
33         def __init__(self, name, version, key,
34                 block_paths, block_dtd, default_flow_graph, generator,
35                 license='', website=None, colors=[]):
36                 """
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
49                 """
50                 _Element.__init__(self)
51                 self._name = name
52                 self._version = version
53                 self._key = key
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
60                 self._colors = colors
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
64                 xml_files = list()
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))
71                 #load the blocks
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)
82                                 key = block.get_key()
83                                 #test against repeated keys
84                                 try:
85                                         assert key not in self.get_block_keys()
86                                         #store the block
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)
97                         except Exception, e:
98                                 print >> sys.stderr, 'Warning: Block loading failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file)
99
100         def parse_flow_graph(self, flow_graph_file):
101                 """
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
105                 @return nested data
106                 @throws exception if the validation fails
107                 """
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)
112
113         def load_block_tree(self, block_tree):
114                 """
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
119                 """
120                 #recursive function to load categories and blocks
121                 def load_category(cat_n, parent=[]):
122                         #add this category
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)
131                                         continue
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)
135                 #load the block tree
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)
144
145         def __str__(self): return 'Platform - %s(%s)'%(self.get_key(), self.get_name())
146
147         def is_platform(self): return True
148
149         def get_new_flow_graph(self): return self.FlowGraph(self)
150
151         def get_generator(self): return self._generator
152
153         ##############################################
154         # Access Blocks
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])
160
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
167
168         ##############################################
169         # Constructors
170         ##############################################
171         FlowGraph = _FlowGraph
172         Connection = _Connection
173         Block = _Block
174         Source = _Port
175         Sink = _Port
176         Param = _Param