Show More
@@ -31,6 +31,7 b' var IPython = (function (IPython) {' | |||||
31 | }; |
|
31 | }; | |
32 |
|
32 | |||
33 | WidgetManager.prototype.init_kernel = function (kernel) { |
|
33 | WidgetManager.prototype.init_kernel = function (kernel) { | |
|
34 | // connect the kernel, and register message handlers | |||
34 | this.kernel = kernel; |
|
35 | this.kernel = kernel; | |
35 | var msg_types = ['widget_create', 'widget_destroy', 'widget_update']; |
|
36 | var msg_types = ['widget_create', 'widget_destroy', 'widget_update']; | |
36 | for (var i = 0; i < msg_types.length; i++) { |
|
37 | for (var i = 0; i < msg_types.length; i++) { | |
@@ -44,6 +45,20 b' var IPython = (function (IPython) {' | |||||
44 | this.widget_types[widget_type] = constructor; |
|
45 | this.widget_types[widget_type] = constructor; | |
45 | }; |
|
46 | }; | |
46 |
|
47 | |||
|
48 | WidgetManager.prototype.register_widget = function (widget) { | |||
|
49 | // Register a widget in the mapping | |||
|
50 | this.widgets[widget.widget_id] = widget; | |||
|
51 | widget.kernel = this.kernel; | |||
|
52 | return widget.widget_id; | |||
|
53 | }; | |||
|
54 | ||||
|
55 | WidgetManager.prototype.unregister_widget = function (widget_id) { | |||
|
56 | // Remove a widget from the mapping | |||
|
57 | delete this.widgets[widget_id]; | |||
|
58 | }; | |||
|
59 | ||||
|
60 | // widget message handlers | |||
|
61 | ||||
47 | WidgetManager.prototype.widget_create = function (msg) { |
|
62 | WidgetManager.prototype.widget_create = function (msg) { | |
48 | var content = msg.content; |
|
63 | var content = msg.content; | |
49 | var constructor = this.widget_types[content.widget_type]; |
|
64 | var constructor = this.widget_types[content.widget_type]; | |
@@ -52,7 +67,10 b' var IPython = (function (IPython) {' | |||||
52 | console.log("Available widget types are: ", this.widget_types); |
|
67 | console.log("Available widget types are: ", this.widget_types); | |
53 | return; |
|
68 | return; | |
54 | } |
|
69 | } | |
55 |
var widget = new constructor( |
|
70 | var widget = new constructor(content.widget_id); | |
|
71 | this.register_widget(widget); | |||
|
72 | widget.handle_create(content.data); | |||
|
73 | ||||
56 | this.widgets[content.widget_id] = widget; |
|
74 | this.widgets[content.widget_id] = widget; | |
57 | }; |
|
75 | }; | |
58 |
|
76 | |||
@@ -79,39 +97,48 b' var IPython = (function (IPython) {' | |||||
79 | // Widget base class |
|
97 | // Widget base class | |
80 | //----------------------------------------------------------------------- |
|
98 | //----------------------------------------------------------------------- | |
81 |
|
99 | |||
82 |
var Widget = function ( |
|
100 | var Widget = function (widget_id) { | |
83 | this.kernel = kernel; |
|
101 | this.widget_id = widget_id; | |
84 | if (!content) return; |
|
102 | this.widget_type = 'widget'; | |
85 | this.widget_id = content.widget_id; |
|
|||
86 | this.handle_create(content.data); |
|
|||
87 | }; |
|
103 | }; | |
88 |
|
104 | |||
89 | Widget.prototype.handle_create = function (data) { |
|
105 | // methods for sending messages | |
90 | }; |
|
106 | Widget.prototype.create = function (data) { | |
91 |
|
107 | var content = { | ||
92 | Widget.prototype.handle_update = function (data) { |
|
108 | widget_id : this.widget_id, | |
|
109 | widget_type : this.widget_type, | |||
|
110 | data : data || {}, | |||
93 | }; |
|
111 | }; | |
94 |
|
112 | this.kernel.send_shell_message("widget_create", content); | ||
95 | Widget.prototype.handle_destroy = function (data) { |
|
|||
96 | }; |
|
113 | }; | |
97 |
|
114 | |||
98 | Widget.prototype.update = function (data) { |
|
115 | Widget.prototype.update = function (data) { | |
99 | var content = { |
|
116 | var content = { | |
100 | widget_id : this.widget_id, |
|
117 | widget_id : this.widget_id, | |
101 | data : data, |
|
118 | data : data || {}, | |
102 | }; |
|
119 | }; | |
103 | this.kernel.send_shell_message("widget_update", content); |
|
120 | this.kernel.send_shell_message("widget_update", content); | |
104 | }; |
|
121 | }; | |
105 |
|
122 | |||
106 |
|
||||
107 | Widget.prototype.destroy = function (data) { |
|
123 | Widget.prototype.destroy = function (data) { | |
108 | var content = { |
|
124 | var content = { | |
109 | widget_id : this.widget_id, |
|
125 | widget_id : this.widget_id, | |
110 | data : data, |
|
126 | data : data || {}, | |
111 | }; |
|
127 | }; | |
112 | this.kernel.send_shell_message("widget_destroy", content); |
|
128 | this.kernel.send_shell_message("widget_destroy", content); | |
113 | }; |
|
129 | }; | |
114 |
|
130 | |||
|
131 | // methods for handling incoming messages | |||
|
132 | ||||
|
133 | Widget.prototype.handle_create = function (data) { | |||
|
134 | }; | |||
|
135 | ||||
|
136 | Widget.prototype.handle_update = function (data) { | |||
|
137 | }; | |||
|
138 | ||||
|
139 | Widget.prototype.handle_destroy = function (data) { | |||
|
140 | }; | |||
|
141 | ||||
115 | IPython.WidgetManager = WidgetManager; |
|
142 | IPython.WidgetManager = WidgetManager; | |
116 | IPython.Widget = Widget; |
|
143 | IPython.Widget = Widget; | |
117 |
|
144 |
@@ -11,11 +11,11 b'' | |||||
11 | # Imports |
|
11 | # Imports | |
12 | #----------------------------------------------------------------------------- |
|
12 | #----------------------------------------------------------------------------- | |
13 |
|
13 | |||
14 | from weakref import ref |
|
|||
15 |
|
||||
16 | from IPython.config import LoggingConfigurable |
|
14 | from IPython.config import LoggingConfigurable | |
17 | from IPython.core.prompts import LazyEvaluate |
|
15 | from IPython.core.prompts import LazyEvaluate | |
18 | from IPython.core.getipython import get_ipython |
|
16 | from IPython.core.getipython import get_ipython | |
|
17 | ||||
|
18 | from IPython.utils.importstring import import_item | |||
19 | from IPython.utils.traitlets import Instance, Unicode, Dict, Any |
|
19 | from IPython.utils.traitlets import Instance, Unicode, Dict, Any | |
20 |
|
20 | |||
21 | #----------------------------------------------------------------------------- |
|
21 | #----------------------------------------------------------------------------- | |
@@ -30,6 +30,7 b' def lazy_keys(dikt):' | |||||
30 | """ |
|
30 | """ | |
31 | return LazyEvaluate(lambda d: list(d.keys())) |
|
31 | return LazyEvaluate(lambda d: list(d.keys())) | |
32 |
|
32 | |||
|
33 | ||||
33 | class WidgetManager(LoggingConfigurable): |
|
34 | class WidgetManager(LoggingConfigurable): | |
34 | """Manager for Widgets in the Kernel""" |
|
35 | """Manager for Widgets in the Kernel""" | |
35 |
|
36 | |||
@@ -46,25 +47,32 b' class WidgetManager(LoggingConfigurable):' | |||||
46 | return self.shell.parent.session |
|
47 | return self.shell.parent.session | |
47 |
|
48 | |||
48 | widgets = Dict() |
|
49 | widgets = Dict() | |
|
50 | widget_types = Dict() | |||
49 |
|
51 | |||
50 | # Public APIs |
|
52 | # Public APIs | |
51 |
|
53 | |||
|
54 | def register_widget_type(self, widget_type, constructor): | |||
|
55 | """Register a constructor for a given widget_type | |||
|
56 | ||||
|
57 | constructor can be a Widget class or an importstring for a Widget class. | |||
|
58 | """ | |||
|
59 | if isinstance(constructor, basestring): | |||
|
60 | constructor = import_item(constructor) | |||
|
61 | ||||
|
62 | self.widget_types[widget_type] = constructor | |||
|
63 | ||||
52 | def register_widget(self, widget): |
|
64 | def register_widget(self, widget): | |
53 | """Register a new widget""" |
|
65 | """Register a new widget""" | |
54 |
|
|
66 | widget_id = widget.widget_id | |
55 | widget.shell = self.shell |
|
67 | widget.shell = self.shell | |
56 | widget.iopub_socket = self.iopub_socket |
|
68 | widget.iopub_socket = self.iopub_socket | |
57 | widget.create() |
|
69 | self.widgets[widget_id] = widget | |
58 |
return |
|
70 | return widget_id | |
59 |
|
71 | |||
60 | def unregister_widget(self, widget_id): |
|
72 | def unregister_widget(self, widget_id): | |
61 | """Unregister a widget, and destroy its counterpart""" |
|
73 | """Unregister a widget, and destroy its counterpart""" | |
62 | # unlike get_widget, this should raise a KeyError |
|
74 | # unlike get_widget, this should raise a KeyError | |
63 |
widget |
|
75 | widget = self.widgets.pop(widget_id) | |
64 | widget = widget_ref() |
|
|||
65 | if widget is None: |
|
|||
66 | # already destroyed, nothing to do |
|
|||
67 | return |
|
|||
68 | widget.destroy() |
|
76 | widget.destroy() | |
69 |
|
77 | |||
70 | def get_widget(self, widget_id): |
|
78 | def get_widget(self, widget_id): | |
@@ -80,16 +88,27 b' class WidgetManager(LoggingConfigurable):' | |||||
80 | self.log.debug("Current widgets: %s", lazy_keys(self.widgets)) |
|
88 | self.log.debug("Current widgets: %s", lazy_keys(self.widgets)) | |
81 | return |
|
89 | return | |
82 | # call, because we store weakrefs |
|
90 | # call, because we store weakrefs | |
83 |
widget = self.widgets[widget_id] |
|
91 | widget = self.widgets[widget_id] | |
84 | if widget is None: |
|
|||
85 | self.log.error("Widget %s has been removed", widget_id) |
|
|||
86 | del self.widgets[widget_id] |
|
|||
87 | self.log.debug("Current widgets: %s", lazy_keys(self.widgets)) |
|
|||
88 | return |
|
|||
89 | return widget |
|
92 | return widget | |
90 |
|
93 | |||
91 | # Message handlers |
|
94 | # Message handlers | |
92 |
|
95 | |||
|
96 | def widget_create(self, stream, ident, msg): | |||
|
97 | """Handler for widget_update messages""" | |||
|
98 | content = msg['content'] | |||
|
99 | widget_id = content['widget_id'] | |||
|
100 | widget_type = content['widget_type'] | |||
|
101 | constructor = self.widget_types.get(widget_type, None) | |||
|
102 | if constructor is None: | |||
|
103 | self.log.error("No such widget_type registered: %s", widget_type) | |||
|
104 | return | |||
|
105 | widget = constructor(widget_id=widget_id, | |||
|
106 | shell=self.shell, | |||
|
107 | iopub_socket=self.iopub_socket, | |||
|
108 | _create_data=content['data'], | |||
|
109 | ) | |||
|
110 | self.register_widget(widget) | |||
|
111 | ||||
93 | def widget_update(self, stream, ident, msg): |
|
112 | def widget_update(self, stream, ident, msg): | |
94 | """Handler for widget_update messages""" |
|
113 | """Handler for widget_update messages""" | |
95 | content = msg['content'] |
|
114 | content = msg['content'] |
@@ -13,6 +13,7 b'' | |||||
13 |
|
13 | |||
14 | import uuid |
|
14 | import uuid | |
15 |
|
15 | |||
|
16 | from IPython.core.getipython import get_ipython | |||
16 | from IPython.config import LoggingConfigurable |
|
17 | from IPython.config import LoggingConfigurable | |
17 | from IPython.utils.traitlets import Instance, Unicode, Bytes, Bool, Dict, Any |
|
18 | from IPython.utils.traitlets import Instance, Unicode, Bytes, Bool, Dict, Any | |
18 |
|
19 | |||
@@ -47,6 +48,18 b' class Widget(LoggingConfigurable):' | |||||
47 | def _widget_id_default(self): |
|
48 | def _widget_id_default(self): | |
48 | return uuid.uuid4().hex |
|
49 | return uuid.uuid4().hex | |
49 |
|
50 | |||
|
51 | primary = Bool(False, help="Am I the primary or secondary Widget?") | |||
|
52 | ||||
|
53 | def __init__(self, **kwargs): | |||
|
54 | super(Widget, self).__init__(**kwargs) | |||
|
55 | get_ipython().widget_manager.register_widget(self) | |||
|
56 | if self.primary: | |||
|
57 | # I am primary, create my peer | |||
|
58 | self.create() | |||
|
59 | else: | |||
|
60 | # I am secondary, handle creation | |||
|
61 | self.handle_create(self._create_data) | |||
|
62 | ||||
50 | def _publish_msg(self, msg_type, data=None, **keys): |
|
63 | def _publish_msg(self, msg_type, data=None, **keys): | |
51 | """Helper for sending a widget message on IOPub""" |
|
64 | """Helper for sending a widget message on IOPub""" | |
52 | data = {} if data is None else data |
|
65 | data = {} if data is None else data | |
@@ -61,16 +74,20 b' class Widget(LoggingConfigurable):' | |||||
61 |
|
74 | |||
62 | # publishing messages |
|
75 | # publishing messages | |
63 |
|
76 | |||
64 | def create(self): |
|
77 | def create(self, data=None): | |
65 | """Create the frontend-side version of this widget""" |
|
78 | """Create the frontend-side version of this widget""" | |
66 | self._publish_msg('widget_create', self._create_data, widget_type = self.widget_type) |
|
79 | if data is None: | |
|
80 | data = self._create_data | |||
|
81 | self._publish_msg('widget_create', data, widget_type=self.widget_type) | |||
67 |
|
82 | |||
68 | def destroy(self): |
|
83 | def destroy(self, data=None): | |
69 | """Destroy the frontend-side version of this widget""" |
|
84 | """Destroy the frontend-side version of this widget""" | |
70 | if self._destroyed: |
|
85 | if self._destroyed: | |
71 | # only destroy once |
|
86 | # only destroy once | |
72 | return |
|
87 | return | |
73 | self._publish_msg('widget_destroy', self._destroy_data) |
|
88 | if data is None: | |
|
89 | data = self._destroy_data | |||
|
90 | self._publish_msg('widget_destroy', data) | |||
74 | self._destroyed = True |
|
91 | self._destroyed = True | |
75 |
|
92 | |||
76 | def update(self, data=None): |
|
93 | def update(self, data=None): | |
@@ -79,6 +96,10 b' class Widget(LoggingConfigurable):' | |||||
79 |
|
96 | |||
80 | # handling of incoming messages |
|
97 | # handling of incoming messages | |
81 |
|
98 | |||
|
99 | def handle_create(self, data): | |||
|
100 | """Handle a widget_create message""" | |||
|
101 | self.log.debug("handle_create %s", data) | |||
|
102 | ||||
82 | def handle_destroy(self, data): |
|
103 | def handle_destroy(self, data): | |
83 | """Handle a widget_destroy message""" |
|
104 | """Handle a widget_destroy message""" | |
84 | self.log.debug("handle_destroy %s", data) |
|
105 | self.log.debug("handle_destroy %s", data) |
@@ -168,7 +168,7 b' class Kernel(Configurable):' | |||||
168 | for msg_type in msg_types: |
|
168 | for msg_type in msg_types: | |
169 | self.shell_handlers[msg_type] = getattr(self, msg_type) |
|
169 | self.shell_handlers[msg_type] = getattr(self, msg_type) | |
170 |
|
170 | |||
171 | widget_msg_types = [ 'widget_update', 'widget_destroy' ] |
|
171 | widget_msg_types = [ 'widget_create', 'widget_update', 'widget_destroy' ] | |
172 | widget_manager = self.shell.widget_manager |
|
172 | widget_manager = self.shell.widget_manager | |
173 | for msg_type in widget_msg_types: |
|
173 | for msg_type in widget_msg_types: | |
174 | self.shell_handlers[msg_type] = getattr(widget_manager, msg_type) |
|
174 | self.shell_handlers[msg_type] = getattr(widget_manager, msg_type) |
General Comments 0
You need to be logged in to leave comments.
Login now