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