Merged r9481:9518 on jblum/grc_reorganize into trunk. Reorganized grc source under...
[debian/gnuradio] / grc / src / platforms / base / Block.py
1 """
2 Copyright 2008 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 from ... import utils
21 from ... utils import odict
22 from Element import Element
23 from Param import Param
24 from Port import Port
25
26 from Cheetah.Template import Template
27 from UserDict import UserDict
28
29 class TemplateArg(UserDict):
30         """
31         A cheetah template argument created from a param.
32         The str of this class evaluates to the param's to code method.
33         The use of this class as a dictionary (enum only) will reveal the enum opts.
34         The eval method can return the param evaluated to a raw python data type.
35         """
36
37         def __init__(self, param):
38                 UserDict.__init__(self)
39                 self._param = param
40                 if param.is_enum():
41                         for key in param.get_opt_keys():
42                                 self[key] = str(param.get_opt(key))
43
44         def __str__(self):
45                 return str(self._param.to_code())
46
47         def eval(self):
48                 return self._param.evaluate()
49
50 class Block(Element):
51
52         def __init__(self, flow_graph, n):
53                 """
54                 Make a new block from nested data.
55                 @param flow graph the parent element
56                 @param n the nested odict
57                 @return block a new block
58                 """
59                 #grab the data
60                 name = n['name']
61                 key = n['key']
62                 category = utils.exists_or_else(n, 'category', '')
63                 params = utils.listify(n, 'param')
64                 sources = utils.listify(n, 'source')
65                 sinks = utils.listify(n, 'sink')
66                 #build the block
67                 Element.__init__(self, flow_graph)
68                 #store the data
69                 self._name = name
70                 self._key = key
71                 self._category = category
72                 #create the param objects
73                 self._params = odict()
74                 #add the id param
75                 self._params['id'] = self.get_parent().get_parent().Param(
76                         self,
77                         {
78                                 'name': 'ID',
79                                 'key': 'id',
80                                 'type': 'id',
81                         }
82                 )
83                 self._params['_enabled'] = self.get_parent().get_parent().Param(
84                         self,
85                         {
86                                 'name': 'Enabled',
87                                 'key': '_enabled',
88                                 'type': 'raw',
89                                 'value': 'True',
90                                 'hide': 'all',
91                         }
92                 )
93                 for param in map(lambda n: self.get_parent().get_parent().Param(self, n), params):
94                         key = param.get_key()
95                         #test against repeated keys
96                         try: assert(key not in self.get_param_keys())
97                         except AssertionError: self._exit_with_error('Key "%s" already exists in params'%key)
98                         #store the param
99                         self._params[key] = param
100                 #create the source objects
101                 self._sources = odict()
102                 for source in map(lambda n: self.get_parent().get_parent().Source(self, n), sources):
103                         key = source.get_key()
104                         #test against repeated keys
105                         try: assert(key not in self.get_source_keys())
106                         except AssertionError: self._exit_with_error('Key "%s" already exists in sources'%key)
107                         #store the port
108                         self._sources[key] = source
109                 #create the sink objects
110                 self._sinks = odict()
111                 for sink in map(lambda n: self.get_parent().get_parent().Sink(self, n), sinks):
112                         key = sink.get_key()
113                         #test against repeated keys
114                         try: assert(key not in self.get_sink_keys())
115                         except AssertionError: self._exit_with_error('Key "%s" already exists in sinks'%key)
116                         #store the port
117                         self._sinks[key] = sink
118                 #begin the testing
119                 self.test()
120
121         def test(self):
122                 """
123                 Call test on all children.
124                 """
125                 map(lambda c: c.test(), self.get_params() + self.get_sinks() + self.get_sources())
126
127         def get_enabled(self):
128                 """
129                 Get the enabled state of the block.
130                 @return true for enabled
131                 """
132                 try: return eval(self.get_param('_enabled').get_value())
133                 except: return True
134
135         def set_enabled(self, enabled):
136                 """
137                 Set the enabled state of the block.
138                 @param enabled true for enabled
139                 """
140                 self.get_param('_enabled').set_value(str(enabled))
141
142         def validate(self):
143                 """
144                 Validate the block.
145                 All ports and params must be valid.
146                 All checks must evaluate to true.
147                 """
148                 if not self.get_enabled(): return
149                 for c in self.get_params() + self.get_sinks() + self.get_sources():
150                         try: assert(c.is_valid())
151                         except AssertionError:
152                                 for msg in c.get_error_messages():
153                                         self._add_error_message('%s: %s'%(c, msg))
154
155         def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key())
156
157         def get_id(self): return self.get_param('id').get_value()
158
159         def is_block(self): return True
160
161         def get_doc(self): return self._doc
162
163         def get_name(self): return self._name
164
165         def get_key(self): return self._key
166
167         def get_category(self): return self._category
168
169         def get_doc(self): return ''
170
171         def get_ports(self): return self.get_sources() + self.get_sinks()
172
173         ##############################################
174         # Access Params
175         ##############################################
176         def get_param_keys(self): return self._params.keys()
177         def get_param(self, key): return self._params[key]
178         def get_params(self): return self._params.values()
179
180         ##############################################
181         # Access Sinks
182         ##############################################
183         def get_sink_keys(self): return self._sinks.keys()
184         def get_sink(self, key): return self._sinks[key]
185         def get_sinks(self): return self._sinks.values()
186
187         ##############################################
188         # Access Sources
189         ##############################################
190         def get_source_keys(self): return self._sources.keys()
191         def get_source(self, key): return self._sources[key]
192         def get_sources(self): return self._sources.values()
193
194         def get_connections(self):
195                 return sum([port.get_connections() for port in self.get_ports()], [])
196
197         def resolve_dependencies(self, tmpl):
198                 """
199                 Resolve a paramater dependency with cheetah templates.
200                 @param tmpl the string with dependencies
201                 @return the resolved value
202                 """
203                 tmpl = str(tmpl)
204                 if '$' not in tmpl: return tmpl
205                 n = dict((p.get_key(), TemplateArg(p)) for p in self.get_params())
206                 try: return str(Template(tmpl, n))
207                 except Exception, e: return "-------->\n%s: %s\n<--------"%(e, tmpl)
208
209         ##############################################
210         ## Import/Export Methods
211         ##############################################
212         def export_data(self):
213                 """
214                 Export this block's params to nested data.
215                 @return a nested data odict
216                 """
217                 n = odict()
218                 n['key'] = self.get_key()
219                 n['param'] = map(lambda p: p.export_data(), self.get_params())
220                 return n
221
222         def import_data(self, n):
223                 """
224                 Import this block's params from nested data.
225                 Any param keys that do not exist will be ignored.
226                 @param n the nested data odict
227                 """
228                 params_n = utils.listify(n, 'param')
229                 for param_n in params_n:
230                         #key and value must exist in the n data
231                         if 'key' in param_n.keys() and 'value' in param_n.keys():
232                                 key = param_n['key']
233                                 value = param_n['value']
234                                 #the key must exist in this block's params
235                                 if key in self.get_param_keys():
236                                         self.get_param(key).set_value(value)
237                 self.validate()