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()