view orpg/mapper/images.py @ 76:37a11fea3304 ornery-dev

More clean up. Images now posts a Chat Info post if image doesn't load.
author sirebral
date Sat, 22 Aug 2009 04:02:14 -0500
parents 449a8900f9ac
children 6226a5f9a4b3
line wrap: on
line source

# Copyright (C) 2000-2001 The OpenRPG Project
#
#    openrpg-dev@lists.sourceforge.net
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# --
#
# File: mapper/images.py
# Author: OpenRPG
# Maintainer:
# Version:
#   $Id: images.py,v 1.21 2007/12/11 04:07:15 digitalxero Exp $
#
# Description:
#
__version__ = "$Id: images.py,v 1.21 2007/12/11 04:07:15 digitalxero Exp $"

import urllib
import Queue
import thread
from threading import Lock
import time

from orpg.orpg_wx import *
from orpg.orpgCore import component
from orpg.dirpath import dir_struct
from orpg.tools.orpg_log import logger

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance()

class ImageHandlerClass(object):
    __cache = {}
    __fetching = {}
    __queue = Queue.Queue(0)
    __lock = Lock()
    chat = component.get("chat")

    def load(self, path, image_type, imageId):
        """Load an image, with a intermideary fetching image shown while it loads in a background thread"""
        if self.__cache.has_key(path): return wx.ImageFromMime(self.__cache[path][1], 
                                                self.__cache[path][2]).ConvertToBitmap()
        if not self.__fetching.has_key(path):
            self.__fetching[path] = True
            """Start Image Loading Thread"""
            thread.start_new_thread(self.__loadThread, (path, image_type, imageId))
        else:
            if self.__fetching[path] is True: thread.start_new_thread(self.__loadCacheThread, (path, image_type, imageId))
        return wx.Bitmap(dir_struct["icon"] + "fetching.png", wx.BITMAP_TYPE_PNG)

    def directLoad(self, path):
        """Directly load an image, no threads"""
        if self.__cache.has_key(path): return wx.ImageFromMime(self.__cache[path][1], 
                                                self.__cache[path][2]).ConvertToBitmap()
        uriPath = urllib.unquote(path)
        try:
            d = urllib.urlretrieve(uriPath)
            """We have to make sure that not only did we fetch something, but that
               it was an image that we got back."""
            if d[0] and d[1].getmaintype() == "image":
                self.__cache[path] = (path, d[0], d[1].gettype(), None)
                return wx.ImageFromMime(self.__cache[path][1], self.__cache[path][2]).ConvertToBitmap()
            else:
                logger.general("Image refused to load or URI did not reference a valid image: " + path)
                component.get('chat').InfoPost("<font color='#FF0000'>Image refused to load or URI did not reference a valid image: " + path + "</font>")
                return None
        except IOError:
            logger.general("Unable to resolve/open the specified URI; image was NOT loaded: " + path)
            component.get('chat').InfoPost("<font color='#FF0000'>Unable to resolve/open the specified URI; image was NOT loaded: " + path + "</font>")
            return None

    def cleanCache(self):
        """Shrinks the Cache down to the proper size"""
        try: cacheSize = int(component.get('settings').get_setting("ImageCacheSize"))
        except: cacheSize = 32
        cache = self.__cache.keys()
        cache.sort()
        for key in cache[cacheSize:]: del self.__cache[key]

    def flushCache(self):
        """This function will flush all images contained within the image cache."""
        self.__lock.acquire()
        try:
            keyList = self.__cache.keys()
            for key in keyList: del self.__cache[key]
        finally: self.__lock.release()
        urllib.urlcleanup()

    """Private Methods"""
    def __loadThread(self, path, image_type, imageId):
        uriPath = urllib.unquote(path)
        self.__lock.acquire()
        try:
            d = urllib.urlretrieve(uriPath)
            """We have to make sure that not only did we fetch something, but that
               it was an image that we got back."""
            if d[0] and d[1].getmaintype() == "image":
                self.__cache[path] = (path, d[0], d[1].gettype(), imageId)
                self.__queue.put((self.__cache[path], image_type, imageId))
                if self.__fetching.has_key(path): self.__fetching[path] = False #Fix for failed multi-load?
            else:
                logger.general("Image refused to load or URI did not reference a valid image: " + path)
                component.get('chat').InfoPost("<font color='#FF0000'>Image refused to load or URI did not reference a valid image: " + path +"</font>")
                del self.__fetching[path]
        except IOError:
            del self.__fetching[path]
            logger.general("Unable to resolve/open the specified URI; image was NOT loaded: " + path)
            component.get('chat').InfoPost("<font color='#FF0000'> Unable to resolve/open the specified URI; image was NOT loaded: " + path + "</font>")
        finally: self.__lock.release()

    def __loadCacheThread(self, path, image_type, imageId):
        if self.__cache.has_key(path):
            try:
                st = time.time()
                while self.__fetching.has_key(path) and self.__fetching[path] is not False:
                    time.sleep(0.025)
                    if (time.time()-st) > 120:
                        logger.general("Timeout: " + path)
                        break
            except:
                del self.__fetching[path]
                logger.general("Unable to resolve/open the specified URI; image was NOT loaded: " + path)
                component.get('chat').InfoPost("<font color='#FF0000'>Unable to resolve/open the specified URI; image was NOT loaded: " + path + "</font>")
                return 
            self.__lock.acquire()
            try:
                logger.debug("Adding Image to Queue from Cache: " + str(self.__cache[path]))
                component.debug('chat').InfoPost("<font color='#FF0000'>Adding Image to Queue from Cache: " + str(self.__cache[path]) + "</font>)
                self.__queue.put((self.__cache[path], image_type, imageId))
            finally: self.__lock.release()

    """Property Methods"""
    def _getCache(self):
        return self.__cache

    def _getQueue(self):
        return self.__queue

    """Properties"""
    Cache = property(_getCache)
    Queue = property(_getQueue)

ImageHandler = singleton(ImageHandlerClass)