]> git.gag.com Git - debian/gnuradio/blob - grc/src/platforms/python/Param.py
moved param input
[debian/gnuradio] / grc / src / platforms / python / 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
20 from utils import expr_utils
21 from .. base.Param import Param as _Param, EntryParam
22 import Constants
23 import numpy
24 import os
25 import pygtk
26 pygtk.require('2.0')
27 import gtk
28
29 class FileParam(EntryParam):
30         """Provide an entry box for filename and a button to browse for a file."""
31
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)
37
38         def _handle_clicked(self, widget=None):
39                 """
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.
42                 """
43                 #get the paths
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
47                 #build the dialog
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
64
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)
75
76 class Param(_Param):
77
78         _init = False
79         _hostage_cells = list()
80
81         ##possible param types
82         TYPES = _Param.TYPES + [
83                 'complex', 'real', 'int',
84                 'complex_vector', 'real_vector', 'int_vector',
85                 'hex', 'string',
86                 'file_open', 'file_save',
87                 'id',
88                 'grid_pos', 'import',
89         ]
90
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)
94
95         def get_color(self):
96                 """
97                 Get the color that represents this param's type.
98                 @return a hex color code.
99                 """
100                 try:
101                         return {
102                                 #number types
103                                 'complex': Constants.COMPLEX_COLOR_SPEC,
104                                 'real': Constants.FLOAT_COLOR_SPEC,
105                                 'int': Constants.INT_COLOR_SPEC,
106                                 #vector types
107                                 'complex_vector': Constants.COMPLEX_VECTOR_COLOR_SPEC,
108                                 'real_vector': Constants.FLOAT_VECTOR_COLOR_SPEC,
109                                 'int_vector': Constants.INT_VECTOR_COLOR_SPEC,
110                                 #special
111                                 'hex': Constants.INT_COLOR_SPEC,
112                                 'string': Constants.BYTE_VECTOR_COLOR_SPEC,
113                                 'id': '#DDDDDD',
114                                 'grid_pos': Constants.INT_VECTOR_COLOR_SPEC,
115                         }[self.get_type()]
116                 except: return _Param.get_color(self)
117
118         def get_hide(self):
119                 """
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
126                 """
127                 hide = _Param.get_hide(self)
128                 if hide: return hide
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'
132                 ): return 'part'
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())
136                 ): return 'part'
137                 #hide empty grid positions
138                 if self.get_key() == 'grid_pos' and not self.get_value(): return 'part'
139                 return hide
140
141         def evaluate(self):
142                 """
143                 Evaluate the value.
144                 @return evaluated type
145                 """
146                 self._lisitify_flag = False
147                 self._stringify_flag = False
148                 self._hostage_cells = list()
149                 def eval_string(v):
150                         try:
151                                 e = self.get_parent().get_parent().evaluate(v)
152                                 assert isinstance(e, str)
153                                 return e
154                         except:
155                                 self._stringify_flag = True
156                                 return v
157                 t = self.get_type()
158                 v = self.get_value()
159                 #########################
160                 # Enum Type
161                 #########################
162                 if self.is_enum(): return self.get_value()
163                 #########################
164                 # Numeric Types
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)
169                         except:
170                                 self._add_error_message('Value "%s" cannot be evaluated.'%v)
171                                 raise Exception
172                         #raise an exception if the data is invalid
173                         if t == 'raw': return e
174                         elif t == 'complex':
175                                 try: assert(isinstance(e, COMPLEX_TYPES))
176                                 except AssertionError:
177                                         self._add_error_message('Expression "%s" is invalid for type complex.'%str(e))
178                                         raise Exception
179                                 return e
180                         elif t == 'real':
181                                 try: assert(isinstance(e, REAL_TYPES))
182                                 except AssertionError:
183                                         self._add_error_message('Expression "%s" is invalid for type real.'%str(e))
184                                         raise Exception
185                                 return e
186                         elif t == 'int':
187                                 try: assert(isinstance(e, INT_TYPES))
188                                 except AssertionError:
189                                         self._add_error_message('Expression "%s" is invalid for type integer.'%str(e))
190                                         raise Exception
191                                 return e
192                         #########################
193                         # Numeric Vector Types
194                         #########################
195                         elif t == 'complex_vector':
196                                 if not isinstance(e, VECTOR_TYPES):
197                                         self._lisitify_flag = True
198                                         e = [e]
199                                 try:
200                                         for ei in e:
201                                                 assert(isinstance(ei, COMPLEX_TYPES))
202                                 except AssertionError:
203                                         self._add_error_message('Expression "%s" is invalid for type complex vector.'%str(e))
204                                         raise Exception
205                                 return e
206                         elif t == 'real_vector':
207                                 if not isinstance(e, VECTOR_TYPES):
208                                         self._lisitify_flag = True
209                                         e = [e]
210                                 try:
211                                         for ei in e:
212                                                 assert(isinstance(ei, REAL_TYPES))
213                                 except AssertionError:
214                                         self._add_error_message('Expression "%s" is invalid for type real vector.'%str(e))
215                                         raise Exception
216                                 return e
217                         elif t == 'int_vector':
218                                 if not isinstance(e, VECTOR_TYPES):
219                                         self._lisitify_flag = True
220                                         e = [e]
221                                 try:
222                                         for ei in e:
223                                                 assert(isinstance(ei, INT_TYPES))
224                                 except AssertionError:
225                                         self._add_error_message('Expression "%s" is invalid for type integer vector.'%str(e))
226                                         raise Exception
227                                 return e
228                         elif t == 'hex':
229                                 return hex(e)
230                         else: raise TypeError, 'Type "%s" not handled'%t
231                 #########################
232                 # String Types
233                 #########################
234                 elif t in ('string', 'file_open', 'file_save'):
235                         #do not check if file/directory exists, that is a runtime issue
236                         e = eval_string(v)
237                         return str(e)
238                 #########################
239                 # Unique ID Type
240                 #########################
241                 elif t == 'id':
242                         #can python use this as a variable?
243                         try:
244                                 assert(len(v) > 0)
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)
249                                 raise Exception
250                         params = self.get_all_params('id')
251                         keys = [param.get_value() for param in params]
252                         try: assert(len(keys) == len(set(keys)))
253                         except:
254                                 self._add_error_message('ID "%s" is not unique.'%v)
255                                 raise Exception
256                         return v
257                 #########################
258                 # Grid Position Type
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)
263                         try:
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.')
268                                 raise Exception
269                         row, col, row_span, col_span = e
270                         #check row, col
271                         try: assert(row >= 0 and col >= 0)
272                         except AssertionError:
273                                 self._add_error_message('Row and column must be non-negative.')
274                                 raise Exception
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.')
279                                 raise Exception
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))
284                         #avoid collisions
285                         params = filter(lambda p: p is not self, self.get_all_params('grid_pos'))
286                         for param in params:
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))
290                                                 raise Exception
291                         return e
292                 #########################
293                 # Import Type
294                 #########################
295                 elif t == 'import':
296                         n = dict() #new namespace
297                         try: exec v in n
298                         except ImportError:
299                                 self._add_error_message('Import "%s" failed.'%v)
300                                 raise Exception
301                         except Exception:
302                                 self._add_error_message('Bad import syntax: "%s".'%v)
303                                 raise Exception
304                         return filter(lambda k: str(k) != '__builtins__', n.keys())
305                 #########################
306                 else: raise TypeError, 'Type "%s" not handled'%t
307
308         def to_code(self):
309                 """
310                 Convert the value to code.
311                 @return a string representing the code
312                 """
313                 #run init tasks in evaluate
314                 #such as setting flags
315                 if not self._init:
316                         self.evaluate()
317                         self._init = True
318                 v = self.get_value()
319                 t = self.get_type()
320                 if t in ('string', 'file_open', 'file_save'): #string types
321                         if self._stringify_flag:
322                                 return '"%s"'%v.replace('"', '\"')
323                         else:
324                                 return v
325                 elif t in ('complex_vector', 'real_vector', 'int_vector'): #vector types
326                         if self._lisitify_flag:
327                                 return '(%s, )'%v
328                         else:
329                                 return '(%s)'%v
330                 else:
331                         return v
332
333         def get_all_params(self, type):
334                 """
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
338                 """
339                 return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_blocks()], [])