message_control.py 6.94 KB
Newer Older
Philipp Hörist's avatar
Philipp Hörist committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com>
#                    Nikos Kouremenos <kourem AT gmail.com>
# Copyright (C) 2006-2007 Jean-Marie Traissard <jim AT lapin.org>
#                         Travis Shirk <travis AT pobox.com>
# Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
# Copyright (C) 2007 Julien Pivotto <roidelapluie AT gmail.com>
#                    Stephan Erb <steve-e AT h3c.de>
# Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
# Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
#
# This file is part of Gajim.
#
# Gajim is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; version 3 only.
#
# Gajim 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
roidelapluie's avatar
roidelapluie committed
24

25
import uuid
26

27
from gajim.common import app
André's avatar
André committed
28 29
from gajim.common import helpers
from gajim.common import ged
30

31 32
from gajim.gtk.util import get_builder

33 34 35 36 37 38 39
# Derived types MUST register their type IDs here if custom behavor is required
TYPE_CHAT = 'chat'
TYPE_GC = 'gc'
TYPE_PM = 'pm'

####################

40
class MessageControl:
41
    """
42
    An abstract base widget that can embed in the Gtk.Notebook of a
43 44 45
    MessageWindow
    """

46 47
    def __init__(self, type_id, parent_win, widget_name, contact, account,
    resource=None):
48 49 50 51 52 53 54 55 56
        # dict { cb id : widget}
        # keep all registered callbacks of widgets, created by self.xml
        self.handlers = {}
        self.type_id = type_id
        self.parent_win = parent_win
        self.widget_name = widget_name
        self.contact = contact
        self.account = account
        self.resource = resource
57 58 59
        # control_id is a unique id for the control,
        # its used as action name for actions that belong to a control
        self.control_id = str(uuid.uuid4())
60 61
        self.session = None

62
        app.last_message_time[self.account][self.get_full_jid()] = 0
63

64
        self.xml = get_builder('%s.ui' % widget_name)
65
        self.xml.connect_signals(self)
66
        self.widget = self.xml.get_object('%s_hbox' % widget_name)
67

68
        app.ged.register_event_handler('message-outgoing', ged.OUT_GUI1,
69 70
            self._nec_message_outgoing)

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
    def get_full_jid(self):
        fjid = self.contact.jid
        if self.resource:
            fjid += '/' + self.resource
        return fjid

    def set_control_active(self, state):
        """
        Called when the control becomes active (state is True) or inactive (state
        is False)
        """
        pass  # Derived classes MUST implement this method

    def minimizable(self):
        """
        Called to check if control can be minimized

        Derived classes MAY implement this.
        """
        return False

    def safe_shutdown(self):
        """
Alexander Krotov's avatar
Alexander Krotov committed
94
        Called to check if control can be closed without losing data.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
        returns True if control can be closed safely else False

        Derived classes MAY implement this.
        """
        return True

    def allow_shutdown(self, method, on_response_yes, on_response_no,
                    on_response_minimize):
        """
        Called to check is a control is allowed to shutdown.
        If a control is not in a suitable shutdown state this method
        should call on_response_no, else on_response_yes or
        on_response_minimize

        Derived classes MAY implement this.
        """
        on_response_yes(self)

    def shutdown(self):
        """
        Derived classes MUST implement this
        """
117
        app.ged.remove_event_handler('message-outgoing', ged.OUT_GUI1,
118
            self._nec_message_outgoing)
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

    def repaint_themed_widgets(self):
        """
        Derived classes SHOULD implement this
        """
        pass

    def update_ui(self):
        """
        Derived classes SHOULD implement this
        """
        pass

    def toggle_emoticons(self):
        """
        Derived classes MAY implement this
        """
        pass

    def update_font(self):
        """
        Derived classes SHOULD implement this
        """
        pass

    def update_tags(self):
        """
        Derived classes SHOULD implement this
        """
        pass

    def get_tab_label(self, chatstate):
        """
        Return a suitable tab label string. Returns a tuple such as: (label_str,
        color) either of which can be None if chatstate is given that means we
        have HE SENT US a chatstate and we want it displayed

        Derivded classes MUST implement this.
        """
158
        # Return a markup'd label and optional Gtk.Color in a tuple like:
159 160 161 162 163 164 165 166
        # return (label_str, None)
        pass

    def get_tab_image(self, count_unread=True):
        # Return a suitable tab image for display.
        # None clears any current label.
        return None

Philipp Hörist's avatar
Philipp Hörist committed
167
    def prepare_context_menu(self, hide_buttonbar_items=False):
168 169 170 171 172 173 174 175 176 177 178 179
        """
        Derived classes SHOULD implement this
        """
        return None

    def got_connected(self):
        pass

    def got_disconnected(self):
        pass

    def get_specific_unread(self):
180
        return len(app.events.get_events(self.account,
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
                self.contact.jid))

    def set_session(self, session):
        oldsession = None
        if hasattr(self, 'session'):
            oldsession = self.session

        if oldsession and session == oldsession:
            return

        self.session = session

        if session:
            session.control = self

196
        if session and oldsession:
197 198
            oldsession.control = None

199 200 201
    def remove_session(self, session):
        if session != self.session:
            return
Yann Leboulanger's avatar
Yann Leboulanger committed
202
        self.session.control = None
Yann Leboulanger's avatar
Yann Leboulanger committed
203
        self.session = None
204

205
    def _nec_message_outgoing(self, obj):
206 207
        # Send the given message to the active tab.
        # Doesn't return None if error
208
        if obj.control != self:
209
            return
210

211
        obj.message = helpers.remove_invalid_xml_chars(obj.message)
212

213
        conn = app.connections[self.account]
214 215

        if not self.session:
216
            if (not obj.resource and
217
                    obj.jid != app.get_jid_from_account(self.account)):
218
                if self.resource:
219
                    obj.resource = self.resource
220
                else:
221 222
                    obj.resource = self.contact.resource
            sess = conn.find_controlless_session(obj.jid, resource=obj.resource)
223 224

            if self.resource:
225
                obj.jid += '/' + self.resource
226 227 228

            if not sess:
                if self.type_id == TYPE_PM:
229
                    sess = conn.make_new_session(obj.jid, type_='pm')
230
                else:
231
                    sess = conn.make_new_session(obj.jid)
232 233 234

            self.set_session(sess)

235
        obj.session = self.session