~ubuntu-branches/ubuntu/utopic/pida/utopic

« back to all changes in this revision

Viewing changes to pida/model/nevowinteg.py

  • Committer: Bazaar Package Importer
  • Author(s): Jan Luebbe
  • Date: 2007-04-17 16:08:06 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20070417160806-3ttlb6igf94x9i03
Tags: 0.4.4-1
* New upstream release (closes: #419129)
* Add dependency on python-glade2 (closes: #418716)
* Update copyright

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import time, os, sys
 
2
 
 
3
from twisted.internet import task
 
4
from twisted.python import log, util
 
5
 
 
6
from nevow import athena, loaders, static, appserver,inevow,  tags as T
 
7
 
 
8
from model import Model, BaseSingleModelObserver, BaseMultiModelObserver,\
 
9
                  ModelGroup
 
10
from exampleschema import AddressDefinition
 
11
 
 
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
 
16
 
 
17
class Widget(athena.LiveFragment):
 
18
 
 
19
 
 
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">
 
26
     </div>
 
27
</div>
 
28
''')
 
29
 
 
30
    def set_model_attr(self, attr):
 
31
        self._model_attr = attr
 
32
 
 
33
    def set_changed_callback(self, cb):
 
34
        self._changed_callback = cb
 
35
 
 
36
    def set_value(self, value):
 
37
        self.callRemote('setValue', value).addErrback(self._oops)
 
38
 
 
39
    def value_changed(self, value):
 
40
        self._changed_callback(self._model_attr, value)
 
41
    athena.expose(value_changed)
 
42
 
 
43
    def render_label(self, ctx, data):
 
44
        if self.label:
 
45
            return T.div(class_="model-widget-label")[self.label]
 
46
        else:
 
47
            return ctx.tag
 
48
 
 
49
    def _oops(self, err):
 
50
        log.err(err)
 
51
 
 
52
class Entry(Widget):
 
53
 
 
54
    jsClass = u'WidgetDemo.Entry'
 
55
 
 
56
    def render_widget(self, ctx, data):
 
57
        return ctx.tag[
 
58
                T.input(type='text', class_='model-entry')[
 
59
                    athena.handler(event='onkeydown', handler='changed')
 
60
                ]
 
61
                ]
 
62
 
 
63
class CheckBox(Widget):
 
64
 
 
65
    jsClass = u'WidgetDemo.CheckBox'
 
66
    
 
67
    def render_widget(self, ctx, data):
 
68
        return ctx.tag[
 
69
                T.input(type='checkbox', class_='model-checkbox')[
 
70
                    athena.handler(event='onclick', handler='changed')
 
71
                ]
 
72
                ]
 
73
 
 
74
class OptionList(Widget):
 
75
 
 
76
    jsClass = u'WidgetDemo.OptionList'
 
77
    
 
78
    def render_widget(self, ctx, data):
 
79
        radios = []
 
80
        def _radios():
 
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')
 
86
                              ]
 
87
                yield T.br
 
88
        return ctx.tag[_radios()]
 
89
 
 
90
class Label(Widget):
 
91
 
 
92
    jsClass = u'WidgetDemo.Label'
 
93
    label = ''
 
94
 
 
95
    def render_widget(self, ctx, data):
 
96
        return T.div(id=data, class_='tree-label')['loading...']
 
97
 
 
98
class List(Widget):
 
99
 
 
100
    jsClass = u'WidgetDemo.List'
 
101
 
 
102
    def __init__(self):
 
103
        super(List, self).__init__()
 
104
        self._items = []
 
105
        self._models = []
 
106
        self._labels = {}
 
107
        self.label = 'Select a person'
 
108
 
 
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'),
 
116
                self._labels[k]]
 
117
        self._items.append(i)
 
118
 
 
119
    def render_widget(self, ctx, data):
 
120
        yield ctx.tag[self._items]
 
121
        for model in self._models:
 
122
            model.__model_notify__()
 
123
 
 
124
    def set_label(self, model, value):
 
125
        k = unicode(str(hash(model)), 'ascii')
 
126
        self._labels[k].set_value(u'%s' % value)
 
127
 
 
128
def get_widget_for_type(attr):
 
129
    rtype = attr.rtype
 
130
    if rtype is types.boolean:
 
131
        return CheckBox()
 
132
    elif rtype.__name__ == 'stringlist':
 
133
        return OptionList(attr)
 
134
    else:
 
135
        return Entry()
 
136
 
 
137
class WidgetPage(athena.LivePage):
 
138
    docFactory = loaders.xmlstr("""\
 
139
<html xmlns:nevow="http://nevow.com/ns/nevow/0.1">
 
140
    <head>
 
141
        <nevow:invisible nevow:render="liveglue" />
 
142
    </head>
 
143
    <body style="{width: 600px;}">
 
144
        <div nevow:render="entry">
 
145
            First Clock
 
146
        </div>
 
147
        <div nevow:render="debug" />
 
148
    </body>
 
149
</html>
 
150
""")
 
151
 
 
152
    addSlash = True
 
153
 
 
154
    def __init__(self, *a, **kw):
 
155
        super(WidgetPage, self).__init__(*a, **kw)
 
156
        self.jsModules.mapping[u'WidgetDemo'] = util.sibpath(__file__, 'widgets.js')
 
157
 
 
158
    def childFactory(self, ctx, name):
 
159
        ch = super(WidgetPage, self).childFactory(ctx, name)
 
160
        if ch is None:
 
161
            p = util.sibpath(__file__, name)
 
162
            if os.path.exists(p):
 
163
                ch = static.File(file(p))
 
164
        return ch
 
165
 
 
166
    def render_entry(self, ctx, data):
 
167
        e = Entry()
 
168
        e.page = self
 
169
        return ctx.tag[e]
 
170
 
 
171
    def render_debug(self, ctx, data):
 
172
        f = athena.IntrospectionFragment()
 
173
        f.setFragmentParent(self)
 
174
        return ctx.tag[f]
 
175
 
 
176
class ElementObserver(BaseSingleModelObserver):
 
177
 
 
178
    def set_parent_page(self, page):
 
179
        self.page = page
 
180
 
 
181
    def setup_with_model(self, model):
 
182
        self._widgets = []
 
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)
 
191
 
 
192
    def add_group(self, label, doc):
 
193
        self._widgets.append(T.h2[label])
 
194
        self._widgets.append(T.h4[doc])
 
195
 
 
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)
 
201
        widget.label = label
 
202
        self._model_widgets.setdefault(attr, set()).add(widget)
 
203
 
 
204
    def cb_widget_changed(self, attr, value):
 
205
        self.update_model(attr, value)
 
206
 
 
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)
 
212
 
 
213
    def render(self):
 
214
        for widget in self._widgets:
 
215
            yield widget
 
216
 
 
217
class TreeObserver(BaseMultiModelObserver):
 
218
 
 
219
    def __init__(self, *a, **kw):
 
220
        super(TreeObserver, self).__init__(*a, **kw)
 
221
        self.tree = List()
 
222
        self.tree.set_changed_callback(self.cb_widget_changed)
 
223
        self.tree.set_model_attr('')
 
224
        self._models = {}
 
225
 
 
226
    def set_parent_page(self, page):
 
227
        self.page = page
 
228
        self.tree.page = self.page
 
229
 
 
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
 
234
 
 
235
    def render(self):
 
236
        return self.tree
 
237
 
 
238
    def cb_widget_changed(self, attr, value):
 
239
        self.current_callback(self._models[value])
 
240
 
 
241
    def __model_notify__(self, model, attr, value):
 
242
        self.tree.set_label(model, model.__model_markup__)
 
243
 
 
244
class PropertyPage(WidgetPage):
 
245
 
 
246
    docFactory = loaders.xmlstr("""\
 
247
<html xmlns:nevow="http://nevow.com/ns/nevow/0.1">
 
248
    <head>
 
249
        <nevow:invisible nevow:render="liveglue" />
 
250
        <style>
 
251
            body {font-family: sans; width: 800px;
 
252
                  margin-left: auto; margin-right: auto;}
 
253
            td {vertical-align: top}
 
254
 
 
255
            #main {position: relative;
 
256
                   top: 50px; width 800px;}
 
257
            #bar {position: absolute; width: 300px}
 
258
            #item {position: absolute; left: 300px}
 
259
 
 
260
            .model-widget-label {
 
261
                font-size: small;
 
262
                font-weight: bold;
 
263
                margin-top: 0.7em;
 
264
                }
 
265
 
 
266
            .tree-label {
 
267
                cursor: pointer;
 
268
                font-size: 2em;
 
269
            }
 
270
        </style>
 
271
    </head>
 
272
    <body>
 
273
        <div id="main">
 
274
        <div nevow:render="list" />
 
275
        <div nevow:render="item" />
 
276
        </div>
 
277
    </body>
 
278
</html>
 
279
""")
 
280
    def __init__(self, *a, **kw):
 
281
        super(PropertyPage, self).__init__(*a, **kw)
 
282
        mg = ModelGroup()
 
283
        self.mo = mg.create_multi_observer(TreeObserver)
 
284
        self.mo.set_parent_page(self)
 
285
        rootp = '/tmp/address_a-%s'
 
286
        self.a1 = Address()
 
287
        self.a2 = Address()
 
288
        self.a3 = Address()
 
289
        for i, a in enumerate([self.a1, self.a2, self.a3]):
 
290
            load_model_from_ini(rootp % i, a)
 
291
            mg.add_model(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())
 
296
 
 
297
    def render_list(self, ctx, data):
 
298
        yield T.div(id="bar")[self.mo.render()]
 
299
 
 
300
    def render_item(self, ctx, data):
 
301
        yield T.div(id="item")[self.o.render()]
 
302
 
 
303
    def set_model(self, model):
 
304
        self.o.set_model(model)
 
305
 
 
306
from zope.interface import implements, Interface
 
307
 
 
308
class Fake(object):
 
309
    pass
 
310
 
 
311
if __name__ == '__main__':
 
312
    from twisted.application import service, internet
 
313
    #application = service.Application('helloworld')
 
314
    def propertyResourceFactory(original):
 
315
        return PropertyPage()
 
316
 
 
317
    from twisted.python.components import registerAdapter
 
318
    from twisted.internet import reactor
 
319
    registerAdapter(propertyResourceFactory, Fake, inevow.IResource)
 
320
 
 
321
    #log.startLogging(sys.stdout)
 
322
    site = appserver.NevowSite(Fake())
 
323
    reactor.listenTCP(8080, site, interface='')
 
324
    reactor.run()
 
325