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