added include <cstdio> statements in several files to make it compatible with g+...
[debian/gnuradio] / grc / src / platforms / base / Param.py
1 """
2 Copyright 2008, 2009 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 ... utils import odict
21 from Element import Element
22 import pygtk
23 pygtk.require('2.0')
24 import gtk
25
26 class InputParam(gtk.HBox):
27         """The base class for an input parameter inside the input parameters dialog."""
28
29         def __init__(self, param, _handle_changed):
30                 gtk.HBox.__init__(self)
31                 self.param = param
32                 self._handle_changed = _handle_changed
33                 self.label = gtk.Label('') #no label, markup is added by set_markup
34                 self.label.set_size_request(150, -1)
35                 self.pack_start(self.label, False)
36                 self.set_markup = lambda m: self.label.set_markup(m)
37                 self.tp = None
38         def set_color(self, color): pass
39
40 class EntryParam(InputParam):
41         """Provide an entry box for strings and numbers."""
42
43         def __init__(self, *args, **kwargs):
44                 InputParam.__init__(self, *args, **kwargs)
45                 self.entry = input = gtk.Entry()
46                 input.set_text(self.param.get_value())
47                 input.connect('changed', self._handle_changed)
48                 self.pack_start(input, True)
49                 self.get_text = input.get_text
50                 #tool tip
51                 self.tp = gtk.Tooltips()
52                 self.tp.set_tip(self.entry, '')
53                 self.tp.enable()
54         def set_color(self, color): self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
55
56 class EnumParam(InputParam):
57         """Provide an entry box for Enum types with a drop down menu."""
58
59         def __init__(self, *args, **kwargs):
60                 InputParam.__init__(self, *args, **kwargs)
61                 self._input = gtk.combo_box_new_text()
62                 for option in self.param.get_options(): self._input.append_text(option.get_name())
63                 self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
64                 self._input.connect('changed', self._handle_changed)
65                 self.pack_start(self._input, False)
66         def get_text(self): return self.param.get_option_keys()[self._input.get_active()]
67
68 class EnumEntryParam(InputParam):
69         """Provide an entry box and drop down menu for Raw Enum types."""
70
71         def __init__(self, *args, **kwargs):
72                 InputParam.__init__(self, *args, **kwargs)
73                 self._input = gtk.combo_box_entry_new_text()
74                 for option in self.param.get_options(): self._input.append_text(option.get_name())
75                 try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
76                 except:
77                         self._input.set_active(-1)
78                         self._input.get_child().set_text(self.param.get_value())
79                 self._input.connect('changed', self._handle_changed)
80                 self._input.get_child().connect('changed', self._handle_changed)
81                 self.pack_start(self._input, False)
82         def get_text(self):
83                 if self._input.get_active() == -1: return self._input.get_child().get_text()
84                 return self.param.get_option_keys()[self._input.get_active()]
85         def set_color(self, color):
86                 if self._input.get_active() == -1: #custom entry, use color
87                         self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
88                 else: #from enum, make white background
89                         self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff'))
90
91 class Option(Element):
92
93         def __init__(self, param, n):
94                 Element.__init__(self, param)
95                 self._name = n.find('name')
96                 self._key = n.find('key')
97                 self._opts = dict()
98                 opts = n.findall('opt')
99                 #test against opts when non enum
100                 try: assert self.get_parent().is_enum() or not opts
101                 except AssertionError: self._exit_with_error('Options for non-enum types cannot have sub-options')
102                 #extract opts
103                 for opt in opts:
104                         #separate the key:value
105                         try: key, value = opt.split(':')
106                         except: self._exit_with_error('Error separating "%s" into key:value'%opt)
107                         #test against repeated keys
108                         try: assert not self._opts.has_key(key)
109                         except AssertionError: self._exit_with_error('Key "%s" already exists in option'%key)
110                         #store the option
111                         self._opts[key] = value
112
113         def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key())
114         def get_name(self): return self._name
115         def get_key(self): return self._key
116
117         ##############################################
118         # Access Opts
119         ##############################################
120         def get_opt_keys(self): return self._opts.keys()
121         def get_opt(self, key): return self._opts[key]
122         def get_opts(self): return self._opts.values()
123
124 class Param(Element):
125
126         ##possible param types
127         TYPES = ['enum', 'raw']
128
129         def __init__(self, block, n):
130                 """
131                 Make a new param from nested data.
132                 @param block the parent element
133                 @param n the nested odict
134                 @return a new param
135                 """
136                 #grab the data
137                 self._name = n.find('name')
138                 self._key = n.find('key')
139                 value = n.find('value') or ''
140                 self._type = n.find('type')
141                 self._hide = n.find('hide') or ''
142                 #build the param
143                 Element.__init__(self, block)
144                 #create the Option objects from the n data
145                 self._options = odict()
146                 for option in map(lambda o: Option(self, o), n.findall('option')):
147                         key = option.get_key()
148                         #test against repeated keys
149                         try: assert(key not in self.get_option_keys())
150                         except AssertionError: self._exit_with_error('Key "%s" already exists in options'%key)
151                         #store the option
152                         self._options[key] = option
153                 #test the enum options
154                 if self.is_enum():
155                         #test against options with identical keys
156                         try: assert(len(set(self.get_option_keys())) == len(self._options))
157                         except AssertionError: self._exit_with_error('Options keys "%s" are not unique.'%self.get_option_keys())
158                         #test against inconsistent keys in options
159                         opt_keys = self._options.values()[0].get_opt_keys()
160                         for option in self._options.values():
161                                 try: assert(set(opt_keys) == set(option.get_opt_keys()))
162                                 except AssertionError: self._exit_with_error('Opt keys "%s" are not identical across all options.'%opt_keys)
163                         #if a value is specified, it must be in the options keys
164                         self._value = value or self.get_option_keys()[0]
165                         try: assert(self.get_value() in self.get_option_keys())
166                         except AssertionError: self._exit_with_error('The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys()))
167                 else: self._value = value or ''
168
169         def test(self):
170                 """
171                 call test on all children
172                 """
173                 map(lambda c: c.test(), self.get_options())
174
175         def validate(self):
176                 """
177                 Validate the param.
178                 The value must be evaluated and type must a possible type.
179                 """
180                 try:
181                         assert(self.get_type() in self.TYPES)
182                         try: self.evaluate()
183                         except:
184                                 #if the evaluate failed but added no error messages, add the generic one below
185                                 if not self.get_error_messages():
186                                         self._add_error_message('Value "%s" cannot be evaluated.'%self.get_value())
187                 except AssertionError: self._add_error_message('Type "%s" is not a possible type.'%self.get_type())
188
189         def evaluate(self):
190                 """
191                 Evaluate the value of this param.
192                 @throw NotImplementedError
193                 """
194                 raise NotImplementedError
195
196         def to_code(self):
197                 """
198                 Convert the value to code.
199                 @throw NotImplementedError
200                 """
201                 raise NotImplementedError
202
203         def get_color(self): return '#FFFFFF'
204         def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())
205         def is_param(self): return True
206         def get_name(self): return self._name
207         def get_key(self): return self._key
208         def get_hide(self): return self.get_parent().resolve_dependencies(self._hide)
209
210         def get_value(self):
211                 value = self._value
212                 if self.is_enum() and value not in self.get_option_keys():
213                         value = self.get_option_keys()[0]
214                         self.set_value(value)
215                 return value
216
217         def set_value(self, value):
218                 self.flag()
219                 self._value = str(value) #must be a string
220
221         def get_type(self): return self.get_parent().resolve_dependencies(self._type)
222         def is_enum(self): return self._type == 'enum'
223
224         def __repr__(self):
225                 """
226                 Get the repr (nice string format) for this param.
227                 Just return the value (special case enum).
228                 Derived classes can handle complex formatting.
229                 @return the string representation
230                 """
231                 if self.is_enum(): return self.get_option(self.get_value()).get_name()
232                 return self.get_value()
233
234         def get_input_class(self):
235                 """
236                 Get the graphical gtk class to represent this parameter.
237                 An enum requires and combo parameter.
238                 A non-enum with options gets a combined entry/combo parameter.
239                 All others get a standard entry parameter.
240                 @return gtk input class
241                 """
242                 if self.is_enum(): return EnumParam
243                 if self.get_options(): return EnumEntryParam
244                 return EntryParam
245
246         ##############################################
247         # Access Options
248         ##############################################
249         def get_option_keys(self): return self._options.keys()
250         def get_option(self, key): return self._options[key]
251         def get_options(self): return self._options.values()
252
253         ##############################################
254         # Access Opts
255         ##############################################
256         def get_opt_keys(self): return self._options[self.get_value()].get_opt_keys()
257         def get_opt(self, key): return self._options[self.get_value()].get_opt(key)
258         def get_opts(self): return self._options[self.get_value()].get_opts()
259
260         ##############################################
261         ## Import/Export Methods
262         ##############################################
263         def export_data(self):
264                 """
265                 Export this param's key/value.
266                 @return a nested data odict
267                 """
268                 n = odict()
269                 n['key'] = self.get_key()
270                 n['value'] = self.get_value()
271                 return n