2 Copyright 2008, 2009 Free Software Foundation, Inc.
3 This file is part of GNU Radio
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.
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.
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
21 from Element import Element
26 class InputParam(gtk.HBox):
27 """The base class for an input parameter inside the input parameters dialog."""
29 def __init__(self, param, _handle_changed):
30 gtk.HBox.__init__(self)
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)
38 def set_color(self, color): pass
40 class EntryParam(InputParam):
41 """Provide an entry box for strings and numbers."""
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
51 self.tp = gtk.Tooltips()
52 self.tp.set_tip(self.entry, '')
54 def set_color(self, color): self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
56 class EnumParam(InputParam):
57 """Provide an entry box for Enum types with a drop down menu."""
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()]
68 class EnumEntryParam(InputParam):
69 """Provide an entry box and drop down menu for Raw Enum types."""
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()))
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)
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'))
91 def _get_keys(lst): return [elem.get_key() for elem in lst]
92 def _get_elem(lst, key):
93 try: return lst[_get_keys(lst).index(key)]
94 except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
96 class Option(Element):
98 def __init__(self, param, n):
99 Element.__init__(self, param)
100 self._name = n.find('name')
101 self._key = n.find('key')
103 opts = n.findall('opt')
104 #test against opts when non enum
105 try: assert self.get_parent().is_enum() or not opts
106 except AssertionError: raise Exception, 'Options for non-enum types cannot have sub-options'
109 #separate the key:value
110 try: key, value = opt.split(':')
111 except: raise Exception, 'Error separating "%s" into key:value'%opt
112 #test against repeated keys
113 try: assert not self._opts.has_key(key)
114 except AssertionError: raise Exception, 'Key "%s" already exists in option'%key
116 self._opts[key] = value
118 def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key())
119 def get_name(self): return self._name
120 def get_key(self): return self._key
122 ##############################################
124 ##############################################
125 def get_opt_keys(self): return self._opts.keys()
126 def get_opt(self, key): return self._opts[key]
127 def get_opts(self): return self._opts.values()
129 class Param(Element):
131 def __init__(self, block, n, types):
133 Make a new param from nested data.
134 @param block the parent element
135 @param n the nested odict
136 @param types a list of possible types
140 self._name = n.find('name')
141 self._key = n.find('key')
142 value = n.find('value') or ''
143 self._type = n.find('type')
144 self._hide = n.find('hide') or ''
146 Element.__init__(self, block)
147 #create the Option objects from the n data
148 self._options = list()
149 for option in map(lambda o: Option(param=self, n=o), n.findall('option')):
150 key = option.get_key()
151 #test against repeated keys
152 try: assert key not in self.get_option_keys()
153 except AssertionError: raise Exception, 'Key "%s" already exists in options'%key
155 self.get_options().append(option)
156 #test the enum options
158 #test against options with identical keys
159 try: assert len(set(self.get_option_keys())) == len(self.get_options())
160 except AssertionError: raise Exception, 'Options keys "%s" are not unique.'%self.get_option_keys()
161 #test against inconsistent keys in options
162 opt_keys = self.get_options()[0].get_opt_keys()
163 for option in self.get_options():
164 try: assert set(opt_keys) == set(option.get_opt_keys())
165 except AssertionError: raise Exception, 'Opt keys "%s" are not identical across all options.'%opt_keys
166 #if a value is specified, it must be in the options keys
167 self._value = value or self.get_option_keys()[0]
168 try: assert self.get_value() in self.get_option_keys()
169 except AssertionError: raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys())
170 else: self._value = value or ''
176 call test on all children
178 map(lambda c: c.test(), self.get_options())
183 The value must be evaluated and type must a possible type.
185 Element.validate(self)
186 try: assert self.get_type() in self._types
187 except AssertionError: self.add_error_message('Type "%s" is not a possible type.'%self.get_type())
189 def get_evaluated(self): raise NotImplementedError
193 Convert the value to code.
194 @throw NotImplementedError
196 raise NotImplementedError
198 def get_color(self): return '#FFFFFF'
199 def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())
200 def is_param(self): return True
201 def get_name(self): return self._name
202 def get_key(self): return self._key
203 def get_hide(self): return self.get_parent().resolve_dependencies(self._hide).strip()
207 if self.is_enum() and value not in self.get_option_keys():
208 value = self.get_option_keys()[0]
209 self.set_value(value)
212 def set_value(self, value):
214 self._value = str(value) #must be a string
216 def get_type(self): return self.get_parent().resolve_dependencies(self._type)
217 def is_enum(self): return self._type == 'enum'
221 Get the repr (nice string format) for this param.
222 Just return the value (special case enum).
223 Derived classes can handle complex formatting.
224 @return the string representation
226 if self.is_enum(): return self.get_option(self.get_value()).get_name()
227 return self.get_value()
229 def get_input_class(self):
231 Get the graphical gtk class to represent this parameter.
232 An enum requires and combo parameter.
233 A non-enum with options gets a combined entry/combo parameter.
234 All others get a standard entry parameter.
235 @return gtk input class
237 if self.is_enum(): return EnumParam
238 if self.get_options(): return EnumEntryParam
241 ##############################################
243 ##############################################
244 def get_option_keys(self): return _get_keys(self.get_options())
245 def get_option(self, key): return _get_elem(self.get_options(), key)
246 def get_options(self): return self._options
248 ##############################################
250 ##############################################
251 def get_opt_keys(self): return self.get_option(self.get_value()).get_opt_keys()
252 def get_opt(self, key): return self.get_option(self.get_value()).get_opt(key)
253 def get_opts(self): return self.get_option(self.get_value()).get_opts()
255 ##############################################
256 ## Import/Export Methods
257 ##############################################
258 def export_data(self):
260 Export this param's key/value.
261 @return a nested data odict
264 n['key'] = self.get_key()
265 n['value'] = self.get_value()