Updated TODO.
[straw.git] / straw / ImageCache.py
blobf8cb3ef2957d6ebfe85013554225177c2fff705e
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 import NetworkConstants
21 import URLFetch
22 import PollManager
23 import error
24 import Config
25 import gobject
27 import straw
28 from straw import helpers
30 STATUS_IMAGE_WAITING = None
31 STATUS_IMAGE_BROKEN = None
33 class CacheEntry(object):
34 def __init__(self, image, count, pollstopper = None, restore = False):
35 self._image = image
36 self._count = count
37 self._pollstopper = pollstopper
38 if not restore:
39 self._save_count()
41 @apply
42 def image():
43 doc="The image object that is associated with this class"
44 def fget(self):
45 return self._image
46 def fset(self, image):
47 self._image = image
48 return property(**locals())
50 @apply
51 def count():
52 doc="image ref count"
53 def fget(self):
54 return self._count
55 def fset(self, count):
56 self._count = count
57 self._save_count()
58 return property(**locals())
60 @apply
61 def pollstopper():
62 doc="the stopper object for this cache entry"
63 def fget(self):
64 return self._pollstopper
65 def fset(self, pollstopper):
66 self._pollstopper = pollstopper
67 if pollstopper:
68 pollstopper.connect('stopped', self._polling_stopped)
69 return property(**locals())
71 def incr_count(self): self._count += 1
72 def decr_count(self): self._count -= 1
74 def _polling_stopped(self, poller):
75 self._pollstopper = None
77 def _save_count(self):
78 pass
79 #ItemStore.get_instance().set_image_count(self._image.url, self._count)
82 class Cache(gobject.GObject):
83 """Image cache with explicit reference counting."""
85 __gsignals__ = {
86 'image-updated' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
87 (gobject.TYPE_STRING, gobject.TYPE_PYOBJECT))
90 def __init__(self):
91 gobject.GObject.__init__(self)
92 # self.__cache contains items of the form [Image, refcount]
93 self.__cache = dict()
95 def __getitem__(self, key):
96 print "got getitem for %s" % key
97 print "cache is %s" % self.__cache
98 return self.__cache[key].image
100 def add_refer(self, key, restore = False, item = None):
101 if key not in self.__cache:
102 if not restore:
103 # fetch image
104 image = Image(key, Image.WAITING)
105 ic = ImageConsumer(image)
106 headers = {}
107 stopper = None
108 if item and item.feed:
109 headers['Referer'] = item.feed.location
110 try:
111 stopper = URLFetch.get_instance().request(
112 key, ic,
113 priority=NetworkConstants.PRIORITY_IMAGE,
114 headers=headers)
115 #except URLFetch.RequestSchemeException, e:
116 # ic.http_failed(e)
117 except Exception, e:
118 error.logtb("ImageCache.add_refer: ", str(e))
119 ic.http_failed(e)
120 self.__cache[key] = CacheEntry(
121 image, 1, PollManager.PollStopper(stopper, image), restore=restore)
122 else:
123 image = Image(key, Image.DATA_IN_DB)
124 self.__cache[key] = CacheEntry(image, 1, pollstopper=None, restore=restore)
125 elif key in self.__cache and not restore:
126 self.__cache[key].incr_count()
128 def remove_refer(self, key):
129 if self.__cache.has_key(key):
130 entry = self.__cache[key]
131 entry.decr_count()
132 if entry.count == 0:
133 del self.__cache[key]
134 ItemStore.get_instance().update_image(key, None)
135 self.emit('image-updated', key, None)
137 def image_updated(self, url, data):
138 self.__cache[url].pollstopper = None
139 self.set_image(url,data)
140 ItemStore.get_instance().update_image(url,data)
141 self.emit('image-updated', url, data)
143 def set_image(self, url, image):
144 if self.__cache.has_key(url):
145 self.__cache[url].incr_count()
146 else:
147 self.__cache[url] = CacheEntry(image, 1)
149 def set_image_with_count(self, url, image, count, restore=False):
150 self.__cache[url] = CacheEntry(image, count, restore=restore)
152 def stop_transfer(self, url):
153 image = self.__cache.get(url, None)
154 if image and image.pollstopper:
155 self.__cache[url].pollstopper.stop()
156 self.__cache[url].pollstopper = None
158 class Image:
159 WAITING = 1
160 DATA_IN_DB = 2
161 FAILED = 3
163 def __init__(self, url, status = DATA_IN_DB):
164 self.url = url
165 self.status = status
167 def get_data(self):
168 if self.status == self.WAITING:
169 return STATUS_IMAGE_WAITING
170 elif self.status == self.DATA_IN_DB:
171 data = self.read_data()
172 if data is None:
173 self.status = self.FAILED
174 return STATUS_IMAGE_BROKEN
175 return data
176 else:
177 self.status = self.FAILED
178 return STATUS_IMAGE_BROKEN
180 def set_data(self, data):
181 cache.image_updated(self.url, data)
182 self.status = self.DATA_IN_DB
184 def set_failed(self):
185 self.status = self.FAILED
187 def read_data(self):
188 istore = ItemStore.get_instance()
189 return istore.read_image(self.url)
191 def _return_id(self):
192 return "%d %s" % (id(self), self.url)
194 cache = Cache()
196 class ImageConsumer:
197 def __init__(self, imobj):
198 self._imobj = imobj
200 def http_results(self, status, data):
201 if status[1] == 200:
202 self._imobj.set_data(data)
203 else:
204 self._imobj.set_failed()
206 def http_failed(self, exception):
207 self._imobj.set_failed()
209 def operation_stopped(self):
210 # XXX operation stopped is not really failed
211 self._imobj.set_failed()
213 def initialize():
214 global STATUS_IMAGE_WAITING
215 global STATUS_IMAGE_BROKEN
216 STATUS_IMAGE_WAITING = open(
217 straw.STRAW_DATA_DIR + "/image-loading.svg").read()
218 STATUS_IMAGE_BROKEN = open(
219 straw.STRAW_DATA_DIR + "/image-missing.svg").read()