##// END OF EJS Templates
Merge pull request #5520 from jdfreder/2.x...
Thomas Kluyver -
r16201:fbed4929 merge
parent child Browse files
Show More
@@ -1,121 +1,125 b''
1 """SelectionWidget classes.
1 """SelectionWidget 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
20 from .widget import DOMWidget
21 from IPython.utils.traitlets import Unicode, List, Bool, Any, Dict, TraitError
21 from IPython.utils.traitlets import Unicode, List, Bool, Any, Dict, TraitError
22 from IPython.utils.py3compat import unicode_type
22 from IPython.utils.py3compat import unicode_type
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # SelectionWidget
25 # SelectionWidget
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 class _SelectionWidget(DOMWidget):
27 class _SelectionWidget(DOMWidget):
28 """Base class for Selection widgets
28 """Base class for Selection widgets
29
29
30 ``values`` can be specified as a list or dict. If given as a list,
30 ``values`` can be specified as a list or dict. If given as a list,
31 it will be transformed to a dict of the form ``{str(value):value}``.
31 it will be transformed to a dict of the form ``{str(value):value}``.
32 """
32 """
33
33
34 value = Any(help="Selected value")
34 value = Any(help="Selected value")
35 values = Dict(help="""Dictionary of {name: value} the user can select.
35 values = Dict(help="""Dictionary of {name: value} the user can select.
36
36
37 The keys of this dictionary are the strings that will be displayed in the UI,
37 The keys of this dictionary are the strings that will be displayed in the UI,
38 representing the actual Python choices.
38 representing the actual Python choices.
39
39
40 The keys of this dictionary are also available as value_names.
40 The keys of this dictionary are also available as value_names.
41 """)
41 """)
42 value_name = Unicode(help="The name of the selected value", sync=True)
42 value_name = Unicode(help="The name of the selected value", sync=True)
43 value_names = List(Unicode, help="""Read-only list of names for each value.
43 value_names = List(Unicode, help="""Read-only list of names for each value.
44
44
45 If values is specified as a list, this is the string representation of each element.
45 If values is specified as a list, this is the string representation of each element.
46 Otherwise, it is the keys of the values dictionary.
46 Otherwise, it is the keys of the values dictionary.
47
47
48 These strings are used to display the choices in the front-end.""", sync=True)
48 These strings are used to display the choices in the front-end.""", sync=True)
49 disabled = Bool(False, help="Enable or disable user changes", sync=True)
49 disabled = Bool(False, help="Enable or disable user changes", sync=True)
50 description = Unicode(help="Description of the value this widget represents", sync=True)
50 description = Unicode(help="Description of the value this widget represents", sync=True)
51
51
52
52
53 def __init__(self, *args, **kwargs):
53 def __init__(self, *args, **kwargs):
54 self.value_lock = Lock()
54 self.value_lock = Lock()
55 self._in_values_changed = False
55 self._in_values_changed = False
56 if 'values' in kwargs:
56 if 'values' in kwargs:
57 values = kwargs['values']
57 values = kwargs['values']
58 # convert list values to an dict of {str(v):v}
58 # convert list values to an dict of {str(v):v}
59 if isinstance(values, list):
59 if isinstance(values, list):
60 # preserve list order with an OrderedDict
60 # preserve list order with an OrderedDict
61 kwargs['values'] = OrderedDict((unicode_type(v), v) for v in values)
61 kwargs['values'] = OrderedDict((unicode_type(v), v) for v in values)
62 # python3.3 turned on hash randomization by default - this means that sometimes, randomly
63 # we try to set value before setting values, due to dictionary ordering. To fix this, force
64 # the setting of self.values right now, before anything else runs
65 self.values = kwargs.pop('values')
62 DOMWidget.__init__(self, *args, **kwargs)
66 DOMWidget.__init__(self, *args, **kwargs)
63
67
64 def _values_changed(self, name, old, new):
68 def _values_changed(self, name, old, new):
65 """Handles when the values dict has been changed.
69 """Handles when the values dict has been changed.
66
70
67 Setting values implies setting value names from the keys of the dict.
71 Setting values implies setting value names from the keys of the dict.
68 """
72 """
69 self._in_values_changed = True
73 self._in_values_changed = True
70 try:
74 try:
71 self.value_names = list(new.keys())
75 self.value_names = list(new.keys())
72 finally:
76 finally:
73 self._in_values_changed = False
77 self._in_values_changed = False
74
78
75 # ensure that the chosen value is one of the choices
79 # ensure that the chosen value is one of the choices
76 if self.value not in new.values():
80 if self.value not in new.values():
77 self.value = next(iter(new.values()))
81 self.value = next(iter(new.values()))
78
82
79 def _value_names_changed(self, name, old, new):
83 def _value_names_changed(self, name, old, new):
80 if not self._in_values_changed:
84 if not self._in_values_changed:
81 raise TraitError("value_names is a read-only proxy to values.keys(). Use the values dict instead.")
85 raise TraitError("value_names is a read-only proxy to values.keys(). Use the values dict instead.")
82
86
83 def _value_changed(self, name, old, new):
87 def _value_changed(self, name, old, new):
84 """Called when value has been changed"""
88 """Called when value has been changed"""
85 if self.value_lock.acquire(False):
89 if self.value_lock.acquire(False):
86 try:
90 try:
87 # Reverse dictionary lookup for the value name
91 # Reverse dictionary lookup for the value name
88 for k,v in self.values.items():
92 for k,v in self.values.items():
89 if new == v:
93 if new == v:
90 # set the selected value name
94 # set the selected value name
91 self.value_name = k
95 self.value_name = k
92 return
96 return
93 # undo the change, and raise KeyError
97 # undo the change, and raise KeyError
94 self.value = old
98 self.value = old
95 raise KeyError(new)
99 raise KeyError(new)
96 finally:
100 finally:
97 self.value_lock.release()
101 self.value_lock.release()
98
102
99 def _value_name_changed(self, name, old, new):
103 def _value_name_changed(self, name, old, new):
100 """Called when the value name has been changed (typically by the frontend)."""
104 """Called when the value name has been changed (typically by the frontend)."""
101 if self.value_lock.acquire(False):
105 if self.value_lock.acquire(False):
102 try:
106 try:
103 self.value = self.values[new]
107 self.value = self.values[new]
104 finally:
108 finally:
105 self.value_lock.release()
109 self.value_lock.release()
106
110
107
111
108 class ToggleButtonsWidget(_SelectionWidget):
112 class ToggleButtonsWidget(_SelectionWidget):
109 _view_name = Unicode('ToggleButtonsView', sync=True)
113 _view_name = Unicode('ToggleButtonsView', sync=True)
110
114
111
115
112 class DropdownWidget(_SelectionWidget):
116 class DropdownWidget(_SelectionWidget):
113 _view_name = Unicode('DropdownView', sync=True)
117 _view_name = Unicode('DropdownView', sync=True)
114
118
115
119
116 class RadioButtonsWidget(_SelectionWidget):
120 class RadioButtonsWidget(_SelectionWidget):
117 _view_name = Unicode('RadioButtonsView', sync=True)
121 _view_name = Unicode('RadioButtonsView', sync=True)
118
122
119
123
120 class SelectWidget(_SelectionWidget):
124 class SelectWidget(_SelectionWidget):
121 _view_name = Unicode('SelectView', sync=True)
125 _view_name = Unicode('SelectView', sync=True)
@@ -1,186 +1,187 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "name": ""
3 "name": ""
4 },
4 },
5 "nbformat": 3,
5 "nbformat": 3,
6 "nbformat_minor": 0,
6 "nbformat_minor": 0,
7 "worksheets": [
7 "worksheets": [
8 {
8 {
9 "cells": [
9 "cells": [
10 {
10 {
11 "cell_type": "code",
11 "cell_type": "code",
12 "collapsed": false,
12 "collapsed": false,
13 "input": [
13 "input": [
14 "# Widget related imports\n",
14 "# Widget related imports\n",
15 "from IPython.html import widgets\n",
15 "from IPython.html import widgets\n",
16 "from IPython.display import display, clear_output, Javascript\n",
16 "from IPython.display import display, clear_output, Javascript\n",
17 "from IPython.utils.traitlets import Unicode\n",
17 "from IPython.utils.traitlets import Unicode\n",
18 "\n",
18 "\n",
19 "# nbconvert related imports\n",
19 "# nbconvert related imports\n",
20 "from IPython.nbconvert import get_export_names, export_by_name\n",
20 "from IPython.nbconvert import get_export_names, export_by_name\n",
21 "from IPython.nbconvert.writers import FilesWriter\n",
21 "from IPython.nbconvert.writers import FilesWriter\n",
22 "from IPython.nbformat import current"
22 "from IPython.nbformat import current\n",
23 "from IPython.nbconvert.utils.exceptions import ConversionException"
23 ],
24 ],
24 "language": "python",
25 "language": "python",
25 "metadata": {},
26 "metadata": {},
26 "outputs": [],
27 "outputs": [],
27 "prompt_number": 1
28 "prompt_number": 1
28 },
29 },
29 {
30 {
30 "cell_type": "markdown",
31 "cell_type": "markdown",
31 "metadata": {},
32 "metadata": {},
32 "source": [
33 "source": [
33 "Create a text Widget without displaying it. The widget will be used to store the notebook's name which is otherwise only available in the front-end."
34 "Create a text Widget without displaying it. The widget will be used to store the notebook's name which is otherwise only available in the front-end."
34 ]
35 ]
35 },
36 },
36 {
37 {
37 "cell_type": "code",
38 "cell_type": "code",
38 "collapsed": false,
39 "collapsed": false,
39 "input": [
40 "input": [
40 "notebook_name = widgets.TextWidget()"
41 "notebook_name = widgets.TextWidget()"
41 ],
42 ],
42 "language": "python",
43 "language": "python",
43 "metadata": {},
44 "metadata": {},
44 "outputs": [],
45 "outputs": [],
45 "prompt_number": 2
46 "prompt_number": 2
46 },
47 },
47 {
48 {
48 "cell_type": "markdown",
49 "cell_type": "markdown",
49 "metadata": {},
50 "metadata": {},
50 "source": [
51 "source": [
51 "Get the current notebook's name by pushing JavaScript to the browser that sets the notebook name in a string widget."
52 "Get the current notebook's name by pushing JavaScript to the browser that sets the notebook name in a string widget."
52 ]
53 ]
53 },
54 },
54 {
55 {
55 "cell_type": "code",
56 "cell_type": "code",
56 "collapsed": false,
57 "collapsed": false,
57 "input": [
58 "input": [
58 "js = \"\"\"var model = IPython.notebook.kernel.widget_manager.get_model('{model_id}');\n",
59 "js = \"\"\"var model = IPython.notebook.kernel.widget_manager.get_model('{model_id}');\n",
59 "model.set('value', IPython.notebook.notebook_name);\n",
60 "model.set('value', IPython.notebook.notebook_name);\n",
60 "model.save();\"\"\".format(model_id=notebook_name.model_id)\n",
61 "model.save();\"\"\".format(model_id=notebook_name.model_id)\n",
61 "display(Javascript(data=js))"
62 "display(Javascript(data=js))"
62 ],
63 ],
63 "language": "python",
64 "language": "python",
64 "metadata": {},
65 "metadata": {},
65 "outputs": [
66 "outputs": [
66 {
67 {
67 "javascript": [
68 "javascript": [
68 "var model = IPython.notebook.kernel.widget_manager.get_model('8c6583524eb3422c99491730a3e1ce6c');\n",
69 "var model = IPython.notebook.kernel.widget_manager.get_model('8c6583524eb3422c99491730a3e1ce6c');\n",
69 "model.set('value', IPython.notebook.notebook_name);\n",
70 "model.set('value', IPython.notebook.notebook_name);\n",
70 "model.save();"
71 "model.save();"
71 ],
72 ],
72 "metadata": {},
73 "metadata": {},
73 "output_type": "display_data",
74 "output_type": "display_data",
74 "text": [
75 "text": [
75 "<IPython.core.display.Javascript at 0x164ea50>"
76 "<IPython.core.display.Javascript at 0x164ea50>"
76 ]
77 ]
77 }
78 }
78 ],
79 ],
79 "prompt_number": 3
80 "prompt_number": 3
80 },
81 },
81 {
82 {
82 "cell_type": "code",
83 "cell_type": "code",
83 "collapsed": false,
84 "collapsed": false,
84 "input": [
85 "input": [
85 "filename = notebook_name.value\n",
86 "filename = notebook_name.value\n",
86 "filename"
87 "filename"
87 ],
88 ],
88 "language": "python",
89 "language": "python",
89 "metadata": {},
90 "metadata": {},
90 "outputs": [
91 "outputs": [
91 {
92 {
92 "metadata": {},
93 "metadata": {},
93 "output_type": "pyout",
94 "output_type": "pyout",
94 "prompt_number": 4,
95 "prompt_number": 4,
95 "text": [
96 "text": [
96 "u'Export As (nbconvert).ipynb'"
97 "u'Export As (nbconvert).ipynb'"
97 ]
98 ]
98 }
99 }
99 ],
100 ],
100 "prompt_number": 4
101 "prompt_number": 4
101 },
102 },
102 {
103 {
103 "cell_type": "markdown",
104 "cell_type": "markdown",
104 "metadata": {},
105 "metadata": {},
105 "source": [
106 "source": [
106 "Create the widget that will allow the user to Export the current notebook."
107 "Create the widget that will allow the user to Export the current notebook."
107 ]
108 ]
108 },
109 },
109 {
110 {
110 "cell_type": "code",
111 "cell_type": "code",
111 "collapsed": false,
112 "collapsed": false,
112 "input": [
113 "input": [
113 "exporter_names = widgets.DropdownWidget(values=get_export_names(), value='html')\n",
114 "exporter_names = widgets.DropdownWidget(values=get_export_names(), value='html')\n",
114 "export_button = widgets.ButtonWidget(description=\"Export\")\n",
115 "export_button = widgets.ButtonWidget(description=\"Export\")\n",
115 "download_link = widgets.HTMLWidget(visible=False)"
116 "download_link = widgets.HTMLWidget(visible=False)"
116 ],
117 ],
117 "language": "python",
118 "language": "python",
118 "metadata": {},
119 "metadata": {},
119 "outputs": [],
120 "outputs": [],
120 "prompt_number": 5
121 "prompt_number": 5
121 },
122 },
122 {
123 {
123 "cell_type": "markdown",
124 "cell_type": "markdown",
124 "metadata": {},
125 "metadata": {},
125 "source": [
126 "source": [
126 "Export the notebook when the export button is clicked."
127 "Export the notebook when the export button is clicked."
127 ]
128 ]
128 },
129 },
129 {
130 {
130 "cell_type": "code",
131 "cell_type": "code",
131 "collapsed": false,
132 "collapsed": false,
132 "input": [
133 "input": [
133 "file_writer = FilesWriter()\n",
134 "file_writer = FilesWriter()\n",
134 "\n",
135 "\n",
135 "def export(name, nb):\n",
136 "def export(name, nb):\n",
136 " \n",
137 " \n",
137 " # Get a unique key for the notebook and set it in the resources object.\n",
138 " # Get a unique key for the notebook and set it in the resources object.\n",
138 " notebook_name = name[:name.rfind('.')]\n",
139 " notebook_name = name[:name.rfind('.')]\n",
139 " resources = {}\n",
140 " resources = {}\n",
140 " resources['unique_key'] = notebook_name\n",
141 " resources['unique_key'] = notebook_name\n",
141 " resources['output_files_dir'] = '%s_files' % notebook_name\n",
142 " resources['output_files_dir'] = '%s_files' % notebook_name\n",
142 "\n",
143 "\n",
143 " # Try to export\n",
144 " # Try to export\n",
144 " try:\n",
145 " try:\n",
145 " output, resources = export_by_name(exporter_names.value, nb)\n",
146 " output, resources = export_by_name(exporter_names.value, nb)\n",
146 " except ConversionException as e:\n",
147 " except ConversionException as e:\n",
147 " download_link.value = \"<br>Could not export notebook!\"\n",
148 " download_link.value = \"<br>Could not export notebook!\"\n",
148 " else:\n",
149 " else:\n",
149 " write_results = file_writer.write(output, resources, notebook_name=notebook_name)\n",
150 " write_results = file_writer.write(output, resources, notebook_name=notebook_name)\n",
150 " \n",
151 " \n",
151 " download_link.value = \"<br>Results: <a href='files/{filename}'><i>\\\"{filename}\\\"</i></a>\".format(filename=write_results)\n",
152 " download_link.value = \"<br>Results: <a href='files/{filename}'><i>\\\"{filename}\\\"</i></a>\".format(filename=write_results)\n",
152 " download_link.visible = True\n",
153 " download_link.visible = True\n",
153 " \n",
154 " \n",
154 "def handle_export():\n",
155 "def handle_export(widget):\n",
155 " with open(filename, 'r') as f:\n",
156 " with open(filename, 'r') as f:\n",
156 " export(filename, current.read(f, 'json'))\n",
157 " export(filename, current.read(f, 'json'))\n",
157 "export_button.on_click(handle_export)"
158 "export_button.on_click(handle_export)"
158 ],
159 ],
159 "language": "python",
160 "language": "python",
160 "metadata": {},
161 "metadata": {},
161 "outputs": [],
162 "outputs": [],
162 "prompt_number": 6
163 "prompt_number": 6
163 },
164 },
164 {
165 {
165 "cell_type": "markdown",
166 "cell_type": "markdown",
166 "metadata": {},
167 "metadata": {},
167 "source": [
168 "source": [
168 "Display the controls."
169 "Display the controls."
169 ]
170 ]
170 },
171 },
171 {
172 {
172 "cell_type": "code",
173 "cell_type": "code",
173 "collapsed": false,
174 "collapsed": false,
174 "input": [
175 "input": [
175 "display(exporter_names, export_button, download_link)"
176 "display(exporter_names, export_button, download_link)"
176 ],
177 ],
177 "language": "python",
178 "language": "python",
178 "metadata": {},
179 "metadata": {},
179 "outputs": [],
180 "outputs": [],
180 "prompt_number": 7
181 "prompt_number": 7
181 }
182 }
182 ],
183 ],
183 "metadata": {}
184 "metadata": {}
184 }
185 }
185 ]
186 ]
186 } No newline at end of file
187 }
General Comments 0
You need to be logged in to leave comments. Login now