comparison clients/editor/scripts/settings.py @ 255:51cc05d862f2

Merged editor_rewrite branch to trunk. This contains changes that may break compatibility against existing clients. For a list of changes that may affect your client, see: http://wiki.fifengine.de/Changes_to_pychan_and_FIFE_in_editor_rewrite_branch
author cheesesucker@33b003aa-7bff-0310-803a-e67f0ece8222
date Mon, 08 Jun 2009 16:00:02 +0000
parents
children 987a4ea829c1
comparison
equal deleted inserted replaced
254:10b5f7f36dd4 255:51cc05d862f2
1 import shutil
2 import os
3 try:
4 import xml.etree.cElementTree as ET
5 except:
6 import xml.etree.ElementTree as ET
7
8 class Settings(object):
9 """ This class provides an interface for retrieving and putting settings
10 to an XML-file.
11
12 Only one instance of this class may exist, or a RuntimeWarning exception
13 will be raised. Use Settings.instance or Editor.getSettings() to retrieve
14 an instance of this class.
15 """
16 instance = None # Points to the first initialized instance of this class
17 def __init__(self, *args, **kwargs):
18 if Settings.instance is not None:
19 raise RuntimeWarning("Settings instance has already been initialized! Use Editor.getSettings instead")
20
21 Settings.instance = self
22
23 if os.path.exists('settings.xml') is False:
24 shutil.copyfile('settings-dist.xml', 'settings.xml')
25
26 self.tree = ET.parse('settings.xml')
27 self.root_element = self.tree.getroot()
28 self.validateTree()
29
30 def validateTree(self):
31 """ Iterates the settings tree and prints warning when an invalid tag is found """
32 for c in self.root_element.getchildren():
33 if c.tag != "Module":
34 print "Invalid tag in settings.xml. Expected Module, got: ", c.tag
35 elif c.get("name", "") == "":
36 print "Invalid tag in settings.xml. Module name is empty."
37 else:
38 for e in c.getchildren():
39 if e.tag != "Setting":
40 print "Invalid tag in settings.xml in module: ",c.tag,
41 print ". Expected Setting, got: ", e.tag
42 elif c.get("name", "") == "":
43 print "Invalid tag in settings.xml in module: ",c.tag,
44 print ". Setting name is empty", e.tag
45
46 def getModuleTree(self, module):
47 """ Returns a module element from the settings tree. If no module with the specified
48 name exists, a new element will be created. """
49 if not isinstance(module, str) and not isinstance(module, unicode):
50 raise AttributeError("Settings:getModuleTree: Invalid type for module argument.")
51
52 for c in self.root_element.getchildren():
53 if c.tag == "Module" and c.get("name", "") == module:
54 return c
55
56 # Create module
57 return ET.SubElement(self.root_element, "Module", {"name":module})
58
59 def get(self, module, name, defaultValue=None):
60 """ Gets the value of a specified setting
61
62 defaultValue is returned if the setting does not exist
63 """
64 if not isinstance(name, str) and not isinstance(name, unicode):
65 raise AttributeError("Settings:get: Invalid type for name argument.")
66
67 moduleTree = self.getModuleTree(module)
68 element = None
69 for e in moduleTree.getchildren():
70 if e.tag == "Setting" and e.get("name", "") == name:
71 element = e
72 break
73 else:
74 return defaultValue
75
76 e_value = element.text
77 e_strip = element.get("strip", "1").strip().lower()
78 e_type = str(element.get("type", "str")).strip()
79
80 if e_value is None:
81 return defaultValue
82
83 # Strip value
84 if e_strip == "" or e_strip == "false" or e_strip == "no" or e_strip == "0":
85 e_strip = False
86 else: e_strip = True
87
88 if e_type == "str" or e_type == "unicode":
89 if e_strip: e_value = e_value.strip()
90 else:
91 e_value = e_value.strip()
92
93 # Return value
94 if e_type == 'int':
95 return int(e_value)
96 elif e_type == 'float':
97 return float(e_value)
98 elif e_type == 'bool':
99 e_value = e_value.lower()
100 if e_value == "" or e_value == "false" or e_value == "no" or e_value == "0":
101 return False
102 else:
103 return True
104 elif e_type == 'str':
105 return str(e_value)
106 elif e_type == 'unicode':
107 return unicode(e_value)
108 elif e_type == 'list':
109 return self._deserializeList(e_value)
110 elif e_type == 'dict':
111 return self._deserializeDict(e_value)
112
113 def set(self, module, name, value, extra_attrs={}):
114 """
115 Sets a setting to specified value.
116
117 Parameters:
118 module (str|unicode): Module where the setting should be set
119 name (str|unicode): Name of setting
120 value: Value to assign to setting
121 extra_attrs (dict): Extra attributes to be stored in the XML-file
122 """
123 if not isinstance(name, str) and not isinstance(name, unicode):
124 raise AttributeError("Settings:set: Invalid type for name argument.")
125
126 moduleTree = self.getModuleTree(module)
127 e_type = "str"
128
129 if isinstance(value, bool): # This must be before int
130 e_type = "bool"
131 value = str(value)
132 elif isinstance(value, int):
133 e_type = "int"
134 value = str(value)
135 elif isinstance(value, float):
136 e_type = "float"
137 value = str(value)
138 elif isinstance(value, unicode):
139 e_type = "unicode"
140 value = unicode(value)
141 elif isinstance(value, list):
142 e_type = "list"
143 value = self._serializeList(value)
144 elif isinstance(value, dict):
145 e_type = "dict"
146 value = self._serializeDict(value)
147 else:
148 e_type = "str"
149 value = str(value)
150
151 for e in moduleTree.getchildren():
152 if e.tag != "Setting": continue
153 if e.get("name", "") == name:
154 e.text = value
155 break
156 else:
157 attrs = {"name":name, "type":e_type}
158 for k in extra_attrs:
159 if k not in attrs:
160 attrs[k] = extra_args[k]
161 elm = ET.SubElement(moduleTree, "Setting", attrs)
162 elm.text = value
163
164 def saveSettings(self):
165 """ Save settings into settings.xml """
166 self._indent(self.root_element)
167 self.tree.write('settings.xml', 'UTF-8')
168
169 def _indent(self, elem, level=0):
170 """
171 Adds whitespace, so the resulting XML-file is properly indented.
172 Shamelessly stolen from http://effbot.org/zone/element-lib.htm
173 """
174 i = "\n" + level*" "
175 if len(elem):
176 if not elem.text or not elem.text.strip():
177 elem.text = i + " "
178 if not elem.tail or not elem.tail.strip():
179 elem.tail = i
180 for elem in elem:
181 self._indent(elem, level+1)
182 if not elem.tail or not elem.tail.strip():
183 elem.tail = i
184 else:
185 if level and (not elem.tail or not elem.tail.strip()):
186 elem.tail = i
187
188 # FIXME:
189 # These serialization functions are not reliable at all
190 # This will only serialize the first level of a dict or list
191 # It will not check the types nor the content for conflicts.
192 # Perhaps we should add a small serialization library?
193 def _serializeList(self, list):
194 """ Serializes a list, so it can be stored in a text file """
195 return " ; ".join(list)
196
197 def _deserializeList(self, string):
198 """ Deserializes a list back into a list object """
199 return string.split(" ; ")
200
201 def _serializeDict(self, dict):
202 """ Serializes a list, so it can be stored in a text file """
203 serial = ""
204 for key in dict:
205 value = dict[key]
206 if serial != "": serial += " ; "
207 serial += str(key)+" : "+str(value)
208
209 return serial
210
211 def _deserializeDict(self, serial):
212 """ Deserializes a list back into a dict object """
213 dict = {}
214 items = serial.split(" ; ")
215 for i in items:
216 kv_pair = i.split(" : ")
217 dict[kv_pair[0]] = kv_pair[1]
218 return dict