3
from twisted.internet import task
4
from twisted.python import log, util
6
from nevow import athena, loaders, static, appserver,inevow, tags as T
8
from model import Model, BaseSingleModelObserver, BaseMultiModelObserver,\
10
from exampleschema import AddressDefinition
12
# Creates a model class
13
Address = Model.__model_from_definition__(AddressDefinition)
14
from persistency import IniFileObserver, load_model_from_ini
15
import attrtypes as types
17
class Widget(athena.LiveFragment):
20
docFactory = loaders.xmlstr('''\
21
<div xmlns:nevow="http://nevow.com/ns/nevow/0.1"
22
xmlns:athena="http://divmod.org/ns/athena/0.7"
23
nevow:render="liveFragment">
24
<div nevow:render="label" />
25
<div nevow:render="widget">
30
def set_model_attr(self, attr):
31
self._model_attr = attr
33
def set_changed_callback(self, cb):
34
self._changed_callback = cb
36
def set_value(self, value):
37
self.callRemote('setValue', value).addErrback(self._oops)
39
def value_changed(self, value):
40
self._changed_callback(self._model_attr, value)
41
athena.expose(value_changed)
43
def render_label(self, ctx, data):
45
return T.div(class_="model-widget-label")[self.label]
54
jsClass = u'WidgetDemo.Entry'
56
def render_widget(self, ctx, data):
58
T.input(type='text', class_='model-entry')[
59
athena.handler(event='onkeydown', handler='changed')
63
class CheckBox(Widget):
65
jsClass = u'WidgetDemo.CheckBox'
67
def render_widget(self, ctx, data):
69
T.input(type='checkbox', class_='model-checkbox')[
70
athena.handler(event='onclick', handler='changed')
74
class OptionList(Widget):
76
jsClass = u'WidgetDemo.OptionList'
78
def render_widget(self, ctx, data):
81
for choice in data.rtype.choices:
82
yield T.label(for_=choice)[choice]
83
yield T.input(type='radio', name='model-radio-%s' % hash(self),
84
value=choice, class_='model-radio')[
85
athena.handler(event='onclick', handler='changed')
88
return ctx.tag[_radios()]
92
jsClass = u'WidgetDemo.Label'
95
def render_widget(self, ctx, data):
96
return T.div(id=data, class_='tree-label')['loading...']
100
jsClass = u'WidgetDemo.List'
103
super(List, self).__init__()
107
self.label = 'Select a person'
109
def add_item(self, item):
110
k = unicode(str(hash(item)), 'ascii')
111
self._models.append(item)
112
self._labels[k] = Label(k)
113
self._labels[k].page = self.page
114
i = T.span(id=u'_%s' % k, style='{cursor: pointer}')[
115
athena.handler(event='onclick', handler='changed'),
117
self._items.append(i)
119
def render_widget(self, ctx, data):
120
yield ctx.tag[self._items]
121
for model in self._models:
122
model.__model_notify__()
124
def set_label(self, model, value):
125
k = unicode(str(hash(model)), 'ascii')
126
self._labels[k].set_value(u'%s' % value)
128
def get_widget_for_type(attr):
130
if rtype is types.boolean:
132
elif rtype.__name__ == 'stringlist':
133
return OptionList(attr)
137
class WidgetPage(athena.LivePage):
138
docFactory = loaders.xmlstr("""\
139
<html xmlns:nevow="http://nevow.com/ns/nevow/0.1">
141
<nevow:invisible nevow:render="liveglue" />
143
<body style="{width: 600px;}">
144
<div nevow:render="entry">
147
<div nevow:render="debug" />
154
def __init__(self, *a, **kw):
155
super(WidgetPage, self).__init__(*a, **kw)
156
self.jsModules.mapping[u'WidgetDemo'] = util.sibpath(__file__, 'widgets.js')
158
def childFactory(self, ctx, name):
159
ch = super(WidgetPage, self).childFactory(ctx, name)
161
p = util.sibpath(__file__, name)
162
if os.path.exists(p):
163
ch = static.File(file(p))
166
def render_entry(self, ctx, data):
171
def render_debug(self, ctx, data):
172
f = athena.IntrospectionFragment()
173
f.setFragmentParent(self)
176
class ElementObserver(BaseSingleModelObserver):
178
def set_parent_page(self, page):
181
def setup_with_model(self, model):
183
self._model_widgets = {}
184
for group, doc, label, stock_id, attrs in model.__model_groups__:
185
self.add_group(label, doc)
186
for attrkey in attrs:
187
attr = model.__model_attrs_map__[attrkey]
188
widget = get_widget_for_type(attr)
189
self.add_widget(attrkey, widget, attr.label)
190
self._widgets.append(T.hr)
192
def add_group(self, label, doc):
193
self._widgets.append(T.h2[label])
194
self._widgets.append(T.h4[doc])
196
def add_widget(self, attr, widget, label):
197
self._widgets.append(widget)
198
widget.page = self.page
199
widget.set_changed_callback(self.cb_widget_changed)
200
widget.set_model_attr(attr)
202
self._model_widgets.setdefault(attr, set()).add(widget)
204
def cb_widget_changed(self, attr, value):
205
self.update_model(attr, value)
207
def __model_notify__(self, model, attr, value):
208
for widget in self._model_widgets[attr]:
209
if isinstance(value, str):
210
value = unicode(value, 'ascii')
211
widget.set_value(value)
214
for widget in self._widgets:
217
class TreeObserver(BaseMultiModelObserver):
219
def __init__(self, *a, **kw):
220
super(TreeObserver, self).__init__(*a, **kw)
222
self.tree.set_changed_callback(self.cb_widget_changed)
223
self.tree.set_model_attr('')
226
def set_parent_page(self, page):
228
self.tree.page = self.page
230
def add_model(self, model):
231
super(TreeObserver, self).add_model(model)
232
self.tree.add_item(model)
233
self._models[unicode(str(hash(model)), 'ascii')] = model
238
def cb_widget_changed(self, attr, value):
239
self.current_callback(self._models[value])
241
def __model_notify__(self, model, attr, value):
242
self.tree.set_label(model, model.__model_markup__)
244
class PropertyPage(WidgetPage):
246
docFactory = loaders.xmlstr("""\
247
<html xmlns:nevow="http://nevow.com/ns/nevow/0.1">
249
<nevow:invisible nevow:render="liveglue" />
251
body {font-family: sans; width: 800px;
252
margin-left: auto; margin-right: auto;}
253
td {vertical-align: top}
255
#main {position: relative;
256
top: 50px; width 800px;}
257
#bar {position: absolute; width: 300px}
258
#item {position: absolute; left: 300px}
260
.model-widget-label {
274
<div nevow:render="list" />
275
<div nevow:render="item" />
280
def __init__(self, *a, **kw):
281
super(PropertyPage, self).__init__(*a, **kw)
283
self.mo = mg.create_multi_observer(TreeObserver)
284
self.mo.set_parent_page(self)
285
rootp = '/tmp/address_a-%s'
289
for i, a in enumerate([self.a1, self.a2, self.a3]):
290
load_model_from_ini(rootp % i, a)
292
self.p = mg.create_multi_observer(IniFileObserver)
293
self.o = mg.create_single_observer(ElementObserver)
294
self.o.set_parent_page(self)
295
self.o.setup_with_model(Address())
297
def render_list(self, ctx, data):
298
yield T.div(id="bar")[self.mo.render()]
300
def render_item(self, ctx, data):
301
yield T.div(id="item")[self.o.render()]
303
def set_model(self, model):
304
self.o.set_model(model)
306
from zope.interface import implements, Interface
311
if __name__ == '__main__':
312
from twisted.application import service, internet
313
#application = service.Application('helloworld')
314
def propertyResourceFactory(original):
315
return PropertyPage()
317
from twisted.python.components import registerAdapter
318
from twisted.internet import reactor
319
registerAdapter(propertyResourceFactory, Fake, inevow.IResource)
321
#log.startLogging(sys.stdout)
322
site = appserver.NevowSite(Fake())
323
reactor.listenTCP(8080, site, interface='')