root/trunk/RBSkinning/RBSkinning/SkinObject.py

Revision 689, 10.4 kB (checked in by sholloway, 5 years ago)

*** empty log message ***

Line 
1 #!/usr/bin/env python
2 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 ##~ License
4 ##~
5 ##- The RuneBlade Foundation library is intended to ease some
6 ##- aspects of writing intricate Jabber, XML, and User Interface (wxPython, etc.)
7 ##- applications, while providing the flexibility to modularly change the
8 ##- architecture. Enjoy.
9 ##~
10 ##~ Copyright (C) 2002  TechGame Networks, LLC.
11 ##~
12 ##~ This library is free software; you can redistribute it and/or
13 ##~ modify it under the terms of the BSD style License as found in the
14 ##~ LICENSE file included with this distribution.
15 ##~
16 ##~ TechGame Networks, LLC can be reached at:
17 ##~ 3578 E. Hartsel Drive #211
18 ##~ Colorado Springs, Colorado, USA, 80920
19 ##~
20 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21
22 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 #~ Imports
24 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25
26 from RBFoundation import XMLBuilder
27 from RBFoundation.Utilities import *
28 from InheritableSettings import InheritSettingsMixin
29 import SkinContext
30 import weakref
31 import warnings
32 import random
33
34 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
35 #~ Constants / Variables / Etc.
36 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
37
38 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
39 #~ Class
40 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
41
42 class SkinObject(XMLBuilder.XMLBuilderObjectBase, InheritSettingsMixin):
43     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44     #~ Constants / Variables / Etc.
45     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
46
47     SettingsSaveOpt = InheritSettingsMixin.SettingsSaveOpt.copy()
48     SettingsSaveOpt = {'ctxvar': False, 'ctxnode': False}
49
50     default_settings = InheritSettingsMixin.default_settings.copy()
51     default_settings.update({
52         #'ctxvar':'',
53         #'ctxnode':'',
54         #'unravelstop':'0',
55         #'unravelnode':'0',
56         #'unravel':'0',
57         })
58
59     globalnamespace = {'argskw': lambda *args, **kw: (args, kw), 'random':random}
60
61     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
62     #~ Special
63     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
64
65     def __init__(self, builder, parent, node, settings, namespacemap):
66         self.children = []
67         self.object = None
68         self._InitParent(parent)
69         self._InitContext(builder, parent)
70         self._InitSettings(settings)
71
72     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
73     #~ Init Protected Methods
74     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
75
76     def _InitParent(self, parent):
77         if parent: self.parent = weakref.ref(parent)
78         else: self.parent = lambda: None
79
80     def _InitContext(self, builder, parent):
81         if parent: self.context = parent.context
82         else: self.context = builder.context
83
84     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
85     #~ Public Methods
86     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
87
88     def SkinInitialize(self):
89         # self.PushContext() # Call this if you are going to add to the context tree
90         pass
91
92     def SkinFinalize(self):
93         pass
94
95     def SkinComplete(self):
96         pass
97
98     def PushContext(self, force=0):
99         """Adds a context to the stack, if needed or forced.
100         Returns the resultant context."""
101         result = self.context
102         if force or (self.parent() and self.parent().context is self.context):
103             self.context = SkinContext.SkinContext(self.context)
104         return result
105
106     def PopContext(self, force=0):
107         """Removes a context from the stack if owned or forced.
108         Returns the resultant context."""
109         result = self.context
110         if force or self.context._next:
111             self.context = self.context._next
112         return result
113        
114     def _SetContextVars(self, startphase):
115         # Context Var/Node settings
116         if startphase:
117             try:
118                 # TODO: Remove this code when the time is ripe!
119                 value = self.settings['contextnode']
120                 self.settings['ctxnode'] = value
121                 warnings.warn('"contextnode" attribute will be renamed to "ctxnode" in future releases.', DeprecationWarning)
122             except KeyError: pass
123
124             if self.settings.get('ctxnode', None):
125                 for name in strtolist(self.settings['ctxnode']):
126                     obj, (setname,) = self.context.getnamedvar(name, -1)
127                     setattr(obj, setname, weakref.proxy(self))
128
129         if self.object is not None:
130             try:
131                 # TODO: Remove this code when the time is ripe!
132                 value = self.settings['contextvar']
133                 self.settings['ctxvar'] = value
134                 warnings.warn('"contextvar" attribute will be renamed to "ctxvar" in future releases.', DeprecationWarning)
135             except KeyError: pass
136
137             if self.settings.get('ctxvar', None):
138                 for name in strtolist(self.settings['ctxvar']):
139                     obj, (setname,) = self.context.getnamedvar(name, -1)
140                     setattr(obj, setname, self.object)
141
142     def Content(self):
143         return [child[1] for child in self.children if child[0] == '']
144
145     def Elements(self, node=None):
146         if node is None:
147             return [child[1] for child in self.children if child[0]]
148         elif node == '*':
149             return [child[1] for child in self.children]
150         else:
151             return [child[1] for child in self.children if child[0] == node]
152        
153     def RemoveElement(self, node):
154         self.children[:] = [child for child in self.children if child[1] is not node]
155
156     def Unravel(self):
157         unravelstop = int(self.settings.get('unravelstop', 0))
158         if not unravelstop and self.parent():
159             # Recursively unravel the next level up
160             unravelstop = self.parent().Unravel()
161             if unravelstop > 0:
162                 return result
163
164         if unravelstop < 0:
165             # Should unravel N stops up the line
166             return unravelstop + 1
167
168         # Unravel this node and everything below it
169         self.UnravelNode()
170
171     def UnravelNode(self):
172         # Unravel this node and everything below it
173         if self.parent():
174             self.parent().RemoveElement(self)
175
176         # Context Var/Node settings
177         if self.settings.get('ctxnode', None):
178             for name in strtolist(self.settings['ctxnode']):
179                 obj, (delname,) = self.context.getnamedvar(name, -1)
180                 delattr(obj, delname)
181         if self.settings.get('ctxvar', None) and self.object:
182             for name in strtolist(self.settings['ctxvar']):
183                 obj, (delname,) = self.context.getnamedvar(name, -1)
184                 delattr(obj, delname)
185
186         try: del self.children
187         except AttributeError: pass
188         try: del self.object
189         except AttributeError: pass
190         try: del self.context
191         except AttributeError: pass
192         try: del self.parent
193         except AttributeError: pass
194         try: del self.settings
195         except AttributeError: pass
196         return 1
197
198     #~ Parent Search Patterns ~~~~~~~~~~~~~~~~~~~~~~~~~~~
199
200     def FindParent(self, *Types):
201         p = self.parent()
202         while p:
203             if isinstance(p, *Types):
204                 return p
205             else: p = p.parent()
206         return None
207
208     def FindParentOrObject(self, *Types):
209         p = self.parent()
210         while p:
211             if isinstance(p.object, Types) or isinstance(p, Types):
212                 return p.object
213             else: p = p.parent()
214         return None
215
216     def FindParentObject(self, *Types):
217         p = self.parent()
218         while p:
219             if isinstance(p.object, Types):
220                 return p.object
221             else: p = p.parent()
222         return None
223
224     def FindParentOfObject(self, *Types):
225         p = self.parent()
226         while p:
227             if isinstance(p.object, Types):
228                 return p
229             else: p = p.parent()
230         return None
231
232     #~ Eval Helpers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
233
234     def _GetEvalLocals(self, **variables):
235         variables['self'] = weakref.proxy(self)
236         variables['ctx'] = variables['context'] = weakref.proxy(self.context)
237         parent = self.parent()
238         if parent:
239             variables['parent'] = parent
240             variables['parentObj'] = parent.object
241         return variables
242
243     def _GetEvalLocalsEx(self, variables, *args):
244         result = variables.copy()
245         result.update(self._GetEvalLocals())
246         map(result.update, args)
247         return result
248
249     def EvalLocal(self, code, **variables):
250         return eval(code, self.globalnamespace, self._GetEvalLocals(**variables))
251
252     def EvalLocalEx(self, code, variables, codefmtstr=None, **kw):
253         if codefmtstr:
254             code = codefmtstr % code
255         return eval(code, self.globalnamespace, self._GetEvalLocalsEx(variables, kw))
256        
257     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
258     #~ Private Methods
259     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
260
261     def _addElement(self, node, element):
262         self.children.append((node[1], element))
263
264     __addDataHadNewLine = 1
265     def _addData(self, data):
266         HadNewline, self.__addDataHadNewLine = self.__addDataHadNewLine, data[-1] in '\n\r'
267         if not HadNewline and self.children and self.children[-1][0] == '':
268             data = self.children.pop()[1] + data
269         self.children.append(('', data))
270
271     def _xmlInitStarted(self):
272         self.SkinInitialize()
273         self._SetContextVars(startphase=1)
274
275     def _xmlInitFinalized(self):
276         # Test this first
277         if self.object is not None:
278             self.SkinFinalize()
279         else:
280             # Skin finalize might change it
281             self.SkinFinalize()
282             self._SetContextVars(startphase=0)
283
284     def _xmlInitComplete(self):
285         # Test this first
286         if self.object is not None:
287             self.SkinComplete()
288         else:
289             # Skin finalize might change it
290             self.SkinComplete()
291             self._SetContextVars(startphase=0)
292
293         # Unraveling code
294         if int(self.settings.get('unravel', 0)):
295             self.Unravel()
296         elif int(self.settings.get('unravelnode', 0)):
297             self.UnravelNode()
298
299     def _toXML(self, strSplit='', *args, **kw):
300         result = []
301         children = getattr(self, 'children', [])
302         for node, each in children:
303             if node:
304                 result.append(each._toXML(strSplit, *args, **kw))
305
306         result = filter(None, result)
307         if strSplit is not None:
308             return strSplit.join(result)
309         else: return result
310
Note: See TracBrowser for help on using the browser.