1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 """
29 Python structures to represent filters.
30 These structures can be transformed to QT forms.
31 """
32
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
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
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
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
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
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