view orpg/mapper/images.py @ 99:a647e0e8f520 alpha

Traipse Alpha 'OpenRPG' {090925-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary: 00: Update forwards to the 090909-02 Server code that now works. New default Lobby Map, designed for Traipse. Feel free to change it. Updates to Server GUI: * Admin can Ban from Backend. * Prework to modify Ban List in back end. * Server GUI finds your Lobby Name * New users default as Lurker unless a Role is set New Addition to Chat Die Roll commands. Math Ordering. Ex. [(X+Y)dZ]. Currently does pairs only, no nesting either. Cleaner TraipseSuiteAttention portability and clean up in Main (Beta!) 01: Die Roll Commands addition removed in favor of Core code {090925-00}: Updates to Server GUI: *Admin can Modify Ban List and Un Ban users. New About Dialog. A more uniform About Dialog. 01: Corrects image loading of duplicate images.
author sirebral
date Fri, 25 Sep 2009 20:37:54 -0500
parents 763a04270cf6
children 61fc775862f7 dcf4fbe09b70
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.exception(str("Image refused to load or URI did not reference a valid image: " + path), True)
                return None
        except IOError:
            logger.exception(str("Unable to resolve/open the specified URI; image was NOT loaded: " + path), True)
            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:
            self.__cache = {}
            self.__fetching = {}
        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): del self.__fetching[path]
            else:
                logger.exception(str("Image refused to load or URI did not reference a valid image: " + path), True)
                del self.__fetching[path]
        except IOError:
            del self.__fetching[path]
            logger.exception(str("Unable to resolve/open the specified URI; image was NOT loaded: " + path), True)
        finally: self.__lock.release()

    def __loadCacheThread(self, path, image_type, imageId):
        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.exception(str("Unable to resolve/open the specified URI; image was NOT loaded: " + path), True)
            return 
        self.__lock.acquire()
        try:
            logger.info("Adding Image to Queue from Cache: " + str(self.__cache[path]), True)
            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)
component.add('ImageHandler', ImageHandler)