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