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 for type and nports
134 if self.get_key() in ' '.join(map(
135 lambda p: ' '.join([p._type, p._nports]), self.get_parent().get_ports())
137 #hide port controllers for vlen, when == 1
138 if self.get_key() in ' '.join(map(
139 lambda p: p._vlen, self.get_parent().get_ports())
142 assert int(self.evaluate()) == 1
145 #hide empty grid positions
146 if self.get_key() == 'grid_pos' and not self.get_value(): return 'part'
152 @return evaluated type
154 self._lisitify_flag = False
155 self._stringify_flag = False
156 self._hostage_cells = list()
159 e = self.get_parent().get_parent().evaluate(v)
160 assert isinstance(e, str)
163 self._stringify_flag = True
167 #########################
169 #########################
170 if self.is_enum(): return self.get_value()
171 #########################
173 #########################
174 elif t in ('raw', 'complex', 'real', 'int', 'complex_vector', 'real_vector', 'int_vector', 'hex'):
175 #raise exception if python cannot evaluate this value
176 try: e = self.get_parent().get_parent().evaluate(v)
178 self._add_error_message('Value "%s" cannot be evaluated.'%v)
180 #raise an exception if the data is invalid
181 if t == 'raw': return e
183 try: assert(isinstance(e, COMPLEX_TYPES))
184 except AssertionError:
185 self._add_error_message('Expression "%s" is invalid for type complex.'%str(e))
189 try: assert(isinstance(e, REAL_TYPES))
190 except AssertionError:
191 self._add_error_message('Expression "%s" is invalid for type real.'%str(e))
195 try: assert(isinstance(e, INT_TYPES))
196 except AssertionError:
197 self._add_error_message('Expression "%s" is invalid for type integer.'%str(e))
200 #########################
201 # Numeric Vector Types
202 #########################
203 elif t == 'complex_vector':
204 if not isinstance(e, VECTOR_TYPES):
205 self._lisitify_flag = True
209 assert(isinstance(ei, COMPLEX_TYPES))
210 except AssertionError:
211 self._add_error_message('Expression "%s" is invalid for type complex vector.'%str(e))
214 elif t == 'real_vector':
215 if not isinstance(e, VECTOR_TYPES):
216 self._lisitify_flag = True
220 assert(isinstance(ei, REAL_TYPES))
221 except AssertionError:
222 self._add_error_message('Expression "%s" is invalid for type real vector.'%str(e))
225 elif t == 'int_vector':
226 if not isinstance(e, VECTOR_TYPES):
227 self._lisitify_flag = True
231 assert(isinstance(ei, INT_TYPES))
232 except AssertionError:
233 self._add_error_message('Expression "%s" is invalid for type integer vector.'%str(e))
238 else: raise TypeError, 'Type "%s" not handled'%t
239 #########################
241 #########################
242 elif t in ('string', 'file_open', 'file_save'):
243 #do not check if file/directory exists, that is a runtime issue
246 #########################
248 #########################
250 #can python use this as a variable?
253 assert(v[0].isalpha())
254 for c in v: assert(c.isalnum() or c in ('_',))
255 except AssertionError:
256 self._add_error_message('ID "%s" must be alpha-numeric or underscored, and begin with a letter.'%v)
258 params = self.get_all_params('id')
259 keys = [param.get_value() for param in params]
260 try: assert(len(keys) == len(set(keys)))
262 self._add_error_message('ID "%s" is not unique.'%v)
265 #########################
267 #########################
268 elif t == 'grid_pos':
269 if not v: return '' #allow for empty grid pos
270 e = self.get_parent().get_parent().evaluate(v)
272 assert(isinstance(e, (list, tuple)) and len(e) == 4)
273 for ei in e: assert(isinstance(ei, int))
274 except AssertionError:
275 self._add_error_message('A grid position must be a list of 4 integers.')
277 row, col, row_span, col_span = e
279 try: assert(row >= 0 and col >= 0)
280 except AssertionError:
281 self._add_error_message('Row and column must be non-negative.')
283 #check row span, col span
284 try: assert(row_span > 0 and col_span > 0)
285 except AssertionError:
286 self._add_error_message('Row and column span must be greater than zero.')
288 #calculate hostage cells
289 for r in range(row_span):
290 for c in range(col_span):
291 self._hostage_cells.append((row+r, col+c))
293 params = filter(lambda p: p is not self, self.get_all_params('grid_pos'))
295 for cell in param._hostage_cells:
296 if cell in self._hostage_cells:
297 self._add_error_message('Another graphical element is using cell "%s".'%str(cell))
300 #########################
302 #########################
304 n = dict() #new namespace
307 self._add_error_message('Import "%s" failed.'%v)
310 self._add_error_message('Bad import syntax: "%s".'%v)
312 return filter(lambda k: str(k) != '__builtins__', n.keys())
313 #########################
314 else: raise TypeError, 'Type "%s" not handled'%t
318 Convert the value to code.
319 @return a string representing the code
321 #run init tasks in evaluate
322 #such as setting flags
328 if t in ('string', 'file_open', 'file_save'): #string types
329 if self._stringify_flag:
330 return '"%s"'%v.replace('"', '\"')
333 elif t in ('complex_vector', 'real_vector', 'int_vector'): #vector types
334 if self._lisitify_flag:
341 def get_all_params(self, type):
343 Get all the params from the flowgraph that have the given type.
344 @param type the specified type
345 @return a list of params
347 return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_blocks()], [])