Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / cssutils / css / cssvariablesdeclaration.py @ 475

History | View | Annotate | Download (12.3 KB)

1
"""CSSVariablesDeclaration
2
http://disruptive-innovations.com/zoo/cssvariables/#mozTocId496530
3
"""
4
__all__ = ['CSSVariablesDeclaration']
5
__docformat__ = 'restructuredtext'
6
__version__ = '$Id: cssstyledeclaration.py 1819 2009-08-01 20:52:43Z cthedot $'
7

    
8
from cssutils.prodparser import *
9
from cssutils.helper import normalize
10
from value import PropertyValue
11
import cssutils
12
import itertools
13
import xml.dom
14

    
15
class CSSVariablesDeclaration(cssutils.util._NewBase):
16
    """The CSSVariablesDeclaration interface represents a single block of
17
    variable declarations. 
18
    """
19
    def __init__(self, cssText=u'', parentRule=None, readonly=False):
20
        """
21
        :param cssText:
22
            Shortcut, sets CSSVariablesDeclaration.cssText
23
        :param parentRule:
24
            The CSS rule that contains this declaration block or
25
            None if this CSSVariablesDeclaration is not attached to a CSSRule.
26
        :param readonly:
27
            defaults to False
28
            
29
        Format::
30
        
31
            variableset
32
                : vardeclaration [ ';' S* vardeclaration ]* S*
33
                ;
34
            
35
            vardeclaration
36
                : varname ':' S* term
37
                ;
38
            
39
            varname
40
                : IDENT S*
41
                ;
42
        """
43
        super(CSSVariablesDeclaration, self).__init__()
44
        self._parentRule = parentRule
45
        self._vars = {}
46
        if cssText:
47
            self.cssText = cssText
48
            
49
        self._readonly = readonly
50

    
51
    def __repr__(self):
52
        return u"cssutils.css.%s(cssText=%r)" % (self.__class__.__name__,
53
                                                 self.cssText)
54

    
55
    def __str__(self):
56
        return u"<cssutils.css.%s object length=%r at 0x%x>" % (
57
                self.__class__.__name__,
58
                self.length,
59
                id(self))
60
        
61
    def __contains__(self, variableName):
62
        """Check if a variable is in variable declaration block.
63
        
64
        :param variableName:
65
            a string
66
        """
67
        return normalize(variableName) in self.keys()
68
    
69
    def __getitem__(self, variableName):
70
        """Retrieve the value of variable ``variableName`` from this 
71
        declaration.
72
        """
73
        return self.getVariableValue(variableName)
74
    
75
    def __setitem__(self, variableName, value):
76
        self.setVariable(variableName, value)
77

    
78
    def __delitem__(self, variableName):
79
        return self.removeVariable(variableName)
80

    
81
    def __iter__(self):
82
        """Iterator of names of set variables."""
83
        for name in self.keys():
84
            yield name
85

    
86
    def keys(self):
87
        """Analoguous to standard dict returns variable names which are set in
88
        this declaration."""
89
        return self._vars.keys()
90
    
91
    def _getCssText(self):
92
        """Return serialized property cssText."""
93
        return cssutils.ser.do_css_CSSVariablesDeclaration(self)
94

    
95
    def _setCssText(self, cssText):
96
        """Setting this attribute will result in the parsing of the new value
97
        and resetting of all the properties in the declaration block
98
        including the removal or addition of properties.
99

100
        :exceptions:
101
            - :exc:`~xml.dom.NoModificationAllowedErr`:
102
              Raised if this declaration is readonly or a property is readonly.
103
            - :exc:`~xml.dom.SyntaxErr`:
104
              Raised if the specified CSS string value has a syntax error and
105
              is unparsable.
106

107
        Format::
108
        
109
            variableset
110
            : vardeclaration [ ';' S* vardeclaration ]*
111
            ;
112
            
113
            vardeclaration
114
            : varname ':' S* term
115
            ;
116
            
117
            varname
118
            : IDENT S*
119
            ;
120
            
121
            expr
122
            : [ VARCALL | term ] [ operator [ VARCALL | term ] ]*
123
            ;
124

125
        """
126
        self._checkReadonly()
127

    
128
        vardeclaration = Sequence(
129
            PreDef.ident(),
130
            PreDef.char(u':', u':', toSeq=False, optional=True),
131
            #PreDef.S(toSeq=False, optional=True),
132
            Prod(name=u'term', match=lambda t, v: True,
133
                 toSeq=lambda t, tokens: (u'value', 
134
                                          PropertyValue(itertools.chain([t], 
135
                                                                        tokens), 
136
                                          parent=self)
137
                 )
138
            )
139
        )
140
        prods = Sequence(vardeclaration,                         
141
                         Sequence(PreDef.S(optional=True),
142
                                  PreDef.char(u';', u';', toSeq=False, optional=True),
143
                                  PreDef.S(optional=True),
144
                                  vardeclaration,
145
                                  minmax=lambda: (0, None)),
146
                         PreDef.S(optional=True),
147
                         PreDef.char(u';', u';', toSeq=False, optional=True)
148
                         )
149
        # parse
150
        wellformed, seq, store, notused = \
151
            ProdParser().parse(cssText, 
152
                               u'CSSVariableDeclaration',
153
                               prods,
154
                               emptyOk=True)
155
        if wellformed:
156
            newseq = self._tempSeq()
157
            newvars = {}
158

    
159
            # seq contains only name: value pairs plus comments etc
160
            nameitem = None
161
            for item in seq:
162
                if u'IDENT' == item.type:
163
                    nameitem = item
164
                elif u'value' == item.type:
165
                    nname = normalize(nameitem.value)
166
                    if nname in newvars:
167
                        # replace var with same name
168
                        for i, it in enumerate(newseq):
169
                            if normalize(it.value[0]) == nname:
170
                                newseq.replace(i,
171
                                               (nameitem.value, item.value),
172
                                               'var',
173
                                               nameitem.line, nameitem.col)
174
                    else: 
175
                        # saved non normalized name for reserialization
176
                        newseq.append((nameitem.value, item.value), 
177
                                      'var',
178
                                      nameitem.line, nameitem.col)
179

    
180
#                    newseq.append((nameitem.value, item.value), 
181
#                                  'var',
182
#                                  nameitem.line, nameitem.col)
183
                    
184
                    newvars[nname] = item.value
185
                    
186
                else:
187
                    newseq.appendItem(item)
188

    
189
            self._setSeq(newseq)
190
            self._vars = newvars
191
            self.wellformed = True
192

    
193
    cssText = property(_getCssText, _setCssText,
194
        doc=u"(DOM) A parsable textual representation of the declaration "
195
            u"block excluding the surrounding curly braces.")
196

    
197
    def _setParentRule(self, parentRule):
198
        self._parentRule = parentRule
199
    
200
    parentRule = property(lambda self: self._parentRule, _setParentRule,
201
                          doc=u"(DOM) The CSS rule that contains this"
202
                              u" declaration block or None if this block"
203
                              u" is not attached to a CSSRule.")
204

    
205
    def getVariableValue(self, variableName):
206
        """Used to retrieve the value of a variable if it has been explicitly
207
        set within this variable declaration block.
208
         
209
        :param variableName:
210
            The name of the variable.
211
        :returns:
212
            the value of the variable if it has been explicitly set in this
213
            variable declaration block. Returns the empty string if the
214
            variable has not been set.
215
        """
216
        try:
217
            return self._vars[normalize(variableName)].cssText
218
        except KeyError, e:
219
            return u''
220

    
221
    def removeVariable(self, variableName):
222
        """Used to remove a variable if it has been explicitly set within this
223
        variable declaration block.
224

225
        :param variableName:
226
            The name of the variable.
227
        :returns:
228
            the value of the variable if it has been explicitly set for this
229
            variable declaration block. Returns the empty string if the
230
            variable has not been set.
231

232
        :exceptions:
233
            - :exc:`~xml.dom.NoModificationAllowedErr`:
234
              Raised if this declaration is readonly is readonly.
235
        """
236
        normalname = variableName
237
        try:
238
            r = self._vars[normalname]
239
        except KeyError, e:
240
            return u''
241
        else: 
242
            self.seq._readonly = False
243
            if normalname in self._vars:
244
                for i, x in enumerate(self.seq):
245
                    if x.value[0] == variableName:
246
                        del self.seq[i]
247
            self.seq._readonly = True
248
            del self._vars[normalname]
249

    
250
        return r.cssText
251

    
252
    def setVariable(self, variableName, value):
253
        """Used to set a variable value within this variable declaration block.
254

255
        :param variableName:
256
            The name of the CSS variable. 
257
        :param value:
258
            The new value of the variable, may also be a PropertyValue object.
259

260
        :exceptions:
261
            - :exc:`~xml.dom.SyntaxErr`:
262
              Raised if the specified value has a syntax error and is
263
              unparsable.
264
            - :exc:`~xml.dom.NoModificationAllowedErr`:
265
              Raised if this declaration is readonly or the property is
266
              readonly.
267
        """
268
        self._checkReadonly()
269
                
270
        # check name
271
        wellformed, seq, store, unused = \
272
            ProdParser().parse(normalize(variableName),
273
                               u'variableName',
274
                               Sequence(PreDef.ident()))
275
        if not wellformed:
276
            self._log.error(u'Invalid variableName: %r: %r'
277
                            % (variableName, value))
278
        else:
279
            # check value
280
            if isinstance(value, PropertyValue):
281
                v = value 
282
            else:
283
                v = PropertyValue(cssText=value, parent=self)
284
                                
285
            if not v.wellformed:
286
                self._log.error(u'Invalid variable value: %r: %r'
287
                                % (variableName, value))
288
            else:
289
                # update seq
290
                self.seq._readonly = False
291
                
292
                variableName = normalize(variableName)
293
                
294
                if variableName in self._vars:
295
                    for i, x in enumerate(self.seq):
296
                        if x.value[0] == variableName:
297
                            self.seq.replace(i, 
298
                                      [variableName, v], 
299
                                      x.type, 
300
                                      x.line,
301
                                      x.col)
302
                            break
303
                else:
304
                    self.seq.append([variableName, v], 'var')                
305
                self.seq._readonly = True
306
                self._vars[variableName] = v
307
                
308
    def item(self, index):
309
        """Used to retrieve the variables that have been explicitly set in
310
        this variable declaration block. The order of the variables
311
        retrieved using this method does not have to be the order in which
312
        they were set. This method can be used to iterate over all variables
313
        in this variable declaration block.
314

315
        :param index:
316
            of the variable name to retrieve, negative values behave like
317
            negative indexes on Python lists, so -1 is the last element
318

319
        :returns:
320
            The name of the variable at this ordinal position. The empty
321
            string if no variable exists at this position.
322
        """
323
        try:
324
            return self.keys()[index]
325
        except IndexError:
326
            return u''
327

    
328
    length = property(lambda self: len(self._vars),
329
        doc=u"The number of variables that have been explicitly set in this"
330
            u" variable declaration block. The range of valid indices is 0"
331
            u" to length-1 inclusive.")