summaryrefslogtreecommitdiff
path: root/lib/taurus/core/util/eventfilters.py
blob: f32359911244fe52cf958d73eb16dde875d8dbd3 (plain)
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#!/usr/bin/env python

# ###########################################################################
#
# This file is part of Taurus
#
# http://taurus-scada.org
#
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
#
# Taurus is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Taurus is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Taurus.  If not, see <http://www.gnu.org/licenses/>.
#
# ###########################################################################

"""event filters library to be used with
:meth:`taurus.qt.qtgui.base.TaurusBaseComponent.setFilters`
"""


def IGNORE_ALL(s, t, v):
    """Will discard all events"""
    return None


def ONLY_CHANGE(s, t, v):
    """Only change events pass"""
    from taurus.core import TaurusEventType

    if t == TaurusEventType.Change:
        return s, t, v
    else:
        return None


def IGNORE_CHANGE(s, t, v):
    """Config events are discarded"""
    from taurus.core import TaurusEventType

    if t != TaurusEventType.Change:
        return s, t, v
    else:
        return None


def ONLY_CHANGE_AND_PERIODIC(s, t, v):
    """Only change events pass"""
    from taurus.core import TaurusEventType

    if t in [TaurusEventType.Change, TaurusEventType.Periodic]:
        return s, t, v
    else:
        return None


def IGNORE_CHANGE_AND_PERIODIC(s, t, v):
    """Config events are discarded"""
    from taurus.core import TaurusEventType

    if t not in [TaurusEventType.Change, TaurusEventType.Periodic]:
        return s, t, v
    else:
        return None


def ONLY_CONFIG(s, t, v):
    """Only config events pass"""
    from taurus.core import TaurusEventType

    if t == TaurusEventType.Config:
        return s, t, v
    else:
        return None


def IGNORE_CONFIG(s, t, v):
    """Config events are discarded"""
    from taurus.core import TaurusEventType

    if t != TaurusEventType.Config:
        return s, t, v
    else:
        return None


def IGNORE_FAKE(s, t, v):
    """Only events with actual value (!=None) pass"""
    if v is not None:
        return s, t, v
    else:
        return None


def ONLY_VALID(s, t, v):
    """Only events whose quality is VALID pass"""
    from taurus.core import AttrQuality

    if t == AttrQuality.ATTR_VALID:
        return s, t, v
    else:
        return None


class EventValueMap(dict):
    """A filter destined to change the original value into another one
    according to a given map. Example:

        filter = EventValueMap({1:"OPEN", 2:"CHANGING", 3:"CLOSED"})

    this will create a filter that changes the integer value of the event
    into a string. The event type is changed according to the python type in
    the map value.

    For now it only supports simple types: str, int, long, float, bool
    """

    def __call__(self, s, t, v):
        import copy
        from taurus.core import TaurusEventType, DataType

        if t not in (TaurusEventType.Change, TaurusEventType.Periodic):
            return s, t, v
        if v is None:
            return s, t, v

        # make a copy
        v = copy.copy(v)

        v.value = self.get(v.rvalue, v.rvalue)

        v.type = DataType.from_python_type(type(v.rvalue), v.type)
        return s, t, v


class RepeatedEventFilter(object):
    """
    The instances of this class will be callables that can be used as filters
    of repeated-value events.
    If the event type is Change or Periodic, it will only pass when its
    evt_value.value is different from that of the last event received from the
    same source and type. If evt_value.value is not available in the current
    event, the whole evt_value is used for comparison and as a future
    reference.

    This is useful to avoid processing repetitive events.

    Note that you cannot use this class as a filter: you need to use an
    instance of it.

    Note 2: Use a different instance each time you insert this filter
    into a different widget unless you *really* know what you are doing.

    Example of usage::

        filters = [RepeatedEventFilter(), IGNORE_CONFIG]
        filterEvent(s, t, v, filters)
    """

    def __init__(self):
        self._lastValues = {}

    def __call__(self, s, t, v):
        # restrict this  filter only to change and periodic events.
        if ONLY_CHANGE_AND_PERIODIC(s, t, v) is None:
            return s, t, v
        # block event if we recorded one before with same src, type and v.value
        new_value = getattr(v, "value", v)
        try:
            if self._lastValues[(s, t)] == new_value:
                return None
        except KeyError:
            pass
        # if it was't blocked, store src, type and v.value for future checks
        self._lastValues[(s, t)] = new_value
        return s, t, v


def filterEvent(evt_src=-1, evt_type=-1, evt_value=-1, filters=()):
    """The event is processed by each and all filters in strict order
    unless one of them returns None (in which case the event is discarded)

    :param evt_src: object that triggered the event
    :type evt_src: object
    :param evt_type: type of event
    :type evt_type: TaurusEventType
    :param evt_value: event value
    :type evt_value: object
    :param filters: a sequence of callables, each returning either None (to
        discard the event) or the tuple (with possibly transformed values) of
        (evt_src, evt_type, evt_value)
    :type filters: sequence<callable>
    :return: The result of piping the event through the given filters.
    :rtype: None or tuple
    """
    evt = evt_src, evt_type, evt_value

    for f in filters:
        evt = f(*evt)
        if evt is None:
            return None
    return evt