handle outgoing messages with events. Fixes #6743
[gajim.git] / src / message_control.py
blob14efb42dafdf8b1420265f176d3cbadcdf0fd231
1 # -*- coding:utf-8 -*-
2 ## src/message_control.py
3 ##
4 ## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com>
5 ## Nikos Kouremenos <kourem AT gmail.com>
6 ## Copyright (C) 2006-2007 Jean-Marie Traissard <jim AT lapin.org>
7 ## Travis Shirk <travis AT pobox.com>
8 ## Copyright (C) 2006-2010 Yann Leboulanger <asterix AT lagaule.org>
9 ## Copyright (C) 2007 Julien Pivotto <roidelapluie AT gmail.com>
10 ## Stephan Erb <steve-e AT h3c.de>
11 ## Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
12 ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
14 ## This file is part of Gajim.
16 ## Gajim is free software; you can redistribute it and/or modify
17 ## it under the terms of the GNU General Public License as published
18 ## by the Free Software Foundation; version 3 only.
20 ## Gajim is distributed in the hope that it will be useful,
21 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 ## GNU General Public License for more details.
25 ## You should have received a copy of the GNU General Public License
26 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
29 import gtkgui_helpers
31 from common import gajim
32 from common import helpers
33 from common import ged
34 from common.stanza_session import EncryptedStanzaSession, ArchivingStanzaSession
36 # Derived types MUST register their type IDs here if custom behavor is required
37 TYPE_CHAT = 'chat'
38 TYPE_GC = 'gc'
39 TYPE_PM = 'pm'
41 ####################
43 class MessageControl(object):
44 """
45 An abstract base widget that can embed in the gtk.Notebook of a
46 MessageWindow
47 """
49 def __init__(self, type_id, parent_win, widget_name, contact, account, resource = None):
50 # dict { cb id : widget}
51 # keep all registered callbacks of widgets, created by self.xml
52 self.handlers = {}
53 self.type_id = type_id
54 self.parent_win = parent_win
55 self.widget_name = widget_name
56 self.contact = contact
57 self.account = account
58 self.hide_chat_buttons = False
59 self.resource = resource
61 self.session = None
63 gajim.last_message_time[self.account][self.get_full_jid()] = 0
65 self.xml = gtkgui_helpers.get_gtk_builder('%s.ui' % widget_name)
66 self.widget = self.xml.get_object('%s_hbox' % widget_name)
68 gajim.ged.register_event_handler('message-outgoing', ged.OUT_GUI1,
69 self._nec_message_outgoing)
71 def get_full_jid(self):
72 fjid = self.contact.jid
73 if self.resource:
74 fjid += '/' + self.resource
75 return fjid
77 def set_control_active(self, state):
78 """
79 Called when the control becomes active (state is True) or inactive (state
80 is False)
81 """
82 pass # Derived classes MUST implement this method
84 def minimizable(self):
85 """
86 Called to check if control can be minimized
88 Derived classes MAY implement this.
89 """
90 return False
92 def safe_shutdown(self):
93 """
94 Called to check if control can be closed without loosing data.
95 returns True if control can be closed safely else False
97 Derived classes MAY implement this.
98 """
99 return True
101 def allow_shutdown(self, method, on_response_yes, on_response_no,
102 on_response_minimize):
104 Called to check is a control is allowed to shutdown.
105 If a control is not in a suitable shutdown state this method
106 should call on_response_no, else on_response_yes or
107 on_response_minimize
109 Derived classes MAY implement this.
111 on_response_yes(self)
113 def shutdown(self):
115 Derived classes MUST implement this
117 gajim.ged.remove_event_handler('message-outgoing', ged.OUT_GUI1,
118 self._nec_message_outgoing)
120 def repaint_themed_widgets(self):
122 Derived classes SHOULD implement this
124 pass
126 def update_ui(self):
128 Derived classes SHOULD implement this
130 pass
132 def toggle_emoticons(self):
134 Derived classes MAY implement this
136 pass
138 def update_font(self):
140 Derived classes SHOULD implement this
142 pass
144 def update_tags(self):
146 Derived classes SHOULD implement this
148 pass
150 def get_tab_label(self, chatstate):
152 Return a suitable tab label string. Returns a tuple such as: (label_str,
153 color) either of which can be None if chatstate is given that means we
154 have HE SENT US a chatstate and we want it displayed
156 Derivded classes MUST implement this.
158 # Return a markup'd label and optional gtk.Color in a tupple like:
159 # return (label_str, None)
160 pass
162 def get_tab_image(self, count_unread=True):
163 # Return a suitable tab image for display.
164 # None clears any current label.
165 return None
167 def prepare_context_menu(self):
169 Derived classes SHOULD implement this
171 return None
173 def chat_buttons_set_visible(self, state):
175 Derived classes MAY implement this
177 self.hide_chat_buttons = state
179 def got_connected(self):
180 pass
182 def got_disconnected(self):
183 pass
185 def get_specific_unread(self):
186 return len(gajim.events.get_events(self.account,
187 self.contact.jid))
189 def set_session(self, session):
190 oldsession = None
191 if hasattr(self, 'session'):
192 oldsession = self.session
194 if oldsession and session == oldsession:
195 return
197 self.session = session
199 if session:
200 session.control = self
202 if oldsession:
203 oldsession.control = None
205 jid = self.contact.jid
206 if self.resource:
207 jid += '/' + self.resource
209 crypto_changed = bool(session and isinstance(session,
210 EncryptedStanzaSession) and session.enable_encryption) != \
211 bool(oldsession and isinstance(oldsession,
212 EncryptedStanzaSession) and oldsession.enable_encryption)
214 archiving_changed = bool(session and isinstance(session,
215 ArchivingStanzaSession) and session.archiving) != \
216 bool(oldsession and isinstance(oldsession,
217 ArchivingStanzaSession) and oldsession.archiving)
219 if crypto_changed or archiving_changed:
220 self.print_session_details()
222 def _nec_message_outgoing(self, obj):
223 # Send the given message to the active tab.
224 # Doesn't return None if error
225 if obj.account != self.account:
226 return
228 obj.jid = self.contact.jid
229 obj.message = helpers.remove_invalid_xml_chars(obj.message)
230 obj.original_message = obj.message
232 conn = gajim.connections[self.account]
234 if not self.session:
235 if not obj.resource:
236 if self.resource:
237 obj.resource = self.resource
238 else:
239 obj.resource = self.contact.resource
240 sess = conn.find_controlless_session(obj.jid, resource=obj.resource)
242 if self.resource:
243 obj.jid += '/' + self.resource
245 if not sess:
246 if self.type_id == TYPE_PM:
247 sess = conn.make_new_session(obj.jid, type_='pm')
248 else:
249 sess = conn.make_new_session(obj.jid)
251 self.set_session(sess)
253 obj.session = self.session