1# This file is part of Gajim.
2#
3# Gajim is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published
5# by the Free Software Foundation; version 3 only.
6#
7# Gajim is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with Gajim.  If not, see <http://www.gnu.org/licenses/>.
14
15'''
16Network Events Controller.
17
18:author: Mateusz Biliński <mateusz@bilinski.it>
19:since: 10th August 2008
20:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
21:copyright: Copyright (2011) Yann Leboulanger <asterix@lagaule.org>
22:license: GPL
23'''
24
25from typing import List  # pylint: disable=unused-import
26
27from gajim.common import app
28
29
30class NetworkEventsController:
31    def __init__(self):
32        self.incoming_events_generators = {}
33        '''
34        Keys: names of events
35        Values: list of class objects that are subclasses
36        of `NetworkIncomingEvent`
37        '''
38        self.outgoing_events_generators = {}
39        '''
40        Keys: names of events
41        Values: list of class objects that are subclasses
42        of `NetworkOutgoingEvent`
43        '''
44
45    def register_incoming_event(self, event_class):
46        for base_event_name in event_class.base_network_events:
47            event_list = self.incoming_events_generators.setdefault(
48                base_event_name, [])
49            if event_class not in event_list:
50                event_list.append(event_class)
51
52    def unregister_incoming_event(self, event_class):
53        for base_event_name in event_class.base_network_events:
54            if base_event_name in self.incoming_events_generators:
55                self.incoming_events_generators[base_event_name].remove(
56                    event_class)
57
58    def register_outgoing_event(self, event_class):
59        for base_event_name in event_class.base_network_events:
60            event_list = self.outgoing_events_generators.setdefault(
61                base_event_name, [])
62            if event_class not in event_list:
63                event_list.append(event_class)
64
65    def unregister_outgoing_event(self, event_class):
66        for base_event_name in event_class.base_network_events:
67            if base_event_name in self.outgoing_events_generators:
68                self.outgoing_events_generators[base_event_name].remove(
69                    event_class)
70
71    def push_incoming_event(self, event_object):
72        if event_object.generate():
73            if not app.ged.raise_event(event_object.name, event_object):
74                self._generate_events_based_on_incoming_event(event_object)
75
76    def push_outgoing_event(self, event_object):
77        if event_object.generate():
78            if not app.ged.raise_event(event_object.name, event_object):
79                self._generate_events_based_on_outgoing_event(event_object)
80
81    def _generate_events_based_on_incoming_event(self, event_object):
82        '''
83        :return: True if even_object should be dispatched through Global
84        Events Dispatcher, False otherwise. This can be used to replace
85        base events with those that more data computed (easier to use
86        by handlers).
87        :note: replacing mechanism is not implemented currently, but will be
88        based on attribute in new network events object.
89        '''
90        base_event_name = event_object.name
91        if base_event_name in self.incoming_events_generators:
92            for new_event_class in self.incoming_events_generators[
93                    base_event_name]:
94                new_event_object = new_event_class(
95                    None, base_event=event_object)
96                if new_event_object.generate():
97                    if not app.ged.raise_event(new_event_object.name,
98                                               new_event_object):
99                        self._generate_events_based_on_incoming_event(
100                            new_event_object)
101
102    def _generate_events_based_on_outgoing_event(self, event_object):
103        '''
104        :return: True if even_object should be dispatched through Global
105        Events Dispatcher, False otherwise. This can be used to replace
106        base events with those that more data computed (easier to use
107        by handlers).
108        :note: replacing mechanism is not implemented currently, but will be
109        based on attribute in new network events object.
110        '''
111        base_event_name = event_object.name
112        if base_event_name in self.outgoing_events_generators:
113            for new_event_class in self.outgoing_events_generators[
114                    base_event_name]:
115                new_event_object = new_event_class(
116                    None, base_event=event_object)
117                if new_event_object.generate():
118                    if not app.ged.raise_event(new_event_object.name,
119                                               new_event_object):
120                        self._generate_events_based_on_outgoing_event(
121                            new_event_object)
122
123
124class EventHelper:
125    def __init__(self):
126        self.__event_handlers = []
127
128    def register_event(self, event_name, priority, handler):
129        self.__event_handlers.append((event_name, priority, handler))
130        app.ged.register_event_handler(event_name, priority, handler)
131
132    def register_events(self, events):
133        for handler in events:
134            self.__event_handlers.append(handler)
135            app.ged.register_event_handler(*handler)
136
137    def unregister_event(self, event_name, priority, handler):
138        self.__event_handlers.remove((event_name, priority, handler))
139        app.ged.register_event_handler(event_name, priority, handler)
140
141    def unregister_events(self):
142        for handler in self.__event_handlers:
143            app.ged.remove_event_handler(*handler)
144        self.__event_handlers.clear()
145
146
147class NetworkEvent:
148    name = ''
149
150    def __init__(self, new_name, **kwargs):
151        if new_name:
152            self.name = new_name
153
154        self.init()
155
156        self._set_kwargs_as_attributes(**kwargs)
157
158    def init(self):
159        pass
160
161    def generate(self):
162        '''
163        Generates new event (sets it's attributes) based on event object.
164
165        Base event object name is one of those in `base_network_events`.
166
167        Reference to base event object is stored in `self.base_event`
168        attribute.
169
170        Note that this is a reference, so modifications to that event object
171        are possible before dispatching to Global Events Dispatcher.
172
173        :return: True if generated event should be dispatched, False otherwise.
174        '''
175        return True
176
177    def _set_kwargs_as_attributes(self, **kwargs):
178        for k, v in kwargs.items():
179            if k not in ('name', 'base_network_events'):
180                setattr(self, k, v)
181
182    def _set_base_event_vars_as_attributes(self, event):
183        for k, v in vars(event).items():
184            if k not in ('name', 'base_network_events'):
185                setattr(self, k, v)
186
187
188class NetworkIncomingEvent(NetworkEvent):
189    base_network_events = []  # type: List[str]
190    '''
191    Names of base network events that new event is going to be generated on.
192    '''
193
194
195class NetworkOutgoingEvent(NetworkEvent):
196    base_network_events = []  # type: List[str]
197    '''
198    Names of base network events that new event is going to be generated on.
199    '''
200