Mercurial > fife-parpg
comparison tools/editor/scripts/settings.py @ 378:64738befdf3b
bringing in the changes from the build_system_rework branch in preparation for the 0.3.0 release. This commit will require the Jan2010 devkit. Clients will also need to be modified to the new way to import fife.
author | vtchill@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Mon, 11 Jan 2010 23:34:52 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
377:fe6fb0e0ed23 | 378:64738befdf3b |
---|---|
1 # -*- coding: utf-8 -*- | |
2 | |
3 # #################################################################### | |
4 # Copyright (C) 2005-2009 by the FIFE team | |
5 # http://www.fifengine.de | |
6 # This file is part of FIFE. | |
7 # | |
8 # FIFE is free software; you can redistribute it and/or | |
9 # modify it under the terms of the GNU Lesser General Public | |
10 # License as published by the Free Software Foundation; either | |
11 # version 2.1 of the License, or (at your option) any later version. | |
12 # | |
13 # This library is distributed in the hope that it will be useful, | |
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 # Lesser General Public License for more details. | |
17 # | |
18 # You should have received a copy of the GNU Lesser General Public | |
19 # License along with this library; if not, write to the | |
20 # Free Software Foundation, Inc., | |
21 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 # #################################################################### | |
23 | |
24 import shutil | |
25 import os | |
26 from fife.extensions.fife_utils import getUserDataDirectory | |
27 try: | |
28 import xml.etree.cElementTree as ET | |
29 except: | |
30 import xml.etree.ElementTree as ET | |
31 | |
32 class Settings(object): | |
33 """ This class provides an interface for retrieving and putting settings | |
34 to an XML-file. | |
35 | |
36 Only one instance of this class may exist, or a RuntimeWarning exception | |
37 will be raised. Use Settings.instance or Editor.getSettings() to retrieve | |
38 an instance of this class. | |
39 """ | |
40 instance = None # Points to the first initialized instance of this class | |
41 def __init__(self, *args, **kwargs): | |
42 if Settings.instance is not None: | |
43 raise RuntimeWarning("Settings instance has already been initialized! Use Editor.getSettings instead") | |
44 | |
45 Settings.instance = self | |
46 | |
47 self._appdata = getUserDataDirectory("fife", "editor") | |
48 | |
49 if os.path.exists(self._appdata+'/settings.xml') is False: | |
50 shutil.copyfile('settings-dist.xml', self._appdata+'/settings.xml') | |
51 | |
52 self.tree = ET.parse(self._appdata+'/settings.xml') | |
53 self.root_element = self.tree.getroot() | |
54 self.validateTree() | |
55 | |
56 def validateTree(self): | |
57 """ Iterates the settings tree and prints warning when an invalid tag is found """ | |
58 for c in self.root_element.getchildren(): | |
59 if c.tag != "Module": | |
60 print "Invalid tag in settings.xml. Expected Module, got: ", c.tag | |
61 elif c.get("name", "") == "": | |
62 print "Invalid tag in settings.xml. Module name is empty." | |
63 else: | |
64 for e in c.getchildren(): | |
65 if e.tag != "Setting": | |
66 print "Invalid tag in settings.xml in module: ",c.tag, | |
67 print ". Expected Setting, got: ", e.tag | |
68 elif c.get("name", "") == "": | |
69 print "Invalid tag in settings.xml in module: ",c.tag, | |
70 print ". Setting name is empty", e.tag | |
71 | |
72 def getModuleTree(self, module): | |
73 """ Returns a module element from the settings tree. If no module with the specified | |
74 name exists, a new element will be created. """ | |
75 if not isinstance(module, str) and not isinstance(module, unicode): | |
76 raise AttributeError("Settings:getModuleTree: Invalid type for module argument.") | |
77 | |
78 for c in self.root_element.getchildren(): | |
79 if c.tag == "Module" and c.get("name", "") == module: | |
80 return c | |
81 | |
82 # Create module | |
83 return ET.SubElement(self.root_element, "Module", {"name":module}) | |
84 | |
85 def get(self, module, name, defaultValue=None): | |
86 """ Gets the value of a specified setting | |
87 | |
88 defaultValue is returned if the setting does not exist | |
89 """ | |
90 if not isinstance(name, str) and not isinstance(name, unicode): | |
91 raise AttributeError("Settings:get: Invalid type for name argument.") | |
92 | |
93 moduleTree = self.getModuleTree(module) | |
94 element = None | |
95 for e in moduleTree.getchildren(): | |
96 if e.tag == "Setting" and e.get("name", "") == name: | |
97 element = e | |
98 break | |
99 else: | |
100 return defaultValue | |
101 | |
102 e_value = element.text | |
103 e_strip = element.get("strip", "1").strip().lower() | |
104 e_type = str(element.get("type", "str")).strip() | |
105 | |
106 if e_value is None: | |
107 return defaultValue | |
108 | |
109 # Strip value | |
110 if e_strip == "" or e_strip == "false" or e_strip == "no" or e_strip == "0": | |
111 e_strip = False | |
112 else: e_strip = True | |
113 | |
114 if e_type == "str" or e_type == "unicode": | |
115 if e_strip: e_value = e_value.strip() | |
116 else: | |
117 e_value = e_value.strip() | |
118 | |
119 # Return value | |
120 if e_type == 'int': | |
121 return int(e_value) | |
122 elif e_type == 'float': | |
123 return float(e_value) | |
124 elif e_type == 'bool': | |
125 e_value = e_value.lower() | |
126 if e_value == "" or e_value == "false" or e_value == "no" or e_value == "0": | |
127 return False | |
128 else: | |
129 return True | |
130 elif e_type == 'str': | |
131 return str(e_value) | |
132 elif e_type == 'unicode': | |
133 return unicode(e_value) | |
134 elif e_type == 'list': | |
135 return self._deserializeList(e_value) | |
136 elif e_type == 'dict': | |
137 return self._deserializeDict(e_value) | |
138 | |
139 def set(self, module, name, value, extra_attrs={}): | |
140 """ | |
141 Sets a setting to specified value. | |
142 | |
143 Parameters: | |
144 module (str|unicode): Module where the setting should be set | |
145 name (str|unicode): Name of setting | |
146 value: Value to assign to setting | |
147 extra_attrs (dict): Extra attributes to be stored in the XML-file | |
148 """ | |
149 if not isinstance(name, str) and not isinstance(name, unicode): | |
150 raise AttributeError("Settings:set: Invalid type for name argument.") | |
151 | |
152 moduleTree = self.getModuleTree(module) | |
153 e_type = "str" | |
154 | |
155 if isinstance(value, bool): # This must be before int | |
156 e_type = "bool" | |
157 value = str(value) | |
158 elif isinstance(value, int): | |
159 e_type = "int" | |
160 value = str(value) | |
161 elif isinstance(value, float): | |
162 e_type = "float" | |
163 value = str(value) | |
164 elif isinstance(value, unicode): | |
165 e_type = "unicode" | |
166 value = unicode(value) | |
167 elif isinstance(value, list): | |
168 e_type = "list" | |
169 value = self._serializeList(value) | |
170 elif isinstance(value, dict): | |
171 e_type = "dict" | |
172 value = self._serializeDict(value) | |
173 else: | |
174 e_type = "str" | |
175 value = str(value) | |
176 | |
177 for e in moduleTree.getchildren(): | |
178 if e.tag != "Setting": continue | |
179 if e.get("name", "") == name: | |
180 e.text = value | |
181 break | |
182 else: | |
183 attrs = {"name":name, "type":e_type} | |
184 for k in extra_attrs: | |
185 if k not in attrs: | |
186 attrs[k] = extra_args[k] | |
187 elm = ET.SubElement(moduleTree, "Setting", attrs) | |
188 elm.text = value | |
189 | |
190 def saveSettings(self): | |
191 """ Save settings into settings.xml """ | |
192 self._indent(self.root_element) | |
193 self.tree.write(self._appdata+'/settings.xml', 'UTF-8') | |
194 | |
195 def _indent(self, elem, level=0): | |
196 """ | |
197 Adds whitespace, so the resulting XML-file is properly indented. | |
198 Shamelessly stolen from http://effbot.org/zone/element-lib.htm | |
199 """ | |
200 i = "\n" + level*" " | |
201 if len(elem): | |
202 if not elem.text or not elem.text.strip(): | |
203 elem.text = i + " " | |
204 if not elem.tail or not elem.tail.strip(): | |
205 elem.tail = i | |
206 for elem in elem: | |
207 self._indent(elem, level+1) | |
208 if not elem.tail or not elem.tail.strip(): | |
209 elem.tail = i | |
210 else: | |
211 if level and (not elem.tail or not elem.tail.strip()): | |
212 elem.tail = i | |
213 | |
214 # FIXME: | |
215 # These serialization functions are not reliable at all | |
216 # This will only serialize the first level of a dict or list | |
217 # It will not check the types nor the content for conflicts. | |
218 # Perhaps we should add a small serialization library? | |
219 def _serializeList(self, list): | |
220 """ Serializes a list, so it can be stored in a text file """ | |
221 return " ; ".join(list) | |
222 | |
223 def _deserializeList(self, string): | |
224 """ Deserializes a list back into a list object """ | |
225 return string.split(" ; ") | |
226 | |
227 def _serializeDict(self, dict): | |
228 """ Serializes a list, so it can be stored in a text file """ | |
229 serial = "" | |
230 for key in dict: | |
231 value = dict[key] | |
232 if serial != "": serial += " ; " | |
233 serial += str(key)+" : "+str(value) | |
234 | |
235 return serial | |
236 | |
237 def _deserializeDict(self, serial): | |
238 """ Deserializes a list back into a dict object """ | |
239 dict = {} | |
240 items = serial.split(" ; ") | |
241 for i in items: | |
242 kv_pair = i.split(" : ") | |
243 dict[kv_pair[0]] = kv_pair[1] | |
244 return dict | |
245 |