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