File indexing completed on 2024-04-21 04:01:48

0001 # -*- coding: utf-8 -*-
0002 
0003 """
0004 Copyright (C) 2009-2016 Wolfgang Rohdewald <wolfgang@rohdewald.de>
0005 
0006 SPDX-License-Identifier: GPL-2.0
0007 
0008 """
0009 
0010 from qt import Qt, QAbstractTableModel, QModelIndex, QSize
0011 from qt import QWidget, QLineEdit, QVBoxLayout, QColor, QAbstractItemView
0012 
0013 from log import i18n, logDebug
0014 from guiutil import MJTableView, decorateWindow
0015 from statesaver import StateSaver
0016 from message import ChatMessage
0017 from common import Debug, Internal
0018 from modeltest import ModelTest
0019 
0020 
0021 class ChatModel(QAbstractTableModel):
0022 
0023     """a model for the chat view"""
0024 
0025     def __init__(self, parent=None):
0026         super().__init__(parent)
0027         self.chatLines = []
0028 
0029     def headerData(self, section, orientation, role=Qt.DisplayRole):  # pylint: disable=no-self-use
0030         """show header"""
0031         if role == Qt.TextAlignmentRole:
0032             if orientation == Qt.Horizontal:
0033                 if section == 1:
0034                     return int(Qt.AlignRight)
0035                 return int(Qt.AlignLeft)
0036         if orientation != Qt.Horizontal:
0037             return int(section + 1)
0038         if role != Qt.DisplayRole:
0039             return None
0040         result = ''
0041         if section < self.columnCount():
0042             result = [i18n('Time'), i18n('Player'), i18n('Message')][section]
0043         return result
0044 
0045     def rowCount(self, parent=None):
0046         """how many lines are in the model?"""
0047         if parent and parent.isValid():
0048             # similar in tables.py
0049             # we have only top level items
0050             return 0
0051         return len(self.chatLines)
0052 
0053     def columnCount(self, unusedParent=None):  # pylint: disable=no-self-use
0054         """for now we only have time, who, message"""
0055         return 3
0056 
0057     def data(self, index, role=Qt.DisplayRole):
0058         """score table"""
0059         result = None
0060         if role == Qt.TextAlignmentRole:
0061             if index.column() == 1:
0062                 return int(Qt.AlignRight)
0063             return int(Qt.AlignLeft)
0064         if index.isValid() and (0 <= index.row() < len(self.chatLines)):
0065             chatLine = self.chatLines[index.row()]
0066             if role == Qt.DisplayRole and index.column() == 0:
0067                 local = chatLine.localtimestamp()
0068                 result = '%02d:%02d:%02d' % (
0069                     local.hour,
0070                     local.minute,
0071                     local.second)
0072             elif role == Qt.DisplayRole and index.column() == 1:
0073                 result = chatLine.fromUser
0074             elif role == Qt.DisplayRole and index.column() == 2:
0075                 result = i18n(chatLine.message)
0076             elif role == Qt.ForegroundRole and index.column() == 2:
0077                 palette = Internal.app.palette()  # pylint: disable=no-member
0078                 color = 'blue' if chatLine.isStatusMessage else palette.windowText(
0079                 )
0080                 result = QColor(color)
0081         return result
0082 
0083     def appendLines(self, lines):
0084         """insert a chatline"""
0085         if not isinstance(lines, list):
0086             lines = [lines]
0087         self.beginInsertRows(
0088             QModelIndex(),
0089             self.rowCount(),
0090             self.rowCount() + len(lines) - 1)
0091         self.chatLines.extend(lines)
0092         self.endInsertRows()
0093 
0094 
0095 class ChatView(MJTableView):
0096 
0097     """define a minimum size"""
0098 
0099     def __init__(self):
0100         MJTableView.__init__(self)
0101 
0102     def sizeHint(self):  # pylint: disable=no-self-use
0103         """sizeHint"""
0104         return QSize(400, 100)
0105 
0106     def minimumSizeHint(self):
0107         """minimumSizeHint"""
0108         return self.sizeHint()
0109 
0110 
0111 class ChatWindow(QWidget):
0112 
0113     """a widget for showing chat messages"""
0114 
0115     def __init__(self, scene=None, table=None):
0116         super().__init__(None)
0117         self.scene = scene
0118         self.table = table or scene.game.client.table
0119         self.table.chatWindow = self
0120         self.setObjectName('chatWindow')
0121         title = i18n(
0122             'Chat on table %1 at %2',
0123             self.table.tableid,
0124             self.table.client.connection.url)
0125         decorateWindow(self, title)
0126         self.messageView = ChatView()
0127         self.messageView.setModel(ChatModel())
0128         self.messageView.setFocusPolicy(Qt.NoFocus)
0129         self.messageView.setShowGrid(False)
0130         self.messageView.setWordWrap(False)
0131         self.messageView.setSelectionMode(QAbstractItemView.NoSelection)
0132         if Debug.modelTest:
0133             self.debugModelTest = ModelTest(
0134                 self.messageView.model(),
0135                 self.messageView)
0136         self.edit = QLineEdit()
0137         layout = QVBoxLayout()
0138         layout.addWidget(self.messageView)
0139         layout.addWidget(self.edit)
0140         self.setLayout(layout)
0141         self.edit.returnPressed.connect(self.sendLine)
0142         self.edit.setFocus()
0143         self.show()
0144         StateSaver(self)
0145 
0146     def show(self):
0147         """not only show but also restore and raise"""
0148         self.activateWindow()
0149         self.setWindowState(self.windowState() & ~Qt.WindowMinimized)
0150         self.raise_()
0151         QWidget.show(self)
0152 
0153     def isVisible(self):
0154         """not only visible but also not minimized"""
0155         return QWidget.isVisible(self) and not self.windowState() & Qt.WindowMinimized
0156 
0157     def kill(self):
0158         """hide and null on table"""
0159         if Debug.chat:
0160             logDebug('chat.kill for %s on table %s' % (self, self.table))
0161         self.hide()
0162         self.table.chatWindow = None
0163 
0164     def sendLine(self, line=None, isStatusMessage=False):
0165         """send line to others. Either the edited line or parameter line."""
0166         if line is None:
0167             line = self.edit.text()
0168             self.edit.clear()
0169         if line:
0170             if Debug.chat:
0171                 logDebug('sending line %s to others' % line)
0172             msg = ChatMessage(
0173                 self.table.tableid,
0174                 self.table.client.name,
0175                 line,
0176                 isStatusMessage)
0177             self.table.client.sendChat(msg).addErrback(self.chatError)
0178 
0179     def chatError(self, result):
0180         """tableList may already have gone away"""
0181         if self.table.client.tableList:
0182             self.table.client.tableList.tableError(result)
0183 
0184     def leave(self):
0185         """leaving the chat"""
0186         self.hide()
0187 
0188     def receiveLine(self, chatLine):
0189         """show a new line in protocol"""
0190         self.show()
0191         self.messageView.model().appendLines(chatLine)
0192         for row in range(self.messageView.model().rowCount()):
0193             self.messageView.setRowHeight(
0194                 row,
0195                 self.messageView.fontMetrics().height())
0196         self.messageView.resizeColumnsToContents()
0197         self.messageView.scrollToBottom()