Package Camelot :: Package camelot :: Package view :: Package model_thread |
[frames] | no frames]

# Source Code for Package Camelot.camelot.view.model_thread

      1  #  ============================================================================
      2  #
      3  #  Copyright (C) 2007-2008 Conceptive Engineering bvba. All rights reserved.
      4  #  www.conceptive.be / project-camelot@conceptive.be
      5  #
      6  #  This file is part of the Camelot Library.
      7  #
      8  #  This file may be used under the terms of the GNU General Public
      9  #  License version 2.0 as published by the Free Software Foundation
     10  #  and appearing in the file LICENSE.GPL included in the packaging of
     11  #  this file.  Please review the following information to ensure GNU
     12  #  General Public Licensing requirements will be met:
     13  #  http://www.trolltech.com/products/qt/opensource.html
     14  #
     15  #  If you are unsure which license is appropriate for your use, please
     16  #  review the following information:
     17  #  http://www.trolltech.com/products/qt/licensing.html or contact
     18  #  project-camelot@conceptive.be.
     19  #
     20  #  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
     21  #  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     22  #
     23  #  For use of this library in commercial applications, please contact
     24  #  project-camelot@conceptive.be
     25  #
     26  #  ============================================================================
     27
     28  import logging
     29  from functools import wraps
     30
     31  from PyQt4 import QtCore, QtGui
     32
     33  logger = logging.getLogger( 'camelot.view.model_thread' )
     34
     35  _model_thread_ = []
     36
     37 -class ModelThreadException( Exception ):
     38      pass
     39
     40 -def model_function( original_function ):
     41      """Decorator to ensure a function is only called from within the model
     42      thread.  If this function is called in another thread, an exception will be
     43      thrown
     44      """
     45
     46      def in_model_thread():
     47          """return wether current thread is model thread"""
     48          from no_thread_model_thread import NoThreadModelThread
     49          current_thread = QtCore.QThread.currentThread()
     50          model_thread = get_model_thread()
     51          return (current_thread==model_thread) or isinstance(model_thread, (NoThreadModelThread,))
     52
     53      @wraps(original_function)
     54      def wrapper( *args, **kwargs ):
     55          assert in_model_thread()
     56          return original_function( *args, **kwargs )
     57
     58      return wrapper
     59
     60 -def gui_function( original_function ):
     61      """Decorator to ensure a function is only called from within the gui thread.
     62      If this function is called in another thread, an exception will be thrown
     63      """
     64
     65      def in_gui_thread():
     66          """return wether current thread is gui thread"""
     67          gui_thread = QtGui.QApplication.instance().thread()
     68          current_thread = QtCore.QThread.currentThread()
     69          return gui_thread == current_thread
     70
     71      @wraps( original_function )
     72      def wrapper( *args, **kwargs ):
     73          assert in_gui_thread()
     74          return original_function( *args, **kwargs )
     75
     76      return wrapper
     77
     78 -def setup_model():
     79      """Call the setup_model function in the settings"""
     80      from settings import setup_model
     81      setup_model()
     82
     83 -class AbstractModelThread(object):
     84      """Abstract implementation of a model thread class
     85    Thread in which the model runs, all requests to the model should be
     86    posted to the the model thread.
     87
     88    This class ensures the gui thread doesn't block when the model needs
     89    time to complete tasks by providing asynchronous communication between
     90    the model thread and the gui thread
     91    """
     92
     93      thread_busy_signal = QtCore.SIGNAL('thread_busy')
     94
     95 -    def __init__(self, setup_thread = setup_model ):
     96          """
     97          @param setup_thread: function to be called at startup of the thread to initialize
     98          everything, by default this will setup the model.  set to None if nothing should
     99          be done.
    100          """
    101          self.logger = logging.getLogger( logger.name + '.%s' % id( self ) )
    102          self._setup_thread = setup_thread
    103          self._exit = False
    104          self._traceback = ''
    105          self.logger.debug( 'model thread constructed' )
    106
    107 -    def run(self):
    108          pass
    109
    110 -    def traceback( self ):
    111          """The formatted traceback of the last exception in the model thread"""
    112          return self._traceback
    113
    114 -    def wait_on_work(self):
    115          """Wait for all work to be finished, this function should only be used
    116      to do unit testing and such, since it will block the calling thread until
    117      all work is done"""
    118          pass
    119
    120 -    def post( self, request, response = None, exception = None ):
    121          """Post a request to the model thread, request should be
    122      a function that takes no arguments.  The request function
    123      will be called within the model thread.  When the request
    124      is finished, on first occasion, the response function will be
    125      called within the gui thread.  The response function takes as
    126      arguments, the results of the request function.
    127      @param request: function to be called within the model thread
    128      @param response: a slot that will be called with the result of the
    129      request function
    130      @param exception: a slot that will be called in case request throws
    131      an exception
    132          """
    133          raise NotImplemented
    134
    135 -    def busy( self ):
    136          """Return True or False indicating wether either the model or the
    137          gui thread is doing something"""
    138          return False
    139
    140 -def construct_model_thread( *args, **kwargs ):
    141      import settings
    142      if hasattr(settings, 'THREADING') and settings.THREADING==False:
    143          logger.info('running without threads')
    144          from no_thread_model_thread import NoThreadModelThread
    145          _model_thread_.insert( 0, NoThreadModelThread( *args, **kwargs ) )
    146      else:
    147          from signal_slot_model_thread import SignalSlotModelThread
    148          _model_thread_.insert( 0, SignalSlotModelThread( *args, **kwargs ) )
    149
    150 -def has_model_thread():
    151      return len( _model_thread_ ) > 0
    152
    153 -def get_model_thread():
    154      return _model_thread_[0]
    155
    156 -def post(request, response = None, exception = None):
    157      """Post a request and a response to the default model thread"""
    158      mt = get_model_thread()
    159      mt.post(request, response, exception)
    160