Package Camelot :: Package camelot :: Package view :: Package proxy :: Module queryproxy |
[frames] | no frames]

# Source Code for Module Camelot.camelot.view.proxy.queryproxy

      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  """Proxies representing the results of a query"""
     29
     30  from PyQt4.QtCore import Qt
     31
     32  import logging
     33  logger = logging.getLogger('camelot.view.proxy.queryproxy')
     34
     35  from collection_proxy import CollectionProxy, strip_data_from_object
     36  from camelot.view.model_thread import model_function, gui_function, post
     37
     38
     39 -class QueryTableProxy(CollectionProxy):
     40      """The QueryTableProxy contains a limited copy of the data in the Elixir
     41      model, which is fetched from the database to be used as the model for a
     42      QTableView
     43      """
     44
     45 -    def __init__(self, admin, query_getter, columns_getter,
     46                   max_number_of_rows=10, edits=None):
     47          """@param query_getter: a model_thread function that returns a query"""
     48          logger.debug('initialize query table')
     49          self._query_getter = query_getter
     50          self._sort_decorator = None
     51          #rows appended to the table which have not yet been flushed to the
     52          #database, and as such cannot be a result of the query
     53          self._appended_rows = []
     54          CollectionProxy.__init__(self, admin, lambda: [],
     55                                   columns_getter, max_number_of_rows=10, edits=None)
     56
     57 -    def get_query_getter(self):
     58          if not self._sort_decorator:
     59              return self._query_getter
     60          else:
     61
     62              def sorted_query_getter():
     63                  return self._sort_decorator(self._query_getter())
     64
     65              return sorted_query_getter
     66
     67      @model_function
     68 -    def _clean_appended_rows(self):
     69          """Remove those rows from appended rows that have been flushed"""
     70          flushed_rows = []
     71          for o in self._appended_rows:
     72              if o.id:
     73                  flushed_rows.append(o)
     74          for o in flushed_rows:
     75              self._appended_rows.remove(o)
     76
     77      @model_function
     78 -    def getRowCount(self):
     79          self._clean_appended_rows()
     80          return self.get_query_getter()().count() + len(self._appended_rows)
     81
     82      @gui_function
     83 -    def setQuery(self, query_getter):
     84          """Set the query and refresh the view"""
     85          self._query_getter = query_getter
     86          self.refresh()
     87
     88 -    def get_collection_getter(self):
     89
     90          def collection_getter():
     91              return self.get_query_getter()().all()
     92
     93          return collection_getter
     94
     95      @gui_function
     96 -    def sort( self, column, order ):
     97
     98          def create_set_sort_decorator(column, order):
     99
    100              def set_sort_decorator():
    101                  from sqlalchemy import orm
    102                  from sqlalchemy.exceptions import InvalidRequestError
    103                  field_name = self._columns[column][0]
    104                  class_attribute = getattr(self.admin.entity, field_name)
    105                  mapper = orm.class_mapper(self.admin.entity)
    106                  try:
    107                      mapper.get_property(
    108                          field_name,
    109                          resolve_synonyms=True
    110                      )
    111                  except InvalidRequestError:
    112                      #
    113                      # If the field name is not a property of the mapper, we cannot
    114                      # sort it using sql
    115                      #
    116                      return self._rows
    117
    118                  def create_sort_decorator(class_attribute, order):
    119
    120                      def sort_decorator(query):
    121                          if order:
    122                              return query.order_by(class_attribute.desc())
    123                          else:
    124                              return query.order_by(class_attribute)
    125
    126                      return sort_decorator
    127
    128
    129                  self._sort_decorator = create_sort_decorator(class_attribute, order)
    130                  return self._rows
    131
    132              return set_sort_decorator
    133
    134          post( create_set_sort_decorator(column, order), self._refresh_content )
    135
    136 -    def append(self, o):
    137          """Add an object to this collection, used when inserting a new
    138          row, overwrite this method for specific behaviour in subclasses"""
    139          if not o.id:
    140              self._appended_rows.append(o)
    141          self._rows = self._rows + 1
    142
    143 -    def remove(self, o):
    144          if o in self._appended_rows:
    145              self._appended_rows.remove(o)
    146          self._rows = self._rows - 1
    147
    148      @model_function
    149 -    def getData(self):
    150          """Generator for all the data queried by this proxy"""
    151          for _i,o in enumerate(self.get_query_getter()().all()):
    152              yield strip_data_from_object(o, self.getColumns())
    153
    154      @model_function
    155 -    def _extend_cache(self, offset, limit):
    156          """Extend the cache around row"""
    157          q = self.get_query_getter()().offset(offset).limit(limit)
    158          columns = self.getColumns()
    159          for i, o in enumerate(q.all()):
    160              self._add_data(columns, i+offset, o)
    161          rows_in_query = (self._rows - len(self._appended_rows))
    162          # Verify if rows that have not yet been flushed have been requested
    163          if offset+limit>=rows_in_query:
    164              for row in range(max(rows_in_query,offset), min(offset+limit, self._rows)):
    165                  o = self._get_object(row)
    166                  self._add_data(columns, row, o)
    167          return (offset, limit)
    168
    169      @model_function
    170 -    def _get_object(self, row):
    171          """Get the object corresponding to row"""
    172          if self._rows > 0:
    173              self._clean_appended_rows()
    174              rows_in_query = (self._rows - len(self._appended_rows))
    175              if row >= rows_in_query:
    176                  return self._appended_rows[row - rows_in_query]
    177              # first try to get the primary key out of the cache, if it's not
    178              # there, query the collection_getter
    179              try:
    180                  return self.cache[Qt.EditRole].get_entity_at_row(row)
    181              except KeyError:
    182                  pass
    183              # momentary hack for list error that prevents forms to be closed
    184              res = self.get_query_getter()().offset(row)
    185              if isinstance(res, list):
    186                  res = res[0]
    187              # @todo: remove this try catch and find out why it sometimes fails
    188              try:
    189                  return res.limit(1).first()
    190              except:
    191                  pass
    192