@ -30,38 +30,38 @@ from IPython.utils.warn import DeprecatedClass
class _Selection ( DOMWidget ) :
""" Base class for Selection widgets
` ` value s` ` can be specified as a list or dict . If given as a list ,
` ` option s` ` can be specified as a list or dict . If given as a list ,
it will be transformed to a dict of the form ` ` { str ( value ) : value } ` ` .
"""
value = Any ( help = " Selected value " )
value_name = Unicode ( help = " The name of the selected value" , sync = True )
value s = Any ( help = """ List of (key, value) tuples or dict of values that the
selected_label = Unicode ( help = " The label of the selected value" , sync = True )
option s = Any ( help = """ List of (key, value) tuples or dict of values that the
user can select .
The keys of this list are the strings that will be displayed in the UI ,
representing the actual Python choices .
The keys of this list are also available as _ value_name s.
The keys of this list are also available as _ options_label s.
""" )
_ value s_dict = Dict ( )
_ value_name s = Tuple ( sync = True )
_ value _values = Tuple ( )
_ option s_dict = Dict ( )
_ options_label s = Tuple ( sync = True )
_ options _values = Tuple ( )
disabled = Bool ( False , help = " Enable or disable user changes " , sync = True )
description = Unicode ( help = " Description of the value this widget represents " , sync = True )
def __init__ ( self , * args , * * kwargs ) :
self . value_lock = Lock ( )
self . value s_lock = Lock ( )
self . on_trait_change ( self . _ values_readonly_changed, [ ' _values_dict ' , ' _value_names ' , ' _value_values ' , ' _value s' ] )
if ' value s' in kwargs :
self . values = kwargs . pop ( ' value s' )
self . option s_lock = Lock ( )
self . on_trait_change ( self . _ options_readonly_changed, [ ' _options_dict ' , ' _options_labels ' , ' _options_values ' , ' _option s' ] )
if ' option s' in kwargs :
self . options = kwargs . pop ( ' option s' )
DOMWidget . __init__ ( self , * args , * * kwargs )
self . _value_in_ value s( )
self . _value_in_ option s( )
def _make_ value s( self , x ) :
def _make_ option s( self , x ) :
# If x is a dict, convert it to list format.
if isinstance ( x , ( OrderedDict , dict ) ) :
return [ ( k , v ) for k , v in x . items ( ) ]
@ -70,7 +70,7 @@ class _Selection(DOMWidget):
if not isinstance ( x , ( list , tuple ) ) :
raise ValueError ( ' x ' )
# If x is an ordinary list, use the values as names.
# If x is an ordinary list, use the option values as names.
for y in x :
if not isinstance ( y , ( list , tuple ) ) or len ( y ) < 2 :
return [ ( i , i ) for i in x ]
@ -78,42 +78,42 @@ class _Selection(DOMWidget):
# Value is already in the correct format.
return x
def _ value s_changed( self , name , old , new ) :
""" Handles when the value s tuple has been changed.
def _ option s_changed( self , name , old , new ) :
""" Handles when the option s tuple has been changed.
Setting values implies setting value name s from the keys of the dict .
"""
if self . value s_lock. acquire ( False ) :
Setting options implies setting option label s from the keys of the dict .
"""
if self . option s_lock. acquire ( False ) :
try :
self . value s = new
self . option s = new
values = self . _make_value s( new )
self . _ value s_dict = { i [ 0 ] : i [ 1 ] for i in value s}
self . _ value_names = [ i [ 0 ] for i in value s]
self . _ value _values = [ i [ 1 ] for i in value s]
self . _value_in_ value s( )
options = self . _make_option s( new )
self . _ option s_dict = { i [ 0 ] : i [ 1 ] for i in option s}
self . _ options_labels = [ i [ 0 ] for i in option s]
self . _ options _values = [ i [ 1 ] for i in option s]
self . _value_in_ option s( )
finally :
self . value s_lock. release ( )
self . option s_lock. release ( )
def _value_in_ value s( self ) :
def _value_in_ option s( self ) :
# ensure that the chosen value is one of the choices
if self . _value_values :
if self . value not in self . _value_values :
self . value = next ( iter ( self . _value_values ) )
def _values_readonly_changed ( self , name , old , new ) :
if not self . values_lock . locked ( ) :
raise TraitError ( " `. %s ` is a read-only trait. Use the `.values` tuple instead. " % name )
if self . _options_values :
if self . value not in self . _options_values :
self . value = next ( iter ( self . _options_values ) )
def _options_readonly_changed ( self , name , old , new ) :
if not self . options_lock . locked ( ) :
raise TraitError ( " `. %s ` is a read-only trait. Use the `.options` tuple instead. " % name )
def _value_changed ( self , name , old , new ) :
""" Called when value has been changed """
if self . value_lock . acquire ( False ) :
try :
# Reverse dictionary lookup for the value name
for k , v in self . _value s_dict. items ( ) :
for k , v in self . _option s_dict. items ( ) :
if new == v :
# set the selected value name
self . value_name = k
self . selected_label = k
return
# undo the change, and raise KeyError
self . value = old
@ -121,11 +121,68 @@ class _Selection(DOMWidget):
finally :
self . value_lock . release ( )
def _ value_name _changed( self , name , old , new ) :
def _ selected_label _changed( self , name , old , new ) :
""" Called when the value name has been changed (typically by the frontend). """
if self . value_lock . acquire ( False ) :
try :
self . value = self . _values_dict [ new ]
self . value = self . _options_dict [ new ]
finally :
self . value_lock . release ( )
class _MultipleSelection ( _Selection ) :
""" Base class for MultipleSelection widgets.
As with ` ` _Selection ` ` , ` ` options ` ` can be specified as a list or dict . If
given as a list , it will be transformed to a dict of the form
` ` { str ( value ) : value } ` ` .
Despite their names , ` ` value ` ` ( and ` ` selected_label ` ` ) will be tuples , even
if only a single option is selected .
"""
value = Tuple ( help = " Selected values " )
selected_labels = Tuple ( help = " The labels of the selected options " ,
sync = True )
@property
def selected_label ( self ) :
raise AttributeError (
" Does not support selected_label, use selected_labels " )
def _value_in_options ( self ) :
# ensure that the chosen value is one of the choices
if self . options :
old_value = self . value or [ ]
new_value = [ ]
for value in old_value :
if value in self . _options_dict . values ( ) :
new_value . append ( value )
if new_value :
self . value = new_value
else :
self . value = [ next ( iter ( self . _options_dict . values ( ) ) ) ]
def _value_changed ( self , name , old , new ) :
""" Called when value has been changed """
if self . value_lock . acquire ( False ) :
try :
self . selected_labels = [
self . _options_labels [ self . _options_values . index ( v ) ]
for v in new
]
except :
self . value = old
raise KeyError ( new )
finally :
self . value_lock . release ( )
def _selected_labels_changed ( self , name , old , new ) :
""" Called when the selected label has been changed (typically by the
frontend ) . """
if self . value_lock . acquire ( False ) :
try :
self . value = [ self . _options_dict [ name ] for name in new ]
finally :
self . value_lock . release ( )
@ -165,6 +222,15 @@ class Select(_Selection):
_view_name = Unicode ( ' SelectView ' , sync = True )
@register ( ' IPython.SelectMultiple ' )
class SelectMultiple ( _MultipleSelection ) :
""" Listbox that allows many items to be selected at any given time.
Despite their names , inherited from ` ` _Selection ` ` , the currently chosen
option values , ` ` value ` ` , or their labels , ` ` selected_labels ` ` must both be
updated with a list - like object . """
_view_name = Unicode ( ' SelectMultipleView ' , sync = True )
# Remove in IPython 4.0
ToggleButtonsWidget = DeprecatedClass ( ToggleButtons , ' ToggleButtonsWidget ' )
DropdownWidget = DeprecatedClass ( Dropdown , ' DropdownWidget ' )