~doctormo/python-moxml/trunk

« back to all changes in this revision

Viewing changes to moxml/config.py

  • Committer: Martin Owens (DoctorMO)
  • Date: 2008-07-20 22:25:40 UTC
  • Revision ID: doctormo@gmail.com-20080720222540-677sj5grs74hz5ui
First Commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
2
# Copyright (C) 2008 Martin Owens
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 3 of the License, or
 
7
# (at your option) any later version.
 
8
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 
18
 
 
19
'''
 
20
XML Based Configuration manager, Very useful xml manager
 
21
allows a program to have and manage data sources which
 
22
are translated from/to xml/python structures transparently.
 
23
'''
 
24
 
 
25
from xml.dom import minidom
 
26
import binascii
 
27
import os, sys, locale
 
28
import atexit, time
 
29
 
 
30
__version__ = "0.9"
 
31
 
 
32
class DefaultManager:
 
33
        """
 
34
        DefaultManager is just a slim file save/load class but it allows
 
35
        configs to be managed in other ways by using different managers.
 
36
        """
 
37
        def load(self, filename):
 
38
                if os.path.isfile(filename):
 
39
                        try:
 
40
                                fh = open(filename, 'rb')
 
41
                                if fh:
 
42
                                        return fh.read()
 
43
                        except:
 
44
                                return sys.stderr.write("Unable to read file %s: Permission denied\n" % filename)
 
45
                sys.stderr.write("Unable to read file %s: File doesn't exist\n" % filename)
 
46
 
 
47
        def save(self, filename, data):
 
48
                dir = self.directory(filename)
 
49
                if os.path.isdir(dir) or dir == '':
 
50
                        try:
 
51
                                fh = open(filename, 'wb')
 
52
                                if fh:
 
53
                                        return fh.write(data)
 
54
                        except:
 
55
                                return sys.stderr.write("Unable to write file %s: permission denied\n" % str(filename))
 
56
                sys.stderr.write("Unable to write file %s: Directory doesn't exist\n" % str(filename))
 
57
 
 
58
        def directory(self, filename):
 
59
                return '/'.join(filename.split('/')[:-1])
 
60
 
 
61
 
 
62
 
 
63
class Directory:
 
64
        '''
 
65
        Directory Manager, has a number of classes for managing directories
 
66
        which are used by config.py to know where to hold files which are
 
67
        related (included from one xml file to another)
 
68
        '''
 
69
        def __init__(self, directory, autoCreate=False):
 
70
                directory = str(directory)
 
71
                self.enabled = False
 
72
 
 
73
                if directory=='':
 
74
                        self.enabled = True
 
75
 
 
76
                if os.path.exists(directory):
 
77
                        if os.path.isdir(directory):
 
78
                                self.enabled = True
 
79
                elif autoCreate:
 
80
                        self.enabled = self.makePath(directory)
 
81
                        
 
82
                if not self.enabled:
 
83
                        self.directory_not_exist(directory)
 
84
                else:
 
85
                        self.directory = directory
 
86
 
 
87
        
 
88
        def directory_not_exist(self, directory):
 
89
                sys.stderr.write(" ! Directory '" + directory + "' does not exist!\n")
 
90
 
 
91
 
 
92
        def load(self, filename):
 
93
                if self.enabled:
 
94
                        path = self.directory + '/' + filename
 
95
                        if self.fileExists(filename):
 
96
                                try:
 
97
                                        file = open(path, 'rb')
 
98
                                        return file.read()
 
99
                                except:
 
100
                                        sys.stderr.write("Unable to read to file %s\n" % filename)
 
101
                                        return ''
 
102
                else:
 
103
                        sys.stderr.write("Failed to load: %s\n" % filename)
 
104
 
 
105
 
 
106
        def save(self, filename, contents):
 
107
                if self.enabled:
 
108
 
 
109
                        path = self.directory + '/' + filename
 
110
                        directory = os.path.dirname(path)
 
111
 
 
112
                        if not self.makePath( directory ):
 
113
                                sys.stderr.write(" ! Unable to create directory: %s\n" % directory)
 
114
                                return False
 
115
 
 
116
                        try:
 
117
                                file = open(path, 'wb')
 
118
                                return file.write(contents)
 
119
                        except:
 
120
                                sys.stderr.write(" ! Unable to write to file %s\n" % filename)
 
121
                                return False
 
122
                else:
 
123
                        sys.stderr.write(" ! Failed to save: %s\n" % filename)
 
124
 
 
125
        def makePath(self, directory):
 
126
                if not os.path.exists(directory):
 
127
                        try:
 
128
                                os.makedirs(directory)
 
129
                                return True
 
130
                        except:
 
131
                                sys.stderr.write(" ! Unable to create directory %s\n" % directory)
 
132
                                return False
 
133
                return True
 
134
 
 
135
        def exists(self, thing):
 
136
                return os.path.exists(self.directory + '/' + thing)
 
137
 
 
138
        def fileExists(self, file):
 
139
                return self.exists(file) and os.path.isfile(self.directory + '/' + file)
 
140
 
 
141
        def directoryExists(self, directory):
 
142
                return self.exists(file) and os.path.isdir(self.directory + '/' + directory)
 
143
 
 
144
        def __str__(self):
 
145
                return self.directory
 
146
 
 
147
 
 
148
 
 
149
class Base:
 
150
        """
 
151
        Base class which will include the ability to
 
152
        Handle the data being in seperate files.
 
153
        """
 
154
        def __init__(self, data, **options):
 
155
                self._manager    = options.has_key('manager')  and options['manager']  or None
 
156
                self._filename   = options.has_key('filename') and options['filename'] or None
 
157
                self._parent     = options.has_key('parent')   and options['parent']   or None
 
158
                self._isroot     = not options.has_key('parent') or not options['parent']
 
159
                self._loaded     = options.has_key('loaded')   and options['loaded']   or False
 
160
                self._version    = options.has_key('version')  and options['version']  or None
 
161
                self._changed    = False
 
162
                self._subchanged = {}
 
163
                self._subfiles   = {}
 
164
                self._loadAll    = False
 
165
 
 
166
                if isinstance(data, minidom.Element):
 
167
                        self.set_attributes(data)
 
168
                        if data.getAttribute('file'):
 
169
                                self._filename = data.getAttribute('file')
 
170
                        else:
 
171
                                self.set_xml(data)
 
172
                else:
 
173
                        self.set(data)
 
174
 
 
175
                # Make sure to register us with the parent list of sub files
 
176
                if self.filename() and self.parent():
 
177
                        self.parent().addSubFile(self.filename(), self)
 
178
 
 
179
        def saveOnExit(self):
 
180
                atexit.register( self.save )
 
181
 
 
182
        def parent(self):
 
183
                if self._parent != None:
 
184
                        return self._parent
 
185
                return None
 
186
 
 
187
        def root(self):
 
188
                if self.isRoot():
 
189
                        return self
 
190
                else:
 
191
                        if self.parent() != None:
 
192
                                return self.parent().root()
 
193
                        else:
 
194
                                sys.stderr.write('This is a fragment, it doesnt have a root\n')
 
195
                                return self
 
196
 
 
197
        def isRoot(self):
 
198
                return self._isroot
 
199
 
 
200
        def fileRoot(self):
 
201
                if self.filename():
 
202
                        return self
 
203
                else:
 
204
                        if self.parent()!=None:
 
205
                                return self.parent().fileRoot()
 
206
                # Assume current node is root
 
207
                return self
 
208
 
 
209
        def filename(self):
 
210
                return self._filename
 
211
 
 
212
        def manager(self):
 
213
                if self._manager:
 
214
                        return self._manager
 
215
                elif not self.isRoot():
 
216
                        return self.root().manager()
 
217
 
 
218
        def setManager(self, manager):
 
219
                self.fileRoot()._manager = manager
 
220
 
 
221
        def save(self):
 
222
                if not self._filename:
 
223
                        return self.fileRoot().save()
 
224
                else:
 
225
                        if self.changed():
 
226
                                result = self._save_all()
 
227
                        #else:
 
228
                                #sys.stderr.write(  "There are no changes to %s, not saving\n" % self._filename )
 
229
                        if self.subFiles():
 
230
                                for filename in self.subFiles().keys():
 
231
                                        child = self.subFiles()[filename]
 
232
                                        child.save()
 
233
 
 
234
        def _save_all(self):
 
235
                if self._filename:
 
236
                        self._save_me()
 
237
 
 
238
        def to_xml(self):
 
239
                doc = minidom.Document()
 
240
                doc.filename = self._filename
 
241
                self.clearSubFiles()
 
242
                root = self.get_xml(doc, 'config')
 
243
                # Set a new version if we have changed
 
244
                root.setAttribute('version', str(self.changed() and self.newVersion() or self.version()))
 
245
                doc.appendChild(root)
 
246
                return doc.toxml()
 
247
 
 
248
        def _save_me(self):
 
249
                if self._loaded:
 
250
                        self._version = self.newVersion()
 
251
                        self.manager().save(self._filename, self.to_xml())
 
252
                        self.hasChanged(False)
 
253
                else:
 
254
                        sys.stderr.write( "Not saving " + self._filename + " Not loaded so not required to save\n")
 
255
 
 
256
        def saveAs(self, filename):
 
257
                self._filename = filename
 
258
                self.manager().save(filename, self.to_xml())
 
259
 
 
260
        def load(self):
 
261
                file = self.manager().load(self._filename)
 
262
                if file:
 
263
                        self.updateWithXML(file)
 
264
                else:
 
265
                        self.set(self.default())
 
266
                self._loaded = True
 
267
 
 
268
        def loadAll(self):
 
269
                ret = self.get()
 
270
                for fileobj in self._subfiles.values():
 
271
                        fileobj.loadAll()
 
272
                return ret
 
273
 
 
274
        def set(self, value):
 
275
                self.value = value
 
276
                
 
277
        def get(self):
 
278
                if self._filename and not self._loaded:
 
279
                        self.load()
 
280
                return self.value
 
281
 
 
282
        def set_attributes(self, xmldoc):
 
283
                pass
 
284
 
 
285
        def version(self):
 
286
                if not self._filename:
 
287
                        return self.fileRoot().version()
 
288
                else:
 
289
                        if self._version:
 
290
                                return self._version
 
291
                        return 1
 
292
 
 
293
        def newVersion(self):
 
294
                return str(int(time.time()))
 
295
 
 
296
        def changed(self):
 
297
                return self.fileRoot()._changed
 
298
 
 
299
        def hasChanged(self, changed=True):
 
300
                self.fileRoot()._changed = changed
 
301
                if not self.isRoot():
 
302
                        self.parent().hasSubChanged(changed, self.filename())
 
303
 
 
304
        def subchanged(self, filename):
 
305
                frsc = self.fileRoot()._subchanged
 
306
                return frsc.has_key(filename) and frsc.has_key(filename)
 
307
 
 
308
        def hasSubChanged(self, changed, filename):
 
309
                self.fileRoot()._subchanged[filename] = changed
 
310
                if not self.isRoot():
 
311
                        self.parent().hasSubChanged(changed, filename)
 
312
 
 
313
        def children(self):
 
314
                return []
 
315
 
 
316
        def subFiles(self):
 
317
                return self.fileRoot()._subfiles
 
318
 
 
319
        def addSubFile(self, filename, child):
 
320
                self.fileRoot()._subfiles[filename] = child
 
321
 
 
322
        def removeSubFile(self, filename):
 
323
                frsf = self.fileRoot()._subfiles
 
324
                if frsf.has_key(filename):
 
325
                        del(frsf[filename])
 
326
 
 
327
        def clearSubFiles(self):
 
328
                self.fileRoot()._subfiles = {}
 
329
 
 
330
        def updateWithXML(self, xml):
 
331
                xmldoc = minidom.parseString(xml)
 
332
                for child in xmldoc.childNodes:
 
333
                        if child.nodeType==1:
 
334
                                if child.tagName=='config':
 
335
                                        self.set_xml(child)
 
336
 
 
337
        # Call Back update, used from standard callback methods
 
338
        # to indicate that one of the files has changed and needs
 
339
        # updating; mostly via internet or some other reason.
 
340
        def cbUpdate(self, xml, options):
 
341
                if options['filename'] == self.filename():
 
342
                        self.updateWithXML(xml)
 
343
                else:
 
344
                        if self._subfiles.has_key(options['filename']):
 
345
                                self._subfiles[options['filename']].updateWithXML(xml)
 
346
                        else:
 
347
                                for subfile in self._subfiles.values():
 
348
                                        subfile.cbUpdate(xml, options)
 
349
 
 
350
 
 
351
        def __str__(self):
 
352
                return str(self.get())
 
353
 
 
354
        def __eq__(self, y):
 
355
                return self.value==y
 
356
 
 
357
        def __int__(self):
 
358
                return int(self.value)
 
359
 
 
360
        def __nonzero__(self):
 
361
                return True
 
362
 
 
363
# Create a child from an xml element
 
364
class XMLChild(object):
 
365
        def __new__(cls, xmldoc, **options):
 
366
                child = None
 
367
                if xmldoc.getAttribute('array'):
 
368
                        child = Array(xmldoc, **options)
 
369
                elif xmldoc.getAttribute('type'):
 
370
                        child = XMLValue(xmldoc, **options)
 
371
                else:
 
372
                        child = Hash(xmldoc, **options)
 
373
                return child
 
374
 
 
375
 
 
376
# Create a child from an xml value element
 
377
class XMLValue(object):
 
378
        def __new__(self, data, **options):
 
379
                vtype = data.getAttribute('type')
 
380
                if vtype=='string':
 
381
                        return ValueString(data, **options)
 
382
                elif vtype=='language':
 
383
                        return ValueLanguage(data, **options)
 
384
                elif vtype=='number':
 
385
                        return ValueNumber(data, **options)
 
386
                elif vtype=='binary':
 
387
                        return ValueBinary(data, **options)
 
388
                else:
 
389
                        sys.stderr.write("ERROR: unknown type " + vtype + "\n")
 
390
 
 
391
 
 
392
# Create a child from a python data class
 
393
class NChild(object):
 
394
        def __new__(cls, child, **options):
 
395
                # Make sure all children are objectified
 
396
                if not isinstance(child, Base):
 
397
                        if isinstance(child, list):
 
398
                                child = Array(child, **options)
 
399
                        elif isinstance(child, dict):
 
400
                                child = Hash(child, **options)
 
401
                        elif isinstance(child, str):
 
402
                                child = ValueString(child, **options)
 
403
                        elif isinstance(child, int):
 
404
                                child = ValueNumber(child, **options)
 
405
                        elif isinstance(child, binary):
 
406
                                child = ValueBinary(child, **options)
 
407
                        elif child:
 
408
                                try:
 
409
                                        child = ValueString(str(child), **options)
 
410
                                except:
 
411
                                        child = ValueString('', **options)
 
412
                        else:
 
413
                                child = ValueString('', **options)
 
414
                return child
 
415
 
 
416
# Load a base file config
 
417
class Config(object):
 
418
        def __new__(cls, filename, manager=None, default={}):
 
419
 
 
420
                config = None
 
421
                file   = None
 
422
 
 
423
                if not manager:
 
424
                        manager = DefaultManager()
 
425
 
 
426
                if manager and filename:
 
427
                        if type(manager) == str:
 
428
                                manager = Directory(manager)
 
429
                        file = manager.load(filename)
 
430
 
 
431
                version = 1
 
432
                if file:
 
433
                        config = newConfig(file, filename, manager, True)
 
434
                
 
435
                if config == None:
 
436
                        config = newConfig(default, filename, manager, False)
 
437
 
 
438
                return config
 
439
 
 
440
# Generate a config based on a new data structure
 
441
class newConfig(object):
 
442
        def __new__(cls, data, filename, manager=None, existing=False):
 
443
 
 
444
                if not manager:
 
445
                        manager = DefaultManager()
 
446
 
 
447
                config = None
 
448
                if type(data) is str and data[:5] == '<?xml':
 
449
 
 
450
                        try:
 
451
                                xmldoc = minidom.parseString(data)
 
452
                        except:
 
453
                                sys.stderr.write("Error when trying to parse xml file %s, corrupt file.\n" % str(filename))
 
454
                                xmldoc   = False
 
455
                                existing = False
 
456
                                data     = {}
 
457
 
 
458
                        if xmldoc:
 
459
                                for child in xmldoc.childNodes:
 
460
                                        if child.nodeType==1:
 
461
                                                if child.tagName=='config':
 
462
                                                        # Load a parentless bastard class
 
463
                                                        config = XMLChild(
 
464
                                                                child,
 
465
                                                                root     = True,
 
466
                                                                filename = filename,
 
467
                                                                manager  = manager,
 
468
                                                                loaded   = True,
 
469
                                                                version  = child.getAttribute('version'),
 
470
                                                        )
 
471
                else:
 
472
                        config = NChild(
 
473
                                data,
 
474
                                root     = True,
 
475
                                filename = filename,
 
476
                                manager  = manager,
 
477
                                loaded   = True,
 
478
                        )
 
479
 
 
480
                if config != None:
 
481
                        # Make sure new configs are marked as changed
 
482
                        config.hasChanged( not existing )
 
483
                return config
 
484
 
 
485
                
 
486
class Hash(Base, dict):
 
487
        def set_xml(self, xmldoc):
 
488
                self.value = {}
 
489
                if xmldoc.hasChildNodes():
 
490
                        for child in xmldoc.childNodes:
 
491
                                if child.nodeType==1: # ELEMENT_NODE
 
492
                                        # For hashes with broken names with extend the xml
 
493
                                        if child.tagName=='_item':
 
494
                                                name  = child.getAttribute('name')
 
495
                                                if name:
 
496
                                                        self.value[name] = XMLChild(
 
497
                                                                child,
 
498
                                                                parent = self,
 
499
                                                        )
 
500
                                        else:
 
501
                                                self.value[child.tagName] = XMLChild(
 
502
                                                        child,
 
503
                                                        parent = self,
 
504
                                                )
 
505
 
 
506
 
 
507
        def get_xml(self, doc, name):
 
508
 
 
509
                root = doc.createElement(name)
 
510
 
 
511
                if not self._filename or doc.filename==self._filename:
 
512
                        for key in self.keys():
 
513
                                if not key.isalnum() or key[0].isdigit():
 
514
                                        element = self[key].get_xml(doc, '_item')
 
515
                                        element.setAttribute('name', key)
 
516
                                else:
 
517
                                        element = self[key].get_xml(doc, key)
 
518
                                
 
519
                                if isinstance(element, minidom.Element):
 
520
                                        root.appendChild(element)
 
521
                elif self.filename() and doc.filename != self.filename() and self.parent():
 
522
                        root.setAttribute('file', self.filename())
 
523
                        # Reafirm connection with parent
 
524
                        self.parent().addSubFile(self.filename(), self)
 
525
                return root
 
526
 
 
527
        def default(self):
 
528
                return {}
 
529
 
 
530
        def set(self, value):
 
531
                self.value = {}
 
532
                # Make sure data comming in is objectified
 
533
                for name in value.keys():
 
534
                        self.value[name] = NChild(
 
535
                                value[name],
 
536
                                parent  = self,
 
537
                        )
 
538
 
 
539
        def keys(self):
 
540
                return self.get().keys()
 
541
 
 
542
        def values(self):
 
543
                return self.get().values()
 
544
 
 
545
        def update(self, hash2):
 
546
                return self.get().update( hash2 )
 
547
 
 
548
        def has_key(self, name):
 
549
                return self.get().has_key(str(name))
 
550
 
 
551
        def __getitem__(self, name):
 
552
                if self.get().has_key(str(name)):
 
553
                    return self.get()[str(name)]
 
554
 
 
555
        def __setitem__(self, name, value):
 
556
                self.hasChanged()
 
557
                self.get()[str(name)] = NChild(
 
558
                        value,
 
559
                        parent = self,
 
560
                )
 
561
 
 
562
        def __delitem__(self, name):
 
563
                if self.get().has_key(name):
 
564
                        self.hasChanged()
 
565
                        del self.get()[name]
 
566
 
 
567
        def __str__(self):
 
568
                return self.to_xml()
 
569
 
 
570
        def children(self):
 
571
                return self.values()
 
572
 
 
573
class Array(Base, list):
 
574
        def set_attributes(self, xmldoc):
 
575
                if xmldoc.getAttribute('array') and not hasattr(self, '_name'):
 
576
                        self._name = xmldoc.getAttribute('array')
 
577
        
 
578
        def set_xml(self, xmldoc):
 
579
                result = []
 
580
                if xmldoc.hasChildNodes():
 
581
                        for child in xmldoc.childNodes:
 
582
                                if child.nodeType==1: # ELEMENT_NODE
 
583
                                        if child.tagName==self.name():
 
584
                                                result.append(XMLChild(
 
585
                                                        child,
 
586
                                                        parent = self,
 
587
                                                ))
 
588
                self.set(result)
 
589
        
 
590
        def get_xml(self, doc, name):
 
591
                root = doc.createElement(name)
 
592
                root.setAttribute('array', self.name())
 
593
                if not self._filename or doc.filename==self._filename:
 
594
                        for value in self.get():
 
595
                                element = value.get_xml(doc, self.name())
 
596
                                if isinstance(element, minidom.Element):
 
597
                                        root.appendChild(element)
 
598
                elif self.filename() and doc.filename != self.filename():
 
599
                        root.setAttribute('file', self.filename())
 
600
                        self.parent().addSubFile(self.filename(), self)
 
601
                return root
 
602
 
 
603
        def default(self):
 
604
                return []
 
605
 
 
606
        def set(self, value):
 
607
                self.value = []
 
608
                # Make sure data comming in is objectified
 
609
                for child in value:
 
610
                        self.value.append(NChild(
 
611
                                child,
 
612
                                parent = self,
 
613
                        ))
 
614
 
 
615
        def name(self):
 
616
                if not hasattr(self, '_name'):
 
617
                        self._name = 'item'
 
618
                return self._name
 
619
        
 
620
        def append(self, item):
 
621
                self.hasChanged()
 
622
                child = NChild(
 
623
                        item,
 
624
                        parent = self,
 
625
                )
 
626
                self.get().append(child)
 
627
                return child
 
628
        
 
629
        def __getitem__(self, index):
 
630
                if index <= len(self.get()):
 
631
                        return self.get()[index]
 
632
 
 
633
        def __setitem__(self, index, value):
 
634
                self.hasChanged()
 
635
                self.get()[index] = NChild(
 
636
                        value,
 
637
                        parent = self,
 
638
                )
 
639
 
 
640
        def __delitem__(self, index):
 
641
                if index < len(self.get()):
 
642
                        self.hasChanged()
 
643
                        del self.get()[index]
 
644
 
 
645
        def __iter__(self):
 
646
                return self.get().__iter__()
 
647
 
 
648
        def __len__(self):
 
649
                if not hasattr(self, 'value'):
 
650
                        return 0
 
651
                return len(self.get())
 
652
 
 
653
        def __str__(self):
 
654
                return self.to_xml()
 
655
 
 
656
        def children(self):
 
657
                return self.get()
 
658
 
 
659
class ValueBase(Base):
 
660
        def __new__(cls, data, **options):
 
661
                return Base.__new__(cls, data, **options)
 
662
 
 
663
        def __init__(self, value, **options):
 
664
                self.encoded = None
 
665
                self.decoded = None
 
666
                self.value   = None
 
667
                Base.__init__(self, value, **options)
 
668
 
 
669
        def set_xml(self, xmldoc):
 
670
                #return self.set(self.get_xml_text(xmldoc))
 
671
                result = ''
 
672
                if xmldoc.hasChildNodes():
 
673
                        for child in xmldoc.childNodes:
 
674
                                if child.nodeType==3: # TEXT_NODE
 
675
                                        result = result + child.data
 
676
                return self.set(result)
 
677
 
 
678
        def get_xml(self, doc, name, ignoreType=0):
 
679
                root = doc.createElement(name)
 
680
 
 
681
                if ignoreType == 0:
 
682
                        root.setAttribute('type', self.type())
 
683
 
 
684
                value = self.get()
 
685
                if not self._filename:
 
686
                        root.appendChild(doc.createTextNode(str(value)))
 
687
                else:
 
688
                        root.setAttribute('file', self._filename)
 
689
                        self._save_me()
 
690
                return root
 
691
 
 
692
        def _save_me(self):
 
693
                self.save()
 
694
 
 
695
        def default(self):
 
696
                return ''
 
697
 
 
698
        def save(self):
 
699
                if self._filename and self._loaded:
 
700
                        self.manager().save(self._filename, self.get())
 
701
 
 
702
        def load(self):
 
703
                file = self.manager().load(self._filename)
 
704
                if file:
 
705
                        self._loaded = 1
 
706
                        self.set(file)
 
707
 
 
708
        def __len__(self):
 
709
                return len(self.get())
 
710
 
 
711
        def __float__(self):
 
712
                return float(self.get())
 
713
 
 
714
# This _should_ also inherit from str or unicode, but
 
715
# can't, currently causes errors with __new__ needs more
 
716
# experenced developer to figure out.
 
717
class ValueString(ValueBase):
 
718
        def __new__(cls, data, **options):
 
719
                return ValueBase.__new__(cls, data, **options)
 
720
 
 
721
        def __init__(self, data, **options):
 
722
                return ValueBase.__init__(self, data, **options)
 
723
 
 
724
        def set(self, value):
 
725
                if value is not None:
 
726
                        self.value = str(value)
 
727
 
 
728
        def type(self):
 
729
                return 'string'
 
730
 
 
731
        def __str__(self):
 
732
                return str(self.get())
 
733
 
 
734
        def lower(self):
 
735
                return str(self.get()).lower()
 
736
 
 
737
 
 
738
class ValueLanguage(ValueBase):
 
739
        def __init__(self, value, **options):
 
740
                self.flipSet = None
 
741
                return ValueBase.__init__(self, value, **options)
 
742
 
 
743
        def set(self, value):
 
744
                lang = self.currentLanguage()[0]
 
745
                return self.setLanguage(lang, value)
 
746
 
 
747
        def get(self):
 
748
                return self.language(self.currentLanguage())
 
749
 
 
750
        def language(self, langs):
 
751
 
 
752
                for lang in langs:
 
753
                        lang = lang.lower()
 
754
                        if self.value.has_key(lang):
 
755
                                return self.value[lang]
 
756
                        elif len(lang) == 5:
 
757
                                suplang = lang[0] + lang[1]
 
758
                                if self.value.has_key(suplang):
 
759
                                        return self.value[suplang]
 
760
 
 
761
                default = self.defaultLanguage()
 
762
                if self.value.has_key(default):
 
763
                        return self.value[default];
 
764
                return None
 
765
 
 
766
        def setLanguage(self, lang, value):
 
767
                lang = lang.lower()
 
768
 
 
769
                if not self.value:
 
770
                        self.value = {}
 
771
 
 
772
                if len(lang) == 5:
 
773
                        suplang = lang[0] + lang[1]
 
774
                        if not self.value.has_key(suplang):
 
775
                                # Update the super varient, because anything is better than nothing
 
776
                                self.value[suplang] = value
 
777
 
 
778
                self.value[lang] = value;
 
779
 
 
780
        def defaultLanguage(self):
 
781
                return 'en'
 
782
 
 
783
        def currentLanguage(self):
 
784
                lang = [ self.defaultLanguage() ]
 
785
                if self.flipSet:
 
786
                        lang = [ self.flipSet ]
 
787
                        self.flipSet = None
 
788
                else:
 
789
                        # There is a tos up between getpreferredencoding()  and getdefaultlocale(), some say the first is better
 
790
                        return locale.getdefaultlocale()
 
791
                return lang
 
792
 
 
793
        def type(self):
 
794
                return 'language'
 
795
 
 
796
        def set_xml(self, xmldoc):
 
797
                if xmldoc.hasChildNodes():
 
798
                        for child in xmldoc.childNodes:
 
799
                                if child.nodeType==1: # ELEMENT_NODE
 
800
                                        lang = child.tagName
 
801
                                        self.flipSet = lang
 
802
                                        ValueBase.set_xml(self, child)
 
803
 
 
804
        def get_xml(self, doc, name):
 
805
                root = doc.createElement(name)
 
806
                root.setAttribute('type', self.type())
 
807
                if not self._filename:
 
808
                        for lang in self.value.keys():
 
809
                                self.flipSet = lang.lower();
 
810
                                element = ValueBase.get_xml(self, doc, lang, 1);
 
811
                                root.appendChild(element);
 
812
                else:
 
813
                        sys.stderr.write("Unable to save language to it's own file, not supported yet\n")
 
814
                return root
 
815
 
 
816
 
 
817
class ValueNumber(ValueBase):
 
818
        def set(self, value):
 
819
                if value is not None:
 
820
                        self.value = int(value)
 
821
 
 
822
        def type(self):
 
823
                return 'number'
 
824
 
 
825
        def default(self):
 
826
                return 0
 
827
 
 
828
        def __add__(self, y):
 
829
                return self.get() + y
 
830
        def __sub__(self, y):
 
831
                return self.get() - y
 
832
        def __div__(self, y):
 
833
                return self.get() / y
 
834
        def __mul__(self, y):
 
835
                return self.get() * y
 
836
 
 
837
# I don't like this is programmed (by me) it just seems messy
 
838
class ValueBinary(ValueBase):
 
839
        def __init__(self, value, **options):
 
840
                ValueBase.__init__(self, value, **options)
 
841
                self.encoded = 'base64'
 
842
 
 
843
        def type(self):
 
844
                return 'binary'
 
845
 
 
846
        def set(self, value):
 
847
                if value:
 
848
                        self.decoded = 1
 
849
                        if isinstance(value, binary):
 
850
                                self.value = value
 
851
                        else:
 
852
                                if not self.value:
 
853
                                        self.value = binary('')
 
854
                                self.value.setbase64(value)
 
855
 
 
856
        def base64(self):
 
857
                return str(self.value)
 
858
 
 
859
        def __str__(self):
 
860
                return self.value.val
 
861
 
 
862
class binary:
 
863
        def __init__(self, data):
 
864
                self.val = data
 
865
                
 
866
        def __str__(self):
 
867
                return binascii.b2a_base64(str(self.val))
 
868
        
 
869
        def setbase64(self, value):
 
870
                self.val = binascii.a2b_base64(value)
 
871
                
 
872
        def __call__(self):
 
873
                return self.val
 
874
 
 
875
        def __len__(self):
 
876
                return len(self.val)