Package pydrizzle :: Package traits102 :: Module trait_sheet
[hide private]
[frames] | no frames]

Source Code for Module pydrizzle.traits102.trait_sheet

  1  #------------------------------------------------------------------------------- 
  2  # 
  3  #  Define the set of abstract classes needed to define the notion of a 
  4  #  graphical 'trait sheet' for use with the 'traits' module. 
  5  # 
  6  #  Note: This module provides abstract definitions only. Concrete implementaions 
  7  #  are GUI toolkit specific and are provided by the following modules: 
  8  # 
  9  #     - wxtrait_sheet.py: wxPython 
 10  #     - tktrait_sheet.py: Tkinter 
 11  # 
 12  #  Written by: David C. Morrill 
 13  # 
 14  #  Date: 10/07/2002 
 15  # 
 16  #  (c) Copyright 2002 by Enthought, Inc. 
 17  # 
 18  #------------------------------------------------------------------------------- 
 19   
 20  #------------------------------------------------------------------------------- 
 21  #  Imports: 
 22  #------------------------------------------------------------------------------- 
 23  from __future__ import division # confidence high 
 24   
 25  from types          import StringType, ListType, TupleType 
 26  from trait_base     import SequenceTypes 
 27  from trait_handlers import TraitPrefixList 
 28  from traits         import Trait, HasTraits, ReadOnly 
 29  from string         import lowercase, uppercase 
 30   
 31  #------------------------------------------------------------------------------- 
 32  #  Trait definitions: 
 33  #------------------------------------------------------------------------------- 
 34   
 35  none_or_string = Trait( None, None, StringType ) 
 36   
 37  true_trait  = Trait( 'true', { 
 38                       'true':  1, 't': 1, 'yes': 1, 'y': 1, 'on':  1, 1: 1, 
 39                       'false': 0, 'f': 0, 'no':  0, 'n': 0, 'off': 0, 0: 0 
 40                       } ) 
 41   
 42  style_trait = Trait( None, None, 
 43                       TraitPrefixList( 'simple', 'custom', 'text', 'readonly' ) ) 
 44   
 45  object_trait = Trait( None, None, HasTraits ) 
 46   
 47  basic_sequence_types = [ ListType, TupleType ] 
 48   
 49  #------------------------------------------------------------------------------- 
 50  #  'TraitSheetHandler' class: 
 51  #------------------------------------------------------------------------------- 
 52   
53 -class TraitSheetHandler:
54 55 #---------------------------------------------------------------------------- 56 # Set the initial position of a trait sheet: 57 #---------------------------------------------------------------------------- 58
59 - def position ( self, trait_sheet, object ):
60 return 0
61 62 #---------------------------------------------------------------------------- 63 # Notification that a trait sheet is being closed: 64 #---------------------------------------------------------------------------- 65
66 - def close ( self, trait_sheet, object ):
67 return 1
68 69 #---------------------------------------------------------------------------- 70 # Notification that a trait sheet has modified a trait of its 71 # associated object: 72 #---------------------------------------------------------------------------- 73
74 - def changed ( self, object, trait_name, new_value, old_value, is_set ):
75 pass
76 77 #---------------------------------------------------------------------------- 78 # Create extra content to add to the trait sheet: 79 #---------------------------------------------------------------------------- 80
81 - def init ( self, trait_sheet, object ):
82 return None
83 84 # Create a default TraitSheetHandler: 85 default_trait_sheet_handler = TraitSheetHandler() 86 87 #------------------------------------------------------------------------------- 88 # 'TraitEditor' class: 89 #------------------------------------------------------------------------------- 90
91 -class TraitEditor:
92 93 #---------------------------------------------------------------------------- 94 # Interactively edit the 'trait_name' trait of 'object' in a 95 # self-contained dialog: 96 #---------------------------------------------------------------------------- 97 98 # def popup_editor ( self, object, trait_name, description, handler, 99 # parent = None ): 100 # return 0 101 102 #---------------------------------------------------------------------------- 103 # Create a simple, imbeddable text view of the current value of the 104 # 'trait_name' trait of 'object': 105 #---------------------------------------------------------------------------- 106
107 - def text_editor ( self, object, trait_name, description, handler, 108 parent ):
109 raise NotImplementedError
110 111 #---------------------------------------------------------------------------- 112 # Create a simple, imbeddable view of the current value of the 113 # 'trait_name' trait of 'object': 114 #---------------------------------------------------------------------------- 115
116 - def simple_editor ( self, object, trait_name, description, handler, 117 parent ):
118 raise NotImplementedError
119 120 #---------------------------------------------------------------------------- 121 # Create a custom, imbeddable view of the current value of the 122 # 'trait_name' trait of 'object': 123 #---------------------------------------------------------------------------- 124
125 - def custom_editor ( self, object, trait_name, description, handler, 126 parent ):
127 return self.simple_editor( object, trait_name, description, handler, 128 parent )
129 130 #---------------------------------------------------------------------------- 131 # Set a specified object trait value: 132 #---------------------------------------------------------------------------- 133
134 - def set ( self, object, trait_name, value, handler ):
135 original_value = getattr( object, trait_name ) 136 setattr( object, trait_name, value ) 137 handler.changed( object, trait_name, value, original_value, True )
138 139 #---------------------------------------------------------------------------- 140 # Return the text representation of the 'trait' trait of 'object': 141 #---------------------------------------------------------------------------- 142
143 - def str ( self, object, trait_name ):
144 return self.str_value( getattr( object, trait_name ) )
145 146 #---------------------------------------------------------------------------- 147 # Return the text representation of a specified object trait value: 148 #---------------------------------------------------------------------------- 149
150 - def str_value ( self, value ):
151 return str( value )
152 153 #------------------------------------------------------------------------------- 154 # 'TraitMonitor' class: 155 #------------------------------------------------------------------------------- 156
157 -class TraitMonitor:
158 159 #---------------------------------------------------------------------------- 160 # Initialize the object: 161 #---------------------------------------------------------------------------- 162
163 - def __init__ ( self, object, trait_name, control, on_trait_change_handler ):
164 self.control = control 165 self.on_trait_change_handler = on_trait_change_handler 166 object.on_trait_change( self.on_trait_change, trait_name )
167 168 #---------------------------------------------------------------------------- 169 # Handle an object trait being changed: 170 #---------------------------------------------------------------------------- 171
172 - def on_trait_change ( self, object, trait_name, new ):
173 try: 174 self.on_trait_change_handler( self.control, new ) 175 except: 176 # NOTE: This code handles the case where a trait editor window has 177 # been destroyed, but we don't know about it. Attempting to update the 178 # now non-existent control generates an exception. We catch it here, 179 # then disconnect the handler so it doesn't happen again: 180 object.on_trait_change( self.on_trait_change, trait_name, 181 remove = True )
182 183 #------------------------------------------------------------------------------- 184 # 'TraitGroupItem' class: 185 #------------------------------------------------------------------------------- 186
187 -class TraitGroupItem ( HasTraits ):
188 189 __traits__ = { 190 'name': none_or_string, 191 'label': none_or_string, 192 'style': style_trait, 193 'editor': Trait( None, None, TraitEditor ), 194 'object': object_trait 195 } 196 197 #---------------------------------------------------------------------------- 198 # Initialize the object: 199 #---------------------------------------------------------------------------- 200
201 - def __init__ ( self, *value, **traits ):
202 HasTraits.__init__( self, **traits ) 203 if (len( value ) == 1) and (type( value[0] ) in SequenceTypes): 204 value = value[0] 205 for data in value: 206 if type( data ) is StringType: 207 if self.name is None: 208 self.name = data 209 elif self.label is None: 210 self.label = data 211 else: 212 self.style = data 213 elif isinstance( data, TraitEditor ): 214 self.editor = data 215 else: 216 self.object = data
217 218 #--------------------------------------------------------------------------- 219 # Create a clone of the object: 220 #--------------------------------------------------------------------------- 221
222 - def clone ( self ):
223 clone = self.__class__() 224 clone.clone_traits( self ) 225 return clone
226 227 #---------------------------------------------------------------------------- 228 # Return the user interface label for a specified object's trait: 229 #---------------------------------------------------------------------------- 230
231 - def label_for ( self, object ):
232 return ( self.label or 233 (self.object or object)._base_trait( self.name ).label or 234 self.user_name_for( self.name ) )
235 236 #---------------------------------------------------------------------------- 237 # Return a 'user-friendly' name for a specified trait: 238 #---------------------------------------------------------------------------- 239
240 - def user_name_for ( self, name ):
241 name = name.replace( '_', ' ' ).capitalize() 242 result = '' 243 last_lower = 0 244 for c in name: 245 if (c in uppercase) and last_lower: 246 result += ' ' 247 last_lower = (c in lowercase) 248 result += c 249 return result
250 251 #---------------------------------------------------------------------------- 252 # Return the TraitEditor object for a specified object's trait: 253 #---------------------------------------------------------------------------- 254
255 - def editor_for ( self, object ):
256 return (self.editor or 257 (self.object or object)._base_trait( self.name ).editor)
258 259 #------------------------------------------------------------------------------- 260 # 'TraitGroup' class: 261 #------------------------------------------------------------------------------- 262
263 -class TraitGroup ( HasTraits ):
264 265 __traits__ = { 266 'values': ReadOnly, 267 'label': none_or_string, 268 'style': style_trait, 269 'orientation': Trait( 'vertical', 270 TraitPrefixList( 'vertical', 'horizontal' ) ), 271 'show_border': true_trait, 272 'show_labels': true_trait, 273 'object': object_trait 274 } 275 276 #---------------------------------------------------------------------------- 277 # Initialize the object: 278 #---------------------------------------------------------------------------- 279
280 - def __init__ ( self, *values, **traits ):
281 HasTraits.__init__( self, **traits ) 282 _values = [] 283 for value in values: 284 if (isinstance( value, TraitGroup ) or 285 isinstance( value, TraitGroupItem )): 286 _values.append( value ) 287 else: 288 _values.append( TraitGroupItem( value ) ) 289 self.values = _values
290 291 #--------------------------------------------------------------------------- 292 # Create a clone of the object: 293 #--------------------------------------------------------------------------- 294
295 - def clone ( self ):
296 clone = self.__class__() 297 clone.clone_traits( self, 298 [ 'label', 'style', 'orientation', 'show_border', 'show_labels' ] ) 299 clone_values_append = clone.values.append 300 for value in self.values: 301 clone_values_append( value.clone() ) 302 return clone
303 304 #--------------------------------------------------------------------------- 305 # Handle merging a TraitGroup with other editable traitsL 306 #--------------------------------------------------------------------------- 307
308 - def __add__ ( self, other ):
309 return merge_trait_groups( self, other )
310 311 #------------------------------------------------------------------------------- 312 # 'TraitGroupList' class: 313 #------------------------------------------------------------------------------- 314
315 -class TraitGroupList ( list ):
316 317 #--------------------------------------------------------------------------- 318 # Handle merging a TraitGroup with other editable traitsL 319 #--------------------------------------------------------------------------- 320
321 - def __add__ ( self, other ):
322 return merge_trait_groups( self, other )
323 324 #------------------------------------------------------------------------------- 325 # 'MergeTraitGroups' class: 326 #------------------------------------------------------------------------------- 327
328 -class MergeTraitGroups:
329 330 #--------------------------------------------------------------------------- 331 # Merge two trait groups: 332 #--------------------------------------------------------------------------- 333
334 - def __call__ ( self, group1, group2 ):
335 return getattr( self, '%s_%s' % ( 336 self._kind( group1 ), self._kind( group2 ) ) )( 337 group1, group2 )
338 339 #--------------------------------------------------------------------------- 340 # Return a string describing the kind of group specified: 341 #--------------------------------------------------------------------------- 342
343 - def _kind ( self, group ):
344 if isinstance( group, TraitGroup ): 345 return 'tg' 346 if (isinstance( group, TraitGroupList ) or 347 (type( group ) in basic_sequence_types)): 348 if (len( group ) == 0) or (type( group[0] ) is StringType): 349 return 'strl' 350 return 'tgl' 351 return 'str'
352 353 #--------------------------------------------------------------------------- 354 # Merge one TraitGroup into another: 355 #--------------------------------------------------------------------------- 356
357 - def _merge ( self, dest_group, src_group ):
358 values = dest_group.values 359 n = len( values ) 360 for value in src_group.values: 361 if isinstance( value, TraitGroupItem ) or (value.label is None): 362 values.append( value ) 363 else: 364 label = value.label 365 for i in range( n ): 366 merge_item = values[i] 367 if (isinstance( merge_item, TraitGroup ) and 368 (label == merge_item.label)): 369 self._merge( merge_item, value ) 370 break 371 else: 372 values.append( value )
373 374 #--------------------------------------------------------------------------- 375 # Handle the various combinations of arguments: 376 #--------------------------------------------------------------------------- 377
378 - def str_str ( self, group1, group2 ):
379 return TraitGroupList( [ group1, group2 ] )
380
381 - def str_strl ( self, group1, group2 ):
382 return TraitGroupList( [ group1 ] + group2 )
383
384 - def str_tg ( self, group1, group2 ):
385 return TraitGroupList( [ TraitGroup( group1, label = 'Main' ), 386 group2 ] )
387
388 - def str_tgl ( self, group1, group2 ):
389 return TraitGroupList( [ TraitGroup( group1, label = 'Main' ) ] + 390 group2 )
391
392 - def strl_str ( self, group1, group2 ):
393 return TraitGroupList( group1 + [ group2 ] )
394
395 - def strl_strl ( self, group1, group2 ):
396 return TraitGroupList( group1 + group2 )
397
398 - def strl_tg ( self, group1, group2 ):
399 return TraitGroupList( [ TraitGroup( label = 'Main', *group1 ), 400 group2 ] )
401
402 - def strl_tgl ( self, group1, group2 ):
403 return TraitGroupList( [ TraitGroup( label = 'Main', *group1 ) ] + 404 group2 )
405
406 - def tg_str ( self, group1, group2 ):
407 return TraitGroupList( [ group1, 408 TraitGroup( group2, label = 'Other' ) ] )
409
410 - def tg_strl ( self, group1, group2 ):
411 return TraitGroupList( [ group1, 412 TraitGroup( label = 'Other', *group2 ) ] )
413
414 - def tg_tg ( self, group1, group2 ):
415 return self.tgl_tgl( [ group1 ], [ group2 ] )
416
417 - def tg_tgl ( self, group1, group2 ):
418 return self.tgl_tgl( [ group1 ], group2 )
419
420 - def tgl_str ( self, group1, group2 ):
421 return TraitGroupList( [ group1, 422 TraitGroup( group2, name = 'Other' ) ] )
423
424 - def tgl_strl ( self, group1, group2 ):
425 return TraitGroupList( [ group1, 426 TraitGroup( name = 'Other', *group2 ) ] )
427
428 - def tgl_tg ( self, group1, group2 ):
429 return self.tgl_tgl( group1, [ group2 ] )
430
431 - def tgl_tgl ( self, group1, group2 ):
432 result = TraitGroupList() 433 page = 0 434 for group in group1: 435 group = group.clone() 436 if group.label is None: 437 page += 1 438 group.label = 'Page %d' % page 439 result.append( group ) 440 for group in group2: 441 label = group.label 442 if label is None: 443 page += 1 444 group.label = 'Page %d' % page 445 result.append( group ) 446 else: 447 for merge_group in result: 448 if label == merge_group.label: 449 self._merge( merge_group, group ) 450 break 451 else: 452 result.append( group ) 453 return result
454 455 # Create a singleton instance which can be used to merge trait groups: 456 merge_trait_groups = MergeTraitGroups() 457 458 """ 459 A trait_element is: 460 - A string (specifying a trait name) 461 - A tuple containing 1 to 3 elements: 462 - 1 string: trait name 463 - 2 strings: trait name and UI label 464 - 1 string and 1 TraitEditor: trait name and editor 465 - 2 strings and 1 TraitEditor: trait name, UI label and editor 466 467 A Trait Sheet description can be: 468 - A string (edit the single trait whose name is specified by the string) 469 - A list of trait_elements: (simple non-tabbed trait sheet, vertically 470 oriented, two-column using UI labels and simple editor) 471 - A TraitGroup (simple non-tabbed trait sheet using layout specified by 472 the TraitGroup contents) 473 - A list of TraitGroup's (Each TraitGroup defines a notebook tab, the 474 contents of which are defined by the TraitGroup's contents) 475 476 Each element passed to a TraitGroup constructor can be: 477 - A trait_element (defines a single trait to be editor) 478 - A TraitGroup (defines a nested group of traits to be edited) 479 480 Examples of Trait Sheet descriptions: 481 482 [ 'foo', 'bar', 'baz' ] 483 484 [ TraitGroup( 'foo', 'bar', 'baz', label = 'Main' ), 485 TraitGroup( 'color', 'style', 'weight', label = 'Border' ) 486 ] 487 488 [ TraitGroup( ( 'foo', 'Enter Foo' ), 489 ( 'bar', 'Enter Bar', TraitEditBar() ), 490 'baz', label = 'Main' ), 491 TraitGroup( 'color', 'style', 'weight', label = 'Border' ) 492 ] 493 494 [ TraitGroup( 495 TraitGroup( 'foo', 'bar', 'baz', 496 label = 'Group 1' ), 497 TraitGroup( 'color', 'style', 'weight', 498 label = 'Line', 499 border = 'no', 500 orientation = 'horizontal', 501 show_labels = 'no', 502 style = 'custom' ), 503 label = 'Main' ), 504 """ 505