2 Copyright 2008 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
20 from utils import expr_utils
21 from .. base.Param import Param as _Param, EntryParam
29 class FileParam(EntryParam):
30 """Provide an entry box for filename and a button to browse for a file."""
32 def __init__(self, *args, **kwargs):
33 EntryParam.__init__(self, *args, **kwargs)
34 input = gtk.Button('...')
35 input.connect('clicked', self._handle_clicked)
36 self.pack_start(input, False)
38 def _handle_clicked(self, widget=None):
40 If the button was clicked, open a file dialog in open/save format.
41 Replace the text in the entry with the new filename from the file dialog.
44 file_path = self.param.is_valid() and self.param.evaluate() or ''
45 (dirname, basename) = os.path.isfile(file_path) and os.path.split(file_path) or (file_path, '')
46 if not os.path.exists(dirname): dirname = os.getcwd() #fix bad paths
48 if self.param.get_type() == 'file_open':
49 file_dialog = gtk.FileChooserDialog('Open a Data File...', None,
50 gtk.FILE_CHOOSER_ACTION_OPEN, ('gtk-cancel',gtk.RESPONSE_CANCEL,'gtk-open',gtk.RESPONSE_OK))
51 elif self.param.get_type() == 'file_save':
52 file_dialog = gtk.FileChooserDialog('Save a Data File...', None,
53 gtk.FILE_CHOOSER_ACTION_SAVE, ('gtk-cancel',gtk.RESPONSE_CANCEL, 'gtk-save',gtk.RESPONSE_OK))
54 file_dialog.set_do_overwrite_confirmation(True)
55 file_dialog.set_current_name(basename) #show the current filename
56 file_dialog.set_current_folder(dirname) #current directory
57 file_dialog.set_select_multiple(False)
58 file_dialog.set_local_only(True)
59 if gtk.RESPONSE_OK == file_dialog.run(): #run the dialog
60 file_path = file_dialog.get_filename() #get the file path
61 self.entry.set_text(file_path)
62 self._handle_changed()
63 file_dialog.destroy() #destroy the dialog
65 #define types, native python + numpy
66 VECTOR_TYPES = (tuple, list, set, numpy.ndarray)
67 COMPLEX_TYPES = [complex, numpy.complex, numpy.complex64, numpy.complex128]
68 REAL_TYPES = [float, numpy.float, numpy.float32, numpy.float64]
69 INT_TYPES = [int, long, numpy.int, numpy.int8, numpy.int16, numpy.int32, numpy.uint64,
70 numpy.uint, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64]
71 #cast to tuple for isinstance, concat subtypes
72 COMPLEX_TYPES = tuple(COMPLEX_TYPES + REAL_TYPES + INT_TYPES)
73 REAL_TYPES = tuple(REAL_TYPES + INT_TYPES)
74 INT_TYPES = tuple(INT_TYPES)
79 _hostage_cells = list()
81 ##possible param types
82 TYPES = _Param.TYPES + [
83 'complex', 'real', 'int',
84 'complex_vector', 'real_vector', 'int_vector',
86 'file_open', 'file_save',
91 def get_input_class(self):
92 if self.get_type() in ('file_open', 'file_save'): return FileParam
93 return _Param.get_input_class(self)
97 Get the color that represents this param's type.
98 @return a hex color code.
103 'complex': Constants.COMPLEX_COLOR_SPEC,
104 'real': Constants.FLOAT_COLOR_SPEC,
105 'int': Constants.INT_COLOR_SPEC,
107 'complex_vector': Constants.COMPLEX_VECTOR_COLOR_SPEC,
108 'real_vector': Constants.FLOAT_VECTOR_COLOR_SPEC,
109 'int_vector': Constants.INT_VECTOR_COLOR_SPEC,
111 'hex': Constants.INT_COLOR_SPEC,
112 'string': Constants.BYTE_VECTOR_COLOR_SPEC,
114 'grid_pos': Constants.INT_VECTOR_COLOR_SPEC,
116 except: return _Param.get_color(self)
120 Get the hide value from the base class.
121 Hide the ID parameter for most blocks. Exceptions below.
122 If the parameter controls a port type, vlen, or nports, return part.
123 If the parameter is an empty grid position, return part.
124 These parameters are redundant to display in the flow graph view.
125 @return hide the hide property string
127 hide = _Param.get_hide(self)
129 #hide ID in non variable blocks
130 if self.get_key() == 'id' and self.get_parent().get_key() not in (
131 'variable', 'variable_slider', 'variable_chooser', 'variable_text_box', 'parameter', 'options'
133 #hide port controllers
134 if self.get_key() in ' '.join(map(
135 lambda p: ' '.join([p._type, p._vlen, p._nports]), self.get_parent().get_ports())
137 #hide empty grid positions
138 if self.get_key() == 'grid_pos' and not self.get_value(): return 'part'
144 @return evaluated type
146 self._lisitify_flag = False
147 self._stringify_flag = False
148 self._hostage_cells = list()
151 e = self.get_parent().get_parent().evaluate(v)
152 assert isinstance(e, str)
155 self._stringify_flag = True
159 #########################
161 #########################
162 if self.is_enum(): return self.get_value()
163 #########################
165 #########################
166 elif t in ('raw', 'complex', 'real', 'int', 'complex_vector', 'real_vector', 'int_vector', 'hex'):
167 #raise exception if python cannot evaluate this value
168 try: e = self.get_parent().get_parent().evaluate(v)
170 self._add_error_message('Value "%s" cannot be evaluated.'%v)
172 #raise an exception if the data is invalid
173 if t == 'raw': return e
175 try: assert(isinstance(e, COMPLEX_TYPES))
176 except AssertionError:
177 self._add_error_message('Expression "%s" is invalid for type complex.'%str(e))
181 try: assert(isinstance(e, REAL_TYPES))
182 except AssertionError:
183 self._add_error_message('Expression "%s" is invalid for type real.'%str(e))
187 try: assert(isinstance(e, INT_TYPES))
188 except AssertionError:
189 self._add_error_message('Expression "%s" is invalid for type integer.'%str(e))
192 #########################
193 # Numeric Vector Types
194 #########################
195 elif t == 'complex_vector':
196 if not isinstance(e, VECTOR_TYPES):
197 self._lisitify_flag = True
201 assert(isinstance(ei, COMPLEX_TYPES))
202 except AssertionError:
203 self._add_error_message('Expression "%s" is invalid for type complex vector.'%str(e))
206 elif t == 'real_vector':
207 if not isinstance(e, VECTOR_TYPES):
208 self._lisitify_flag = True
212 assert(isinstance(ei, REAL_TYPES))
213 except AssertionError:
214 self._add_error_message('Expression "%s" is invalid for type real vector.'%str(e))
217 elif t == 'int_vector':
218 if not isinstance(e, VECTOR_TYPES):
219 self._lisitify_flag = True
223 assert(isinstance(ei, INT_TYPES))
224 except AssertionError:
225 self._add_error_message('Expression "%s" is invalid for type integer vector.'%str(e))
230 else: raise TypeError, 'Type "%s" not handled'%t
231 #########################
233 #########################
234 elif t in ('string', 'file_open', 'file_save'):
235 #do not check if file/directory exists, that is a runtime issue
238 #########################
240 #########################
242 #can python use this as a variable?
245 assert(v[0].isalpha())
246 for c in v: assert(c.isalnum() or c in ('_',))
247 except AssertionError:
248 self._add_error_message('ID "%s" must be alpha-numeric or underscored, and begin with a letter.'%v)
250 params = self.get_all_params('id')
251 keys = [param.get_value() for param in params]
252 try: assert(len(keys) == len(set(keys)))
254 self._add_error_message('ID "%s" is not unique.'%v)
257 #########################
259 #########################
260 elif t == 'grid_pos':
261 if not v: return '' #allow for empty grid pos
262 e = self.get_parent().get_parent().evaluate(v)
264 assert(isinstance(e, (list, tuple)) and len(e) == 4)
265 for ei in e: assert(isinstance(ei, int))
266 except AssertionError:
267 self._add_error_message('A grid position must be a list of 4 integers.')
269 row, col, row_span, col_span = e
271 try: assert(row >= 0 and col >= 0)
272 except AssertionError:
273 self._add_error_message('Row and column must be non-negative.')
275 #check row span, col span
276 try: assert(row_span > 0 and col_span > 0)
277 except AssertionError:
278 self._add_error_message('Row and column span must be greater than zero.')
280 #calculate hostage cells
281 for r in range(row_span):
282 for c in range(col_span):
283 self._hostage_cells.append((row+r, col+c))
285 params = filter(lambda p: p is not self, self.get_all_params('grid_pos'))
287 for cell in param._hostage_cells:
288 if cell in self._hostage_cells:
289 self._add_error_message('Another graphical element is using cell "%s".'%str(cell))
292 #########################
294 #########################
296 n = dict() #new namespace
299 self._add_error_message('Import "%s" failed.'%v)
302 self._add_error_message('Bad import syntax: "%s".'%v)
304 return filter(lambda k: str(k) != '__builtins__', n.keys())
305 #########################
306 else: raise TypeError, 'Type "%s" not handled'%t
310 Convert the value to code.
311 @return a string representing the code
313 #run init tasks in evaluate
314 #such as setting flags
320 if t in ('string', 'file_open', 'file_save'): #string types
321 if self._stringify_flag:
322 return '"%s"'%v.replace('"', '\"')
325 elif t in ('complex_vector', 'real_vector', 'int_vector'): #vector types
326 if self._lisitify_flag:
333 def get_all_params(self, type):
335 Get all the params from the flowgraph that have the given type.
336 @param type the specified type
337 @return a list of params
339 return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_blocks()], [])