Changes to the config system API to make it more flexible and lightweight, code clean up.
[straw.git] / straw / ImageCache.py
blobb77a8b5e08d28c86ccb162712a4f84ab53c1b4cd
1 """ ImageCache.py
3 Module for handling images
4 """
5 __copyright__ = "Copyright (c) 2002-2005 Free Software Foundation, Inc."
6 __license__ = """
7 Straw is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 2 of the License, or (at your option) any later
10 version.
12 Straw is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along with
17 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 Place - Suite 330, Boston, MA 02111-1307, USA. """
20 from straw import helpers
21 import Config
22 import NetworkConstants
23 import URLFetch
24 import error
25 import gobject
26 import straw.defs
28 STATUS_IMAGE_WAITING = None
29 STATUS_IMAGE_BROKEN = None
31 class CacheEntry(object):
32 def __init__(self, image, count, pollstopper = None, restore = False):
33 self._image = image
34 self._count = count
35 self._pollstopper = pollstopper
36 if not restore:
37 self._save_count()
39 @apply
40 def image():
41 doc="The image object that is associated with this class"
42 def fget(self):
43 return self._image
44 def fset(self, image):
45 self._image = image
46 return property(**locals())
48 @apply
49 def count():
50 doc="image ref count"
51 def fget(self):
52 return self._count
53 def fset(self, count):
54 self._count = count
55 self._save_count()
56 return property(**locals())
58 @apply
59 def pollstopper():
60 doc="the stopper object for this cache entry"
61 def fget(self):
62 return self._pollstopper
63 def fset(self, pollstopper):
64 self._pollstopper = pollstopper
65 if pollstopper:
66 pollstopper.connect('stopped', self._polling_stopped)
67 return property(**locals())
69 def incr_count(self): self._count += 1
70 def decr_count(self): self._count -= 1
72 def _polling_stopped(self, poller):
73 self._pollstopper = None
75 def _save_count(self):
76 pass
77 #ItemStore.get_instance().set_image_count(self._image.url, self._count)
80 class Cache(gobject.GObject):
81 """Image cache with explicit reference counting."""
83 __gsignals__ = {
84 'image-updated' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
85 (gobject.TYPE_STRING, gobject.TYPE_PYOBJECT))
88 def __init__(self):
89 gobject.GObject.__init__(self)
90 # self.__cache contains items of the form [Image, refcount]
91 self.__cache = dict()
93 def __getitem__(self, key):
94 print "got getitem for %s" % key
95 print "cache is %s" % self.__cache
96 return self.__cache[key].image
98 def add_refer(self, key, restore = False, item = None):
99 if key not in self.__cache:
100 if not restore:
101 # fetch image
102 image = Image(key, Image.WAITING)
103 ic = ImageConsumer(image)
104 headers = {}
105 stopper = None
106 if item and item.feed:
107 headers['Referer'] = item.feed.location
108 try:
109 stopper = URLFetch.get_instance().request(
110 key, ic,
111 priority=NetworkConstants.PRIORITY_IMAGE,
112 headers=headers)
113 #except URLFetch.RequestSchemeException, e:
114 # ic.http_failed(e)
115 except Exception, e:
116 error.logtb("ImageCache.add_refer: ", str(e))
117 ic.http_failed(e)
118 self.__cache[key] = CacheEntry(
119 image, 1, PollManager.PollStopper(stopper, image), restore=restore)
120 else:
121 image = Image(key, Image.DATA_IN_DB)
122 self.__cache[key] = CacheEntry(image, 1, pollstopper=None, restore=restore)
123 elif key in self.__cache and not restore:
124 self.__cache[key].incr_count()
126 def remove_refer(self, key):
127 if self.__cache.has_key(key):
128 entry = self.__cache[key]
129 entry.decr_count()
130 if entry.count == 0:
131 del self.__cache[key]
132 ItemStore.get_instance().update_image(key, None)
133 self.emit('image-updated', key, None)
135 def image_updated(self, url, data):
136 self.__cache[url].pollstopper = None
137 self.set_image(url,data)
138 ItemStore.get_instance().update_image(url,data)
139 self.emit('image-updated', url, data)
141 def set_image(self, url, image):
142 if self.__cache.has_key(url):
143 self.__cache[url].incr_count()
144 else:
145 self.__cache[url] = CacheEntry(image, 1)
147 def set_image_with_count(self, url, image, count, restore=False):
148 self.__cache[url] = CacheEntry(image, count, restore=restore)
150 def stop_transfer(self, url):
151 image = self.__cache.get(url, None)
152 if image and image.pollstopper:
153 self.__cache[url].pollstopper.stop()
154 self.__cache[url].pollstopper = None
156 class Image:
157 WAITING = 1
158 DATA_IN_DB = 2
159 FAILED = 3
161 def __init__(self, url, status = DATA_IN_DB):
162 self.url = url
163 self.status = status
165 def get_data(self):
166 if self.status == self.WAITING:
167 return STATUS_IMAGE_WAITING
168 elif self.status == self.DATA_IN_DB:
169 data = self.read_data()
170 if data is None:
171 self.status = self.FAILED
172 return STATUS_IMAGE_BROKEN
173 return data
174 else:
175 self.status = self.FAILED
176 return STATUS_IMAGE_BROKEN
178 def set_data(self, data):
179 cache.image_updated(self.url, data)
180 self.status = self.DATA_IN_DB
182 def set_failed(self):
183 self.status = self.FAILED
185 def read_data(self):
186 istore = ItemStore.get_instance()
187 return istore.read_image(self.url)
189 def _return_id(self):
190 return "%d %s" % (id(self), self.url)
192 cache = Cache()
194 class ImageConsumer:
195 def __init__(self, imobj):
196 self._imobj = imobj
198 def http_results(self, status, data):
199 if status[1] == 200:
200 self._imobj.set_data(data)
201 else:
202 self._imobj.set_failed()
204 def http_failed(self, exception):
205 self._imobj.set_failed()
207 def operation_stopped(self):
208 # XXX operation stopped is not really failed
209 self._imobj.set_failed()
211 def initialize():
212 global STATUS_IMAGE_WAITING
213 global STATUS_IMAGE_BROKEN
214 STATUS_IMAGE_WAITING = open(
215 straw.defs.STRAW_DATA_DIR + "/image-loading.svg").read()
216 STATUS_IMAGE_BROKEN = open(
217 straw.defs.STRAW_DATA_DIR + "/image-missing.svg").read()