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