Package camelot :: Package camelot :: Package view :: Module filters
[hide private]
[frames] | no frames]

Source Code for Module camelot.camelot.view.filters

  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  """
 
 29  Python structures to represent filters.
 
 30  These structures can be transformed to QT forms.
 
 31  """ 
 32  
 
33 -def structure_to_filter(structure):
34 """Convert a python data structure to a filter, using the following rules : 35 36 if structure is an instance of Filter, return structure 37 else create a GroupBoxFilter from the structure 38 """ 39 if isinstance(structure, Filter): 40 return structure 41 return GroupBoxFilter(structure)
42
43 -class Filter(object):
44 """Base class for filters""" 45
46 - def __init__(self, attribute, value_to_string=lambda x:unicode(x)):
47 """ 48 @param attribute: the attribute on which to filter, this attribute 49 may contain dots to indicate relationships that need to be followed, 50 eg. 'person.groups.name' 51 @param value_to_string: function that converts a value of the attribute to 52 a string that will be displayed in the filter 53 """ 54 self.attribute = attribute 55 self._value_to_string = value_to_string
56
57 - def render(self, parent, name, options):
58 """Render this filter as a qt object 59 @param parent: its parent widget 60 @param name: the name of the filter 61 @param options: the options that can be selected, where each option is a list 62 of tuples containting (option_name, query_decorator) 63 64 The name and the list of options can be fetched with get_name_and_options""" 65 raise NotImplementedException()
66
67 - def get_name_and_options(self, admin):
68 """return a tuple of the name of the filter and a list of options that can be selected. 69 Each option is a tuple of the name of the option, and a filter function to 70 decorate a query 71 @return: (filter_name, [(option_name, query_decorator), ...) 72 """ 73 from sqlalchemy.sql import select 74 from elixir import session 75 #session.bind = self.entity.table.metadata.bind 76 filter_names = [] 77 joins = [] 78 table = admin.entity.table 79 for field_name in self.attribute.split('.'): 80 attributes = admin.getFieldAttributes(field_name) 81 filter_names.append(attributes['name']) 82 if attributes['widget'] in ('one2many', 'many2many', 'many2one'): 83 admin = attributes['admin'] 84 joins.append(field_name) 85 if attributes['widget'] in ('many2one'): 86 table = admin.entity.table.join(table) 87 else: 88 table = admin.entity.table 89 90 91 col = getattr(admin.entity, field_name) 92 93 query = select([col], distinct=True, order_by=col.asc()).select_from(table) 94 95 def create_decorator(col, value, joins): 96 97 def decorator(q): 98 if joins: 99 q = q.join(joins, aliased=True) 100 return q.filter(col==value)
101 102 return decorator
103 104 options = [(self._value_to_string(value[0]), create_decorator(col, value[0], joins)) 105 for value in session.execute(query)] 106 return (filter_names[0],[('All', lambda q: q)] + options) 107
108 -class GroupBoxFilter(Filter):
109 """Filter where the items are displayed in a QGroupBox""" 110
111 - def render(self, parent, name, options):
112 113 from PyQt4 import QtCore, QtGui 114 115 class FilterWidget(QtGui.QGroupBox): 116 """A box containing a filter that can be applied on a table view, this filter is 117 based on the distinct values in a certain column""" 118 119 def __init__(self, name, choices, parent): 120 QtGui.QGroupBox.__init__(self, name, parent) 121 self.group = QtGui.QButtonGroup() 122 self.item = name 123 self.unique_values = [] 124 self.choices = None 125 self.setChoices(choices)
126 127 def emit_filter_changed(self, state): 128 self.emit(QtCore.SIGNAL('filter_changed'))
129 130 def setChoices(self, choices): 131 self.choices = choices 132 layout = QtGui.QVBoxLayout() 133 for i,name in enumerate([unicode(c[0]) for c in choices]): 134 button = QtGui.QRadioButton(name) 135 layout.addWidget(button) 136 self.group.addButton(button, i) 137 if i==0: 138 button.setChecked(True) 139 self.connect(button, QtCore.SIGNAL('toggled(bool)'), self.emit_filter_changed) 140 layout.addStretch() 141 self.setLayout(layout) 142 143 def decorate_query(self, query): 144 checked = self.group.checkedId() 145 if checked>=0: 146 return self.choices[checked][1](query) 147 return query 148 149 return FilterWidget(name, options, parent) 150
151 -class ComboBoxFilter(Filter):
152 """Filter where the items are displayed in a QComboBox""" 153
154 - def render(self, parent, name, options):
155 156 from PyQt4 import QtCore, QtGui 157 158 class FilterWidget(QtGui.QGroupBox): 159 160 def __init__(self, name, choices, parent): 161 super(FilterWidget, self).__init__(name, parent) 162 layout = QtGui.QVBoxLayout() 163 self.choices = choices 164 combobox = QtGui.QComboBox(self) 165 for i,(name,decorator) in enumerate(choices): 166 combobox.insertItem(i, unicode(name), QtCore.QVariant(decorator)) 167 layout.addWidget(combobox) 168 self.setLayout(layout) 169 self.current_index = 0 170 self.connect(combobox, QtCore.SIGNAL('currentIndexChanged(int)'), self.emit_filter_changed)
171 172 def emit_filter_changed(self, index): 173 self.current_index = index 174 self.emit(QtCore.SIGNAL('filter_changed'))
175 176 def decorate_query(self, query): 177 if self.current_index>=0: 178 return self.choices[self.current_index][1](query) 179 return query 180 181 return FilterWidget(name, options, parent) 182