| Home | Trees | Indices | Help |
|
|---|
|
|
1 # This program is free software: you can redistribute it and/or modify
2 # it under the terms of the GNU General Public License as published by
3 # the Free Software Foundation, either version 3 of the License, or
4 # (at your option) any later version.
5 #
6 # This program is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # GNU General Public License for more details.
10 #
11 # You should have received a copy of the GNU General Public License
12 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 #
14 # screenlets.backend (c) RYX (aka Rico Pfaus) 2007 <ryx@ryxperience.com>
15 #
16 # INFO:
17 # - The backend offers an abstracted way of saving a Screenlet's data
18 #
19 # TODO:
20 # - add "type"-argument to save_option and read_option to be able to correctly
21 # set the values in GconfBackend (instead of storing only strings).
22 #
23
24 import glob
25 import os
26 import gtk
27 import gobject
28 import gettext
29 import screenlets
30
31 gettext.textdomain('screenlets')
32 gettext.bindtextdomain('screenlets', screenlets.INSTALL_PREFIX + '/share/locale')
33
36
37
38 try:
39 import gconf
40 except:
41 print "GConf python module not found. GConf settings backend is disabled."
42
43
45 """The backend performs the loading/saving of the 'key=value'-strings.
46 Extend this superclass to implement different saving-backends."""
47
50
54
56 """Immediately store all values to disk (in case the backend doesn't
57 save in realtime anyway."""
58 pass
59
63
67
71
72
74 """Backend for storing settings in the GConf registry"""
75
76 gconf_dir = '/apps/screenlets/'
77
79 ScreenletsBackend.__init__(self)
80 print 'GConfBackend: initializing'
81 self.client = gconf.client_get_default()
82
84 """Delete an instance's configuration by its id."""
85 os.system('gconftool-2 --recursive-unset ' + self.key + id)
86 return True
87
89 """Immediately store all values to disk (in case the backend doesn't
90 save in realtime anyway."""
91 pass #No need, GConf saves in realtime
92
94 """Load one option for the instance with the given id."""
95 return self.client.get_string(self.gconf_dir + id + '/' + name)
96
98 """Load all options for the instance with the given id."""
99 keys = []
100 vals = []
101 for i in self.client.all_entries(self.gconf_dir + id):
102 keys.append(i.key.split('/')[4])
103 vals.append(self.client.get_string(i.key))
104 return dict(zip(keys, vals))
105 return None
106
111
112
114 """A backend that stores the settings in arrays and saves after a short
115 interval to avoid overhead when multiple values are set within a short time.
116 The data gets saved into $HOME/.config/Screenlets/<Screenletname>/, in a
117 file for each element (named like its id with the extension '.ini')."""
118
119 # internals
120 __instances = {} # a dict with (id:dict)-entries cntaining the data
121 __delay_time = 3000 # delay to wait before performing save
122 __timeout = None # the id of the timeout-function
123 __queue = [] # list with ids of instances that need saving
124
125 # attribs
126 path = '' # the path to store the files
127
128 # Constructor
133
135 """Delete an instance from the list and from the filesystem."""
136 if self.__instances.has_key(id):
137 del self.__instances[id]
138 try:
139 import os
140 os.remove(self.path + id + '.ini')
141 except Exception,ex:
142 print ex
143 print "Temporary file didn't exist - nothing to remove."
144 return False
145 print "CachingBackend: <#%s> removed!" % id
146 return True
147
151
153 """Save option for an instance to cache and start saving-timeout
154 for that element (value must be of type string)."""
155 # create key for option, if not existent yet
156 if self.__instances.has_key(id) == False:
157 self.__instances[id] = {}
158 # set option in array
159 self.__instances[id][name] = str(value)
160 #print "CachingBackend.save_option: "+name+"="+self.__instances[id][name]
161 # if id is not already in queue, add the id to the queue
162 if self.__queue.count(id) == 0:
163 self.__queue.append(id)
164 # reset timeout and start new
165 if self.__timeout:
166 gobject.source_remove(self.__timeout)
167 self.__timeout = gobject.timeout_add(self.__delay_time,
168 self.__save_cache)#, id)
169
171 """TODO: Load option from the backend (returned as str)."""
172 return self.__instances[id][name]
173
175 """Load all options for the instance with the given id."""
176 #print "Load element: "+id
177 if self.__instances.has_key(id):
178 return self.__instances[id]
179 return None
180
182 """Load all cached files from path."""
183 # perform saving
184 print "CachingBackend: Loading instances from cache"
185 # get dir content of self.path
186 dirname = self.path
187 dirlst = glob.glob(dirname + '*')
188 tdlen = len(dirname)
189 lst = []
190 for fname in dirlst:
191 dname = fname[tdlen:]
192 if dname.endswith('.ini'):
193 id = dname[:-4]
194 print "CachingBackend: Loading <%s>" % id
195 #print "ID: "+id
196 if self.__instances.has_key(id) == False:
197 self.__instances[id] = {}
198 # open file
199 try:
200 f = open(fname, 'r')
201 lines = f.readlines()
202 # read all options for this element from file
203 for line in lines:
204 #print "LOAD: "+line[:-1]
205 parts = line[:-1].split('=', 1)
206 if len(parts) > 1:
207 # undocumented features to resize screenlet dynamically on first launch
208 # width, height must precede rel_x and rel_y with "_"
209 # by boamaod for Estobuntu
210 if parts[0] == 'x':
211 if parts[1].startswith("*"): # if * is added, take distance from the opposite side
212 parts[1] = parts[1].strip("*")
213 add_width = 0
214 if parts[1].startswith("_"): # if _ is added, take it to be right corner
215 add_width = int(float(self.__instances[id]["width"])*float(self.__instances[id]["scale"]))
216 print "ADD W", add_width
217 parts[1] = str(gtk.gdk.screen_width() - int(parts[1].strip("_")) - add_width)
218 print ">>>X", parts[1]
219 if parts[0] == 'y':
220 if parts[1].startswith("*"): # if * is added, take distance from the opposite side
221 parts[1] = parts[1].strip("*")
222 add_height = 0
223 if parts[1].startswith("_"): # if _ is added, take it to be bottom corner
224 add_height = int(float(self.__instances[id]["height"])*float(self.__instances[id]["scale"]))
225 print "ADD H", add_height
226 parts[1] = str(gtk.gdk.screen_height() - int(parts[1].strip("_")) - add_height)
227 print ">>>Y", parts[1]
228 if parts[0] == 'rel_x':
229 parts[0] = 'x'
230 add_width = 0
231 if parts[1].startswith("_"): # if _ is added, take it to be right corner
232 add_width = int(float(self.__instances[id]["width"])*float(self.__instances[id]["scale"]))
233 print "ADD W", add_width
234 parts[1] = str(int(gtk.gdk.screen_width()*float(parts[1].strip("_"))) - add_width)
235 print ">>>X", parts[1]
236 if parts[0] == 'rel_y':
237 parts[0] = 'y'
238 add_height = 0
239 if parts[1].startswith("_"): # if _ is added, take it to be bottom corner
240 add_height = int(float(self.__instances[id]["height"])*float(self.__instances[id]["scale"]))
241 print "ADD H", add_height
242 parts[1] = str(int(gtk.gdk.screen_height()*float(parts[1].strip("_"))) - add_height)
243 print ">>>Y", parts[1]
244 if parts[0] == 'rel_scale':
245 parts[0] = 'scale'
246 scale = float(self.__instances[id]["scale"])
247 initial_scale = scale + float(gtk.gdk.screen_height()*gtk.gdk.screen_width())/float(parts[1])
248 if initial_scale < 1.5:
249 initial_scale = 1.5
250 if initial_scale > 3:
251 initial_scale = 3
252 parts[1] = str(initial_scale)
253 # parts[1] = str(gtk.gdk.screen_height()/float(parts[1]))
254 print ">>>SCALE", parts[1]
255 if parts[0] == 'rel_font_name':
256 parts[0] = 'font_name'
257 print "|||", parts[1]
258 font_parts = parts[1].rsplit(" ")
259 parts[1]=""
260 for fp in font_parts:
261 if len(fp)>0 and len(fp.strip("0123456789."))==0:
262 parts[1]+= str( round(float(fp)*float(self.__instances[id]["scale"]), 1) ) + " "
263 else:
264 parts[1]+= fp + " "
265 parts[1] = parts[1].strip(" ")
266 print ">>>FONT_NAME", parts[1]
267 # End of dynamic resize section
268 print "%s='%s'" % (parts[0], parts[1])
269 self.__instances[id][parts[0]] = parts[1]
270 f.close()
271 except Exception, ex:
272 print "Error while loading options: %s" % str(ex)
273
275 """Save the cache (for all pending instances in queue) to self.path."""
276 # loop through all instances in queue:
277 for id in self.__queue:
278 # if element with id not exists, remove it and break
279 if self.__instances.has_key(id) == False:
280 print "Queue-element <%s> not found (already removed?)!" % id
281 self.__queue.remove(id)
282 break
283 # create list with options
284 #print "CachingBackend: Saving <#%s> :) ..." % id
285 lst = []
286 for oname in self.__instances[id]:
287 lst.append([oname, self.__instances[id][oname]])
288 # and save them (if any)
289 if len(lst) > 0:
290 self.__save_settings (self.path + id + '.ini', lst)
291 # clear queue
292 self.__queue = []
293 # NOT continue the timeout-function (!!!!!)
294 return False
295
297 """ Try to save settings in a file, first save this to a temporal file avoid encodings a disk full errors """
298 filenametmp = filename + '.tmp'
299 isOk = True
300 newini = ''
301 try:
302 # Is posible to fail with encoding error?
303 for el in lst:
304 newini += "%s=%s\n" % (el[0], el[1])
305 except:
306 isOk = False
307 print "error while convert config to string (encoding error?), I lose your last changes :'("
308
309 if isOk:
310 # Write the new settings to a temporal file, disk full, encoding, rights may fails at this point.
311 try:
312 open(filenametmp, 'w').write(newini)
313 except:
314 isOk = False
315 print "error while saving configuration to a temporal file %s, disk full?" % filenametmp
316
317 if isOk:
318 # Move saved settings to definitive configuration file, disk error o incorrect rights may fails at this point.
319 try:
320 import shutil
321 shutil.move(filenametmp, filename)
322 except:
323 print "error while moving temporal file to configuration file, %s > %s, sorry, I lose your settings. :'(" % (filenametmp, filename)
324
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Wed Jan 4 16:58:28 2012 | http://epydoc.sourceforge.net |