info_wins.py 13 KB
Newer Older
1 2 3 4 5
"""
Module defining all the "info wins", ie the bar which is on top of the
info buffer in normal tabs
"""

6 7
from typing import Optional, Dict, TYPE_CHECKING, Any

8 9 10
import logging
log = logging.getLogger(__name__)

11 12
from poezio.common import safeJID
from poezio.config import config
13

Link Mauve's avatar
Link Mauve committed
14
from poezio.windows.base_wins import Win
15
from poezio.ui.funcs import truncate_nick
16
from poezio.theming import get_theme, to_curses_attr
17

18 19 20 21 22
if TYPE_CHECKING:
    from poezio.user import User
    from poezio.tabs import MucTab
    from poezio.windows import TextWin

mathieui's avatar
mathieui committed
23

24 25 26 27 28
class InfoWin(Win):
    """
    Base class for all the *InfoWin, used in various tabs. For example
    MucInfoWin, etc. Provides some useful methods.
    """
mathieui's avatar
mathieui committed
29

30 31
    __slots__ = ()

32 33 34 35 36 37 38 39 40 41 42
    def __init__(self):
        Win.__init__(self)

    def print_scroll_position(self, window):
        """
        Print, like in Weechat, a -MORE(n)- where n
        is the number of available lines to scroll
        down
        """
        if window.pos > 0:
            plus = ' -MORE(%s)-' % window.pos
mathieui's avatar
mathieui committed
43 44 45
            self.addstr(plus,
                        to_curses_attr(get_theme().COLOR_SCROLLABLE_NUMBER))

46 47 48 49 50

class XMLInfoWin(InfoWin):
    """
    Info about the latest xml filter used and the state of the buffer.
    """
mathieui's avatar
mathieui committed
51

52 53
    __slots__ = ()

54 55 56 57 58
    def __init__(self):
        InfoWin.__init__(self)

    def refresh(self, filter_t='', filter='', window=None):
        log.debug('Refresh: %s', self.__class__.__name__)
59 60 61 62 63 64 65 66 67 68
        self._win.erase()
        bar = to_curses_attr(get_theme().COLOR_INFORMATION_BAR)
        if not filter_t:
            self.addstr('[No filter]', bar)
        else:
            info = '[%s] %s' % (filter_t, filter)
            self.addstr(info, bar)
        self.print_scroll_position(window)
        self.finish_line(get_theme().COLOR_INFORMATION_BAR)
        self._refresh()
69

mathieui's avatar
mathieui committed
70

71 72
class PrivateInfoWin(InfoWin):
    """
73
    The line above the information window, displaying information
74 75
    about the MUC user we are talking to
    """
mathieui's avatar
mathieui committed
76

77 78
    __slots__ = ()

79 80 81
    def __init__(self):
        InfoWin.__init__(self)

82
    def refresh(self, name, window, chatstate, information):
83
        log.debug('Refresh: %s', self.__class__.__name__)
84 85 86 87
        self._win.erase()
        self.write_room_name(name)
        self.print_scroll_position(window)
        self.write_chatstate(chatstate)
88
        self.write_additional_information(information, name)
89 90
        self.finish_line(get_theme().COLOR_INFORMATION_BAR)
        self._refresh()
91

92
    def write_additional_information(self, information, jid):
93
        """
94
        Write all information added by plugins by getting the
95 96
        value returned by the callbacks.
        """
97 98
        for plugin in information.values():
            self.addstr(plugin(jid),
mathieui's avatar
mathieui committed
99
                        to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
100

101 102
    def write_room_name(self, name):
        jid = safeJID(name)
103
        room_name, nick = jid.bare, jid.resource
104 105
        theme = get_theme()
        self.addstr(nick, to_curses_attr(theme.COLOR_PRIVATE_NAME))
106
        txt = ' from room %s' % room_name
107
        self.addstr(txt, to_curses_attr(theme.COLOR_INFORMATION_BAR))
108 109 110

    def write_chatstate(self, state):
        if state:
mathieui's avatar
mathieui committed
111 112 113
            self.addstr(' %s' % (state, ),
                        to_curses_attr(get_theme().COLOR_INFORMATION_BAR))

114 115 116

class MucListInfoWin(InfoWin):
    """
117
    The live above the information window, displaying informatios
118 119
    about the muc server being listed
    """
mathieui's avatar
mathieui committed
120

121 122
    __slots__ = ('message')

123 124 125 126 127 128
    def __init__(self, message=''):
        InfoWin.__init__(self)
        self.message = message

    def refresh(self, name=None, window=None):
        log.debug('Refresh: %s', self.__class__.__name__)
129
        self._win.erase()
130
        theme = get_theme()
131
        if name:
mathieui's avatar
mathieui committed
132
            self.addstr(name,
133
                        to_curses_attr(theme.COLOR_INFORMATION_BAR))
134
        else:
mathieui's avatar
mathieui committed
135
            self.addstr(self.message,
136
                        to_curses_attr(theme.COLOR_INFORMATION_BAR))
137 138
        if window:
            self.print_scroll_position(window)
139
        self.finish_line(theme.COLOR_INFORMATION_BAR)
140
        self._refresh()
141

mathieui's avatar
mathieui committed
142

143 144
class ConversationInfoWin(InfoWin):
    """
145
    The line above the information window, displaying information
146 147 148
    about the user we are talking to
    """

149 150
    __slots__ = ()

151 152 153
    def __init__(self):
        InfoWin.__init__(self)

154
    def refresh(self, jid, contact, window, chatstate, information):
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
        # contact can be None, if we receive a message
        # from someone not in our roster. In this case, we display
        # only the maximum information from the message we can get.
        log.debug('Refresh: %s', self.__class__.__name__)
        jid = safeJID(jid)
        if contact:
            if jid.resource:
                resource = contact[jid.full]
            else:
                resource = contact.get_highest_priority_resource()
        else:
            resource = None
        # if contact is None, then resource is None too:
        # user is not in the roster so we know almost nothing about it
        # If contact is a Contact, then
        # resource can now be a Resource: user is in the roster and online
        # or resource is None: user is in the roster but offline
172
        self._win.erase()
173 174
        if config.get('show_jid_in_conversations'):
            self.write_contact_jid(jid)
175
        self.write_contact_information(contact)
176 177 178
        self.write_resource_information(resource)
        self.print_scroll_position(window)
        self.write_chatstate(chatstate)
179
        self.write_additional_information(information, jid)
180 181
        self.finish_line(get_theme().COLOR_INFORMATION_BAR)
        self._refresh()
182

183
    def write_additional_information(self, information, jid):
184
        """
185
        Write all information added by plugins by getting the
186 187
        value returned by the callbacks.
        """
188
        color = to_curses_attr(get_theme().COLOR_INFORMATION_BAR)
189
        for plugin in information.values():
190
            self.addstr(plugin(jid), color)
191 192 193

    def write_resource_information(self, resource):
        """
194
        Write the information about the resource
195 196 197 198 199
        """
        if not resource:
            presence = "unavailable"
        else:
            presence = resource.presence
200 201
        theme = get_theme()
        color = theme.color_show(presence)
202
        if not presence:
203 204
            presence = theme.CHAR_STATUS
        self.addstr('[', to_curses_attr(theme.COLOR_INFORMATION_BAR))
205 206
        self.addstr(presence, to_curses_attr(color))
        if resource and resource.status:
ge0rg's avatar
ge0rg committed
207
            shortened = resource.status[:20] + (resource.status[:20] and '…')
mathieui's avatar
mathieui committed
208
            self.addstr(' %s' % shortened,
209 210
                        to_curses_attr(theme.COLOR_INFORMATION_BAR))
        self.addstr(']', to_curses_attr(theme.COLOR_INFORMATION_BAR))
211

212
    def write_contact_information(self, contact):
213
        """
214
        Write the information about the contact
215
        """
216
        color = to_curses_attr(get_theme().COLOR_INFORMATION_BAR)
217
        if not contact:
218
            self.addstr("(contact not in roster)", color)
219 220 221
            return
        display_name = contact.name
        if display_name:
222
            self.addstr('%s ' % (display_name), color)
223 224 225 226 227

    def write_contact_jid(self, jid):
        """
        Just write the jid that we are talking to
        """
228
        theme = get_theme()
229
        color = to_curses_attr(theme.COLOR_INFORMATION_BAR)
230
        self.addstr('[', color)
mathieui's avatar
mathieui committed
231
        self.addstr(jid.full,
232 233
                    to_curses_attr(theme.COLOR_CONVERSATION_NAME))
        self.addstr('] ', color)
234 235 236

    def write_chatstate(self, state):
        if state:
mathieui's avatar
mathieui committed
237 238 239
            self.addstr(' %s' % (state, ),
                        to_curses_attr(get_theme().COLOR_INFORMATION_BAR))

240 241

class DynamicConversationInfoWin(ConversationInfoWin):
242 243
    __slots__ = ()

244 245 246 247 248
    def write_contact_jid(self, jid):
        """
        Just displays the resource in an other color
        """
        log.debug("write_contact_jid DynamicConversationInfoWin, jid: %s",
mathieui's avatar
mathieui committed
249
                  jid.resource)
250
        theme = get_theme()
251
        color = to_curses_attr(theme.COLOR_INFORMATION_BAR)
252
        self.addstr('[', color)
mathieui's avatar
mathieui committed
253
        self.addstr(jid.bare,
254
                    to_curses_attr(theme.COLOR_CONVERSATION_NAME))
255
        if jid.resource:
mathieui's avatar
mathieui committed
256 257
            self.addstr(
                "/%s" % (jid.resource, ),
258 259
                to_curses_attr(theme.COLOR_CONVERSATION_RESOURCE))
        self.addstr('] ', color)
260

mathieui's avatar
mathieui committed
261

262 263
class MucInfoWin(InfoWin):
    """
264
    The line just above the information window, displaying information
265 266
    about the MUC we are viewing
    """
mathieui's avatar
mathieui committed
267

268 269
    __slots__ = ()

270
    def __init__(self) -> None:
271 272
        InfoWin.__init__(self)

273 274 275 276 277 278 279
    def refresh(
        self,
        room: 'MucTab',
        window: Optional['TextWin'] = None,
        user: Optional['User'] = None,
        information: Optional[Dict[str, Any]] = None
    ) -> None:
280
        log.debug('Refresh: %s', self.__class__.__name__)
281
        self._win.erase()
282
        self.write_room_name(room)
283 284 285
        self.write_participants_number(room)
        self.write_own_nick(room)
        self.write_disconnected(room)
286
        self.write_role(room, user)
287
        if information:
288
            self.write_additional_information(information, room.name)
289 290 291 292
        if window:
            self.print_scroll_position(window)
        self.finish_line(get_theme().COLOR_INFORMATION_BAR)
        self._refresh()
293

294 295 296 297 298
    def write_additional_information(self, information, jid):
        """
        Write all information added by plugins by getting the
        value returned by the callbacks.
        """
299
        color = to_curses_attr(get_theme().COLOR_INFORMATION_BAR)
300
        for plugin in information.values():
301
            self.addstr(plugin(jid), color)
302

303
    def write_room_name(self, room):
304 305 306
        theme = get_theme()
        color = to_curses_attr(theme.COLOR_INFORMATION_BAR)
        self.addstr('[', color)
307
        self.addstr(room.name,
308 309
                    to_curses_attr(theme.COLOR_GROUPCHAT_NAME))
        self.addstr(']', color)
310 311

    def write_participants_number(self, room):
312 313 314
        theme = get_theme()
        color = to_curses_attr(theme.COLOR_INFORMATION_BAR)
        self.addstr('{', color)
mathieui's avatar
mathieui committed
315 316
        self.addstr(
            str(len(room.users)),
317 318
            to_curses_attr(theme.COLOR_GROUPCHAT_NAME))
        self.addstr('} ', color)
319 320 321 322 323 324

    def write_disconnected(self, room):
        """
        Shows a message if the room is not joined
        """
        if not room.joined:
mathieui's avatar
mathieui committed
325 326
            self.addstr(' -!- Not connected ',
                        to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
327 328 329 330 331 332 333 334

    def write_own_nick(self, room):
        """
        Write our own nick in the info bar
        """
        nick = room.own_nick
        if not nick:
            return
mathieui's avatar
mathieui committed
335 336 337
        self.addstr(
            truncate_nick(nick, 13),
            to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
338

339
    def write_role(self, room, user):
340 341 342
        """
        Write our own role and affiliation
        """
343
        if not user:
344 345
            return
        txt = ' ('
346 347 348
        if user.affiliation != 'none':
            txt += user.affiliation + ', '
        txt += user.role + ')'
349 350
        self.addstr(txt, to_curses_attr(get_theme().COLOR_INFORMATION_BAR))

mathieui's avatar
mathieui committed
351

352 353 354 355
class ConversationStatusMessageWin(InfoWin):
    """
    The upper bar displaying the status message of the contact
    """
mathieui's avatar
mathieui committed
356

357 358
    __slots__ = ()

359 360 361 362 363 364 365 366 367 368 369 370 371
    def __init__(self):
        InfoWin.__init__(self)

    def refresh(self, jid, contact):
        log.debug('Refresh: %s', self.__class__.__name__)
        jid = safeJID(jid)
        if contact:
            if jid.resource:
                resource = contact[jid.full]
            else:
                resource = contact.get_highest_priority_resource()
        else:
            resource = None
372 373 374 375 376
        self._win.erase()
        if resource:
            self.write_status_message(resource)
        self.finish_line(get_theme().COLOR_INFORMATION_BAR)
        self._refresh()
377 378

    def write_status_message(self, resource):
mathieui's avatar
mathieui committed
379 380 381
        self.addstr(resource.status,
                    to_curses_attr(get_theme().COLOR_INFORMATION_BAR))

382

mathieui's avatar
mathieui committed
383
class BookmarksInfoWin(InfoWin):
384 385
    __slots__ = ()

mathieui's avatar
mathieui committed
386 387 388 389 390 391 392 393 394 395 396
    def __init__(self):
        InfoWin.__init__(self)

    def refresh(self, preferred):
        log.debug('Refresh: %s', self.__class__.__name__)
        self._win.erase()
        self.write_remote_status(preferred)
        self.finish_line(get_theme().COLOR_INFORMATION_BAR)
        self._refresh()

    def write_remote_status(self, preferred):
mathieui's avatar
mathieui committed
397 398 399
        self.addstr('Remote storage: %s' % preferred,
                    to_curses_attr(get_theme().COLOR_INFORMATION_BAR))

mathieui's avatar
mathieui committed
400

mathieui's avatar
mathieui committed
401
class ConfirmStatusWin(Win):
402 403
    __slots__ = ('text', 'critical')

mathieui's avatar
mathieui committed
404 405 406 407 408 409 410 411
    def __init__(self, text, critical=False):
        Win.__init__(self)
        self.text = text
        self.critical = critical

    def refresh(self):
        log.debug('Refresh: %s', self.__class__.__name__)
        self._win.erase()
412
        theme = get_theme()
mathieui's avatar
mathieui committed
413
        if self.critical:
414
            color = theme.COLOR_WARNING_PROMPT
mathieui's avatar
mathieui committed
415
        else:
416
            color = theme.COLOR_INFORMATION_BAR
mathieui's avatar
mathieui committed
417 418 419 420
        c_color = to_curses_attr(color)
        self.addstr(self.text, c_color)
        self.finish_line(color)
        self._refresh()