Merged changeset r9285:9377 from jblum/grc into trunk, with distcheck fixes
[debian/gnuradio] / grc / src / grc / elements / Param.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.Param
20 #Flow graph block parameters.
21 #And options for enum type paramater.
22 #@author Josh Blum
23
24 from grc import Utils
25 from grc.Utils import odict
26 from grc.elements.Element import Element
27
28 class Option(Element):
29
30         def __init__(self, param, name, key, opts):
31                 Element.__init__(self, param)
32                 self._name = name
33                 self._key = key
34                 self._opts = dict()
35                 for opt in opts:
36                         #separate the key:value
37                         try: key, value = opt.split(':')
38                         except: self._exit_with_error('Error separating "%s" into key:value'%opt)
39                         #test against repeated keys
40                         try: assert(not self._opts.has_key(key))
41                         except AssertionError: self._exit_with_error('Key "%s" already exists in option'%key)
42                         #store the option
43                         self._opts[key] = value
44
45         def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key())
46
47         def get_name(self): return self._name
48
49         def get_key(self): return self._key
50
51         ##############################################
52         # Access Opts
53         ##############################################
54         def get_opt_keys(self): return self._opts.keys()
55         def get_opt(self, key): return self._opts[key]
56         def get_opts(self): return self._opts.values()
57
58         ##############################################
59         ## Static Make Methods
60         ##############################################
61         def make_option_from_n(param, n):
62                 """
63                 Make a new option from nested data.
64                 @param param the parent element
65                 @param n the nested odict
66                 @return a new option
67                 """
68                 #grab the data
69                 name = n['name']
70                 key = n['key']
71                 opts = Utils.listify(n, 'opt')
72                 #build the option
73                 return Option(
74                         param=param,
75                         name=name,
76                         key=key,
77                         opts=opts,
78                 )
79         make_option_from_n = staticmethod(make_option_from_n)
80
81 class Param(Element):
82
83         ##possible param types
84         TYPES = ['enum', 'raw']
85
86         def __init__(self, block, n):
87                 """
88                 Make a new param from nested data.
89                 @param block the parent element
90                 @param n the nested odict
91                 @return a new param
92                 """
93                 #grab the data
94                 name = n['name']
95                 key = n['key']
96                 value = Utils.exists_or_else(n, 'value', '')
97                 type = n['type']
98                 hide = Utils.exists_or_else(n, 'hide', '')
99                 options = Utils.listify(n, 'option')
100                 #build the param
101                 Element.__init__(self, block)
102                 self._name = name
103                 self._key = key
104                 self._type = type
105                 self._hide = hide
106                 #create the Option objects from the n data
107                 self._options = odict()
108                 for option in map(lambda o: Option.make_option_from_n(self, o), options):
109                         key = option.get_key()
110                         #test against repeated keys
111                         try: assert(key not in self.get_option_keys())
112                         except AssertionError: self._exit_with_error('Key "%s" already exists in options'%key)
113                         #store the option
114                         self._options[key] = option
115                 #test the enum options
116                 if self._options or self.is_enum():
117                         #test against bad combos of type and enum
118                         try: assert(self._options)
119                         except AssertionError: self._exit_with_error('At least one option must exist when type "enum" is set.')
120                         try: assert(self.is_enum())
121                         except AssertionError: self._exit_with_error('Type "enum" must be set when options are present.')
122                         #test against options with identical keys
123                         try: assert(len(set(self.get_option_keys())) == len(self._options))
124                         except AssertionError: self._exit_with_error('Options keys "%s" are not unique.'%self.get_option_keys())
125                         #test against inconsistent keys in options
126                         opt_keys = self._options.values()[0].get_opt_keys()
127                         for option in self._options.values():
128                                 try: assert(set(opt_keys) == set(option.get_opt_keys()))
129                                 except AssertionError: self._exit_with_error('Opt keys "%s" are not identical across all options.'%opt_keys)
130                         #if a value is specified, it must be in the options keys
131                         self._value = value or self.get_option_keys()[0]
132                         try: assert(self.get_value() in self.get_option_keys())
133                         except AssertionError: self._exit_with_error('The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys()))
134                 else: self._value = value or ''
135
136         def test(self):
137                 """
138                 call test on all children
139                 """
140                 map(lambda c: c.test(), self.get_options())
141
142         def validate(self):
143                 """
144                 Validate the param.
145                 The value must be evaluated and type must a possible type.
146                 """
147                 try:
148                         assert(self.get_type() in self.TYPES)
149                         try: self.evaluate()
150                         except:
151                                 #if the evaluate failed but added no error messages, add the generic one below
152                                 if not self.get_error_messages():
153                                         self._add_error_message('Value "%s" cannot be evaluated.'%self.get_value())
154                 except AssertionError: self._add_error_message('Type "%s" is not a possible type.'%self.get_type())
155
156         def evaluate(self):
157                 """!
158                 Evaluate the value of this param.
159                 @throw NotImplementedError
160                 """
161                 raise NotImplementedError
162
163         def to_code(self):
164                 """!
165                 Convert the value to code.
166                 @throw NotImplementedError
167                 """
168                 raise NotImplementedError
169
170         def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())
171
172         def is_param(self): return True
173
174         def get_name(self): return self._name
175
176         def get_key(self): return self._key
177
178         def get_hide(self): return self.get_parent().resolve_dependencies(self._hide)
179
180         def get_value(self):
181                 value = self._value
182                 if self.is_enum() and value not in self.get_option_keys():
183                         value = self.get_option_keys()[0]
184                         self.set_value(value)
185                 return value
186
187         def set_value(self, value):
188                 self.flag()
189                 self._value = str(value) #must be a string
190
191         def get_type(self): return self.get_parent().resolve_dependencies(self._type)
192
193         def is_enum(self): return self._type == 'enum'
194
195         def is_type_dependent(self): return '$' in self._type
196
197         ##############################################
198         # Access Options
199         ##############################################
200         def get_option_keys(self): return self._options.keys()
201         def get_option(self, key): return self._options[key]
202         def get_options(self): return self._options.values()
203
204         ##############################################
205         # Access Opts
206         ##############################################
207         def get_opt_keys(self): return self._options[self.get_value()].get_opt_keys()
208         def get_opt(self, key): return self._options[self.get_value()].get_opt(key)
209         def get_opts(self): return self._options[self.get_value()].get_opts()
210
211         ##############################################
212         ## Import/Export Methods
213         ##############################################
214         def export_data(self):
215                 """
216                 Export this param's key/value.
217                 @return a nested data odict
218                 """
219                 n = odict()
220                 n['key'] = self.get_key()
221                 n['value'] = self.get_value()
222                 return n