##// END OF EJS Templates
Fix readonly lock logic.
Jonathan Frederic -
Show More
@@ -1,171 +1,169 b''
1 """Selection classes.
1 """Selection classes.
2
2
3 Represents an enumeration using a widget.
3 Represents an enumeration using a widget.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from collections import OrderedDict
17 from collections import OrderedDict
18 from threading import Lock
18 from threading import Lock
19
19
20 from .widget import DOMWidget, register
20 from .widget import DOMWidget, register
21 from IPython.utils.traitlets import (
21 from IPython.utils.traitlets import (
22 Unicode, Bool, Any, Dict, TraitError, CaselessStrEnum, Tuple
22 Unicode, Bool, Any, Dict, TraitError, CaselessStrEnum, Tuple
23 )
23 )
24 from IPython.utils.py3compat import unicode_type
24 from IPython.utils.py3compat import unicode_type
25 from IPython.utils.warn import DeprecatedClass
25 from IPython.utils.warn import DeprecatedClass
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # SelectionWidget
28 # SelectionWidget
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 class _Selection(DOMWidget):
30 class _Selection(DOMWidget):
31 """Base class for Selection widgets
31 """Base class for Selection widgets
32
32
33 ``values`` can be specified as a list or dict. If given as a list,
33 ``values`` can be specified as a list or dict. If given as a list,
34 it will be transformed to a dict of the form ``{str(value):value}``.
34 it will be transformed to a dict of the form ``{str(value):value}``.
35 """
35 """
36
36
37 value = Any(help="Selected value")
37 value = Any(help="Selected value")
38 value_name = Unicode(help="The name of the selected value", sync=True)
38 value_name = Unicode(help="The name of the selected value", sync=True)
39 values = Any(sync=True, help="""List of (key, value) tuples the user can select.
39 values = Any(sync=True, help="""List of (key, value) tuples the user can select.
40
40
41 The keys of this list are the strings that will be displayed in the UI,
41 The keys of this list are the strings that will be displayed in the UI,
42 representing the actual Python choices.
42 representing the actual Python choices.
43
43
44 The keys of this list are also available as value_names.
44 The keys of this list are also available as value_names.
45 """)
45 """)
46
46
47 values_dict = Dict()
47 values_dict = Dict()
48 values_names = Tuple(sync=True)
48 values_names = Tuple(sync=True)
49 values_values = Tuple()
49 values_values = Tuple()
50
50
51 disabled = Bool(False, help="Enable or disable user changes", sync=True)
51 disabled = Bool(False, help="Enable or disable user changes", sync=True)
52 description = Unicode(help="Description of the value this widget represents", sync=True)
52 description = Unicode(help="Description of the value this widget represents", sync=True)
53
53
54 def __init__(self, *args, **kwargs):
54 def __init__(self, *args, **kwargs):
55 self.value_lock = Lock()
55 self.value_lock = Lock()
56 self.values_lock = Lock()
56 self.values_lock = Lock()
57 self.on_trait_change(self._values_readonly_changed, ['values_dict', 'values_names', 'values_values', '_values'])
57 self.on_trait_change(self._values_readonly_changed, ['values_dict', 'values_names', 'values_values', '_values'])
58 if 'values' in kwargs:
58 if 'values' in kwargs:
59 self.values = kwargs.pop('values')
59 self.values = kwargs.pop('values')
60 DOMWidget.__init__(self, *args, **kwargs)
60 DOMWidget.__init__(self, *args, **kwargs)
61 self._value_in_values()
61 self._value_in_values()
62
62
63 def _make_values(self, x):
63 def _make_values(self, x):
64 # If x is a dict, convert it to list format.
64 # If x is a dict, convert it to list format.
65 if isinstance(x, (OrderedDict, dict)):
65 if isinstance(x, (OrderedDict, dict)):
66 return [(k, v) for k, v in x.items()]
66 return [(k, v) for k, v in x.items()]
67
67
68 # Make sure x is a list or tuple.
68 # Make sure x is a list or tuple.
69 if not isinstance(x, (list, tuple)):
69 if not isinstance(x, (list, tuple)):
70 raise ValueError('x')
70 raise ValueError('x')
71
71
72 # If x is an ordinary list, use the values as names.
72 # If x is an ordinary list, use the values as names.
73 for y in x:
73 for y in x:
74 if not isinstance(y, (list, tuple)) or len(y) < 2:
74 if not isinstance(y, (list, tuple)) or len(y) < 2:
75 return [(i, i) for i in x]
75 return [(i, i) for i in x]
76
76
77 # Value is already in the correct format.
77 # Value is already in the correct format.
78 return x
78 return x
79
79
80 def _values_changed(self, name, old, new):
80 def _values_changed(self, name, old, new):
81 """Handles when the values tuple has been changed.
81 """Handles when the values tuple has been changed.
82
82
83 Setting values implies setting value names from the keys of the dict.
83 Setting values implies setting value names from the keys of the dict.
84 """
84 """
85 if self.values_lock.acquire(False):
85 if self.values_lock.acquire(False):
86 try:
86 try:
87 self.values = self._make_values(new)
87 self.values = self._make_values(new)
88 self.values_dict = {i[0]: i[1] for i in self.values}
88 self.values_dict = {i[0]: i[1] for i in self.values}
89 self.values_names = [i[0] for i in self.values]
89 self.values_names = [i[0] for i in self.values]
90 self.values_values = [i[1] for i in self.values]
90 self.values_values = [i[1] for i in self.values]
91 self._value_in_values()
91 self._value_in_values()
92 finally:
92 finally:
93 self.values_lock.release()
93 self.values_lock.release()
94
94
95 def _value_in_values(self):
95 def _value_in_values(self):
96 # ensure that the chosen value is one of the choices
96 # ensure that the chosen value is one of the choices
97 if self.values_values:
97 if self.values_values:
98 if self.value not in self.values_values:
98 if self.value not in self.values_values:
99 self.value = next(iter(self.values_values))
99 self.value = next(iter(self.values_values))
100
100
101 def _values_readonly_changed(self, name, old, new):
101 def _values_readonly_changed(self, name, old, new):
102 if not self.values_lock.acquire(False):
102 if not self.values_lock.locked():
103 raise TraitError("`.%s` is a read-only trait. Use the `.values` tuple instead." % name)
103 raise TraitError("`.%s` is a read-only trait. Use the `.values` tuple instead." % name)
104 else:
105 self.values_lock.release()
106
104
107 def _value_changed(self, name, old, new):
105 def _value_changed(self, name, old, new):
108 """Called when value has been changed"""
106 """Called when value has been changed"""
109 if self.value_lock.acquire(False):
107 if self.value_lock.acquire(False):
110 try:
108 try:
111 # Reverse dictionary lookup for the value name
109 # Reverse dictionary lookup for the value name
112 for k,v in self.values_dict.items():
110 for k,v in self.values_dict.items():
113 if new == v:
111 if new == v:
114 # set the selected value name
112 # set the selected value name
115 self.value_name = k
113 self.value_name = k
116 return
114 return
117 # undo the change, and raise KeyError
115 # undo the change, and raise KeyError
118 self.value = old
116 self.value = old
119 raise KeyError(new)
117 raise KeyError(new)
120 finally:
118 finally:
121 self.value_lock.release()
119 self.value_lock.release()
122
120
123 def _value_name_changed(self, name, old, new):
121 def _value_name_changed(self, name, old, new):
124 """Called when the value name has been changed (typically by the frontend)."""
122 """Called when the value name has been changed (typically by the frontend)."""
125 if self.value_lock.acquire(False):
123 if self.value_lock.acquire(False):
126 try:
124 try:
127 self.value = self.values_dict[new]
125 self.value = self.values_dict[new]
128 finally:
126 finally:
129 self.value_lock.release()
127 self.value_lock.release()
130
128
131
129
132 @register('IPython.ToggleButtons')
130 @register('IPython.ToggleButtons')
133 class ToggleButtons(_Selection):
131 class ToggleButtons(_Selection):
134 """Group of toggle buttons that represent an enumeration. Only one toggle
132 """Group of toggle buttons that represent an enumeration. Only one toggle
135 button can be toggled at any point in time."""
133 button can be toggled at any point in time."""
136 _view_name = Unicode('ToggleButtonsView', sync=True)
134 _view_name = Unicode('ToggleButtonsView', sync=True)
137
135
138 button_style = CaselessStrEnum(
136 button_style = CaselessStrEnum(
139 values=['primary', 'success', 'info', 'warning', 'danger', ''],
137 values=['primary', 'success', 'info', 'warning', 'danger', ''],
140 default_value='', allow_none=True, sync=True, help="""Use a
138 default_value='', allow_none=True, sync=True, help="""Use a
141 predefined styling for the buttons.""")
139 predefined styling for the buttons.""")
142
140
143 @register('IPython.Dropdown')
141 @register('IPython.Dropdown')
144 class Dropdown(_Selection):
142 class Dropdown(_Selection):
145 """Allows you to select a single item from a dropdown."""
143 """Allows you to select a single item from a dropdown."""
146 _view_name = Unicode('DropdownView', sync=True)
144 _view_name = Unicode('DropdownView', sync=True)
147
145
148 button_style = CaselessStrEnum(
146 button_style = CaselessStrEnum(
149 values=['primary', 'success', 'info', 'warning', 'danger', ''],
147 values=['primary', 'success', 'info', 'warning', 'danger', ''],
150 default_value='', allow_none=True, sync=True, help="""Use a
148 default_value='', allow_none=True, sync=True, help="""Use a
151 predefined styling for the buttons.""")
149 predefined styling for the buttons.""")
152
150
153 @register('IPython.RadioButtons')
151 @register('IPython.RadioButtons')
154 class RadioButtons(_Selection):
152 class RadioButtons(_Selection):
155 """Group of radio buttons that represent an enumeration. Only one radio
153 """Group of radio buttons that represent an enumeration. Only one radio
156 button can be toggled at any point in time."""
154 button can be toggled at any point in time."""
157 _view_name = Unicode('RadioButtonsView', sync=True)
155 _view_name = Unicode('RadioButtonsView', sync=True)
158
156
159
157
160
158
161 @register('IPython.Select')
159 @register('IPython.Select')
162 class Select(_Selection):
160 class Select(_Selection):
163 """Listbox that only allows one item to be selected at any given time."""
161 """Listbox that only allows one item to be selected at any given time."""
164 _view_name = Unicode('SelectView', sync=True)
162 _view_name = Unicode('SelectView', sync=True)
165
163
166
164
167 # Remove in IPython 4.0
165 # Remove in IPython 4.0
168 ToggleButtonsWidget = DeprecatedClass(ToggleButtons, 'ToggleButtonsWidget')
166 ToggleButtonsWidget = DeprecatedClass(ToggleButtons, 'ToggleButtonsWidget')
169 DropdownWidget = DeprecatedClass(Dropdown, 'DropdownWidget')
167 DropdownWidget = DeprecatedClass(Dropdown, 'DropdownWidget')
170 RadioButtonsWidget = DeprecatedClass(RadioButtons, 'RadioButtonsWidget')
168 RadioButtonsWidget = DeprecatedClass(RadioButtons, 'RadioButtonsWidget')
171 SelectWidget = DeprecatedClass(Select, 'SelectWidget')
169 SelectWidget = DeprecatedClass(Select, 'SelectWidget')
General Comments 0
You need to be logged in to leave comments. Login now