port and type controller modify logic out of gui
[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                 #build the block
60                 Element.__init__(self, flow_graph)
61                 #grab the data
62                 params = utils.listify(n, 'param')
63                 sources = utils.listify(n, 'source')
64                 sinks = utils.listify(n, 'sink')
65                 self._name = n['name']
66                 self._key = n['key']
67                 self._category = utils.exists_or_else(n, 'category', '')
68                 self._block_wrapper_path = n['block_wrapper_path']
69                 #create the param objects
70                 self._params = odict()
71                 #add the id param
72                 self._params['id'] = self.get_parent().get_parent().Param(
73                         self,
74                         {
75                                 'name': 'ID',
76                                 'key': 'id',
77                                 'type': 'id',
78                         }
79                 )
80                 self._params['_enabled'] = self.get_parent().get_parent().Param(
81                         self,
82                         {
83                                 'name': 'Enabled',
84                                 'key': '_enabled',
85                                 'type': 'raw',
86                                 'value': 'True',
87                                 'hide': 'all',
88                         }
89                 )
90                 for param in map(lambda n: self.get_parent().get_parent().Param(self, n), params):
91                         key = param.get_key()
92                         #test against repeated keys
93                         try: assert(key not in self.get_param_keys())
94                         except AssertionError: self._exit_with_error('Key "%s" already exists in params'%key)
95                         #store the param
96                         self._params[key] = param
97                 #create the source objects
98                 self._sources = odict()
99                 for source in map(lambda n: self.get_parent().get_parent().Source(self, n), sources):
100                         key = source.get_key()
101                         #test against repeated keys
102                         try: assert(key not in self.get_source_keys())
103                         except AssertionError: self._exit_with_error('Key "%s" already exists in sources'%key)
104                         #store the port
105                         self._sources[key] = source
106                 #create the sink objects
107                 self._sinks = odict()
108                 for sink in map(lambda n: self.get_parent().get_parent().Sink(self, n), sinks):
109                         key = sink.get_key()
110                         #test against repeated keys
111                         try: assert(key not in self.get_sink_keys())
112                         except AssertionError: self._exit_with_error('Key "%s" already exists in sinks'%key)
113                         #store the port
114                         self._sinks[key] = sink
115                 #begin the testing
116                 self.test()
117
118         def test(self):
119                 """
120                 Call test on all children.
121                 """
122                 map(lambda c: c.test(), self.get_params() + self.get_sinks() + self.get_sources())
123
124         def get_enabled(self):
125                 """
126                 Get the enabled state of the block.
127                 @return true for enabled
128                 """
129                 try: return eval(self.get_param('_enabled').get_value())
130                 except: return True
131
132         def set_enabled(self, enabled):
133                 """
134                 Set the enabled state of the block.
135                 @param enabled true for enabled
136                 """
137                 self.get_param('_enabled').set_value(str(enabled))
138
139         def validate(self):
140                 """
141                 Validate the block.
142                 All ports and params must be valid.
143                 All checks must evaluate to true.
144                 """
145                 for c in self.get_params() + self.get_ports() + self.get_connections():
146                         try: assert(c.is_valid())
147                         except AssertionError:
148                                 for msg in c.get_error_messages():
149                                         self._add_error_message('>>> %s:\n\t%s'%(c, msg))
150
151         def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key())
152
153         def get_id(self): return self.get_param('id').get_value()
154         def is_block(self): return True
155         def get_name(self): return self._name
156         def get_key(self): return self._key
157         def get_category(self): return self._category
158         def get_doc(self): return ''
159         def get_ports(self): return self.get_sources() + self.get_sinks()
160         def get_block_wrapper_path(self): return self._block_wrapper_path
161
162         ##############################################
163         # Access Params
164         ##############################################
165         def get_param_keys(self): return self._params.keys()
166         def get_param(self, key): return self._params[key]
167         def get_params(self): return self._params.values()
168
169         ##############################################
170         # Access Sinks
171         ##############################################
172         def get_sink_keys(self): return self._sinks.keys()
173         def get_sink(self, key): return self._sinks[key]
174         def get_sinks(self): return self._sinks.values()
175
176         ##############################################
177         # Access Sources
178         ##############################################
179         def get_source_keys(self): return self._sources.keys()
180         def get_source(self, key): return self._sources[key]
181         def get_sources(self): return self._sources.values()
182
183         def get_connections(self):
184                 return sum([port.get_connections() for port in self.get_ports()], [])
185
186         def resolve_dependencies(self, tmpl):
187                 """
188                 Resolve a paramater dependency with cheetah templates.
189                 @param tmpl the string with dependencies
190                 @return the resolved value
191                 """
192                 tmpl = str(tmpl)
193                 if '$' not in tmpl: return tmpl
194                 n = dict((p.get_key(), TemplateArg(p)) for p in self.get_params())
195                 try: return str(Template(tmpl, n))
196                 except Exception, e: return "-------->\n%s: %s\n<--------"%(e, tmpl)
197
198         ##############################################
199         # Controller Modify
200         ##############################################
201         def type_controller_modify(self, direction):
202                 """
203                 Change the type controller.
204                 @param direction +1 or -1
205                 @return true for change
206                 """
207                 changed = False
208                 type_param = None
209                 for param in filter(lambda p: p.is_enum(), self.get_params()):
210                         children = self.get_ports() + self.get_params()
211                         #priority to the type controller
212                         if param.get_key() in ' '.join(map(lambda p: p._type, children)): type_param = param
213                         #use param if type param is unset
214                         if not type_param: type_param = param
215                 if type_param:
216                         #try to increment the enum by direction
217                         try:
218                                 keys = type_param.get_option_keys()
219                                 old_index = keys.index(type_param.get_value())
220                                 new_index = (old_index + direction + len(keys))%len(keys)
221                                 type_param.set_value(keys[new_index])
222                                 changed = True
223                         except: pass
224                 return changed
225
226         def port_controller_modify(self, direction):
227                 """
228                 Change the port controller.
229                 @param direction +1 or -1
230                 @return true for change
231                 """
232                 return False
233
234         ##############################################
235         ## Import/Export Methods
236         ##############################################
237         def export_data(self):
238                 """
239                 Export this block's params to nested data.
240                 @return a nested data odict
241                 """
242                 n = odict()
243                 n['key'] = self.get_key()
244                 n['param'] = map(lambda p: p.export_data(), self.get_params())
245                 return n
246
247         def import_data(self, n):
248                 """
249                 Import this block's params from nested data.
250                 Any param keys that do not exist will be ignored.
251                 @param n the nested data odict
252                 """
253                 params_n = utils.listify(n, 'param')
254                 for param_n in params_n:
255                         #key and value must exist in the n data
256                         if 'key' in param_n.keys() and 'value' in param_n.keys():
257                                 key = param_n['key']
258                                 value = param_n['value']
259                                 #the key must exist in this block's params
260                                 if key in self.get_param_keys():
261                                         self.get_param(key).set_value(value)
262                 self.validate()