[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: KDE/kdegames
From: Wolfgang Rohdewald <wolfgang () rohdewald ! de>
Date: 2012-03-23 8:05:53
Message-ID: 20120323080553.7DB7FAC899 () svn ! kde ! org
[Download RAW message or body]
SVN commit 1286780 by wrohdewald:
players can now chat with each other
FEATURE:
AM doc/kajongg/chat.png
M +31 -0 doc/kajongg/index.docbook
M +1 -0 kajongg/CMakeLists.txt
A kajongg/src/chat.py
M +1 -0 kajongg/src/client.py
M +1 -0 kajongg/src/common.py
M +27 -1 kajongg/src/humanclient.py
M +1 -0 kajongg/src/kajonggui.rc
M +43 -1 kajongg/src/message.py
M +12 -0 kajongg/src/playfield.py
M +25 -1 kajongg/src/server.py
M +27 -0 kajongg/src/tables.py
--- trunk/KDE/kdegames/doc/kajongg/index.docbook #1286779:1286780
@@ -35,6 +35,8 @@
<!ENTITY lastsource "lastsource">
]>
+<!-- TODO: describe the window with the list of tables -->
+
<book lang="&language;"> <!-- do not change this! -->
<bookinfo>
<title>The &kajongg; Handbook</title> <!-- This is the title of this docbook. -->
@@ -475,6 +477,26 @@
Explains how the score for the current hand was computed.
</para></listitem>
</varlistentry>
+ <varlistentry id="view-chat">
+ <term><menuchoice>
+ <guimenu>View</guimenu>
+ <guimenuitem>Chat</guimenuitem>
+ </menuchoice></term>
+ <listitem><para><action>Chat</action>
+ <screenshot>
+ <screeninfo>Chat Window</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="chat.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>Chat Window</phrase>
+ </textobject>
+ </mediaobject>
+ </screenshot>
+ Lets you chat with the other players.
+ </para></listitem>
+ </varlistentry>
</variablelist>
</sect1>
<sect1 id="settings-menu">
@@ -882,6 +904,15 @@
</varlistentry>
<varlistentry>
+<term><keycombo action="simul">&Ctrl;<keycap>H</keycap></keycombo></term>
+<listitem>
+<para>
+Show a chat window.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
<term><keycombo action="simul">&Ctrl;<keycap>G</keycap></keycombo></term>
<listitem>
<para>
--- trunk/KDE/kdegames/kajongg/CMakeLists.txt #1286779:1286780
@@ -24,6 +24,7 @@
src/background.py
src/backgroundselector.py
src/board.py
+src/chat.py
src/handboard.py
src/message.py
src/client.py
--- trunk/KDE/kdegames/kajongg/src/client.py #1286779:1286780
@@ -56,6 +56,7 @@
if myRuleset == self.ruleset:
self.myRuleset = myRuleset
break
+ self.chatWindow = None
def __str__(self):
return 'Table %d %s gameid=%s rules %s players %s online %s' % (self.tableid or 0,
--- trunk/KDE/kdegames/kajongg/src/common.py #1286779:1286780
@@ -45,6 +45,7 @@
robbingKong = False
mahJongg = False
sound = False
+ chat = False
argString = None
def __init__(self):
--- trunk/KDE/kdegames/kajongg/src/humanclient.py #1286779:1286780
@@ -36,7 +36,8 @@
from util import m18n, m18nc, logWarning, logException, socketName, english, \
appdataDir, logInfo, logDebug, removeIfExists
from util import SERVERMARK, isAlive
-from message import Message
+from message import Message, ChatMessage
+from chat import ChatWindow
from common import InternalParameters, PREF, Debug
from game import Players
from query import Transaction, Query
@@ -752,6 +753,24 @@
Client.remote_tablesChanged(self, tables)
self.tableList.loadTables(self.tables)
+ def remote_chat(self, data):
+ """others chat to me"""
+ chatLine = ChatMessage(data)
+ if Debug.chat:
+ logDebug('got chatLine: %s' % chatLine)
+ if self.table:
+ table = self.table
+ else:
+ table = None
+ for _ in self.tableList.view.model().tables:
+ if _.tableid == chatLine.tableid:
+ table = _
+ assert table.tableid == chatLine.tableid
+ if not chatLine.isStatusMessage:
+ ChatWindow.createFor(table)
+ if table.chatWindow:
+ table.chatWindow.receiveLine(chatLine)
+
def readyForGameStart(self, tableid, gameid, wantedGame, playerNames, shouldSave=True):
"""playerNames are in wind order ESWN"""
self.tableList.hideForever = True
@@ -1095,6 +1114,9 @@
self.readyHandQuestion.hide()
if field.clientDialog:
field.clientDialog.hide()
+ if self.table.chatWindow:
+ self.table.chatWindow.hide()
+ self.table.chatWindow = None
def callServer(self, *args):
"""if we are online, call server"""
@@ -1112,3 +1134,7 @@
self.perspective = None
logWarning(m18n('The connection to the server %1 broke, please try again later.',
self.url))
+
+ def sendChat(self, chatLine):
+ """send chat message to server"""
+ self.callServer('chat', chatLine.serialize())
--- trunk/KDE/kdegames/kajongg/src/kajonggui.rc #1286779:1286780
@@ -14,6 +14,7 @@
<Action name="scoring" />
<Action name="scoreTable" />
<Action name="explain" />
+ <Action name="chat" />
</Menu>
<Menu name="settings" >
<Action name="players" />
--- trunk/KDE/kdegames/kajongg/src/message.py #1286779:1286780
@@ -18,7 +18,9 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
-from util import m18n, m18nc, m18ncE, logWarning, logException, logDebug
+import datetime
+
+from util import m18n, m18nc, m18ncE, logWarning, logException, logDebug, SERVERMARK
from sound import Voice, Sound
from meld import Meld
from common import InternalParameters, Debug
@@ -559,4 +561,44 @@
msg = glob()
type.__setattr__(Message, msg.name.replace(' ', ''), msg)
+class ChatMessage:
+ """holds relevant info about a chat message"""
+ def __init__(self, tableid, fromUser=None, message=None, isStatusMessage=False):
+ if isinstance(tableid, basestring) and SERVERMARK in tableid:
+ parts = tableid.split(SERVERMARK)
+ self.tableid = int(parts[0])
+ self.timestamp = datetime.time(hour=int(parts[1]), minute=int(parts[2]), second=int(parts[3]))
+ self.fromUser = parts[4]
+ self.message = parts[5]
+ self.isStatusMessage = bool(int(parts[6]))
+ else:
+ self.tableid = tableid
+ self.fromUser = fromUser
+ self.message = message
+ self.isStatusMessage = isStatusMessage
+ self.timestamp = datetime.datetime.utcnow().time()
+
+ def __unicode__(self):
+ return 'statusMessage=%s %02d:%02d:%02d %s: %s' % (
+ str(self.isStatusMessage),
+ self.timestamp.hour,
+ self.timestamp.minute,
+ self.timestamp.second,
+ self.fromUser,
+ self.message)
+
+ def __repr__(self):
+ return unicode(self)
+
+ def serialize(self):
+ """encode me in a string for network transfer"""
+ return SERVERMARK.join([
+ str(self.tableid),
+ str(self.timestamp.hour),
+ str(self.timestamp.minute),
+ str(self.timestamp.second),
+ self.fromUser,
+ self.message,
+ str(int(self.isStatusMessage))])
+
__scanSelf()
--- trunk/KDE/kdegames/kajongg/src/playfield.py #1286779:1286780
@@ -81,6 +81,7 @@
from animation import animate, afterCurrentAnimationDo, Animated
from player import Player, Players
from game import Game, ScoringGame
+ from chat import ChatWindow
except ImportError, e:
NOTFOUND.append('kajongg is not correctly installed: modules: %s' % e)
@@ -548,6 +549,11 @@
self.actionAbortGame.setEnabled(False)
self.actionQuit = self.kajonggAction("quit", "application-exit", self.quit, Qt.Key_Q)
self.actionPlayers = self.kajonggAction("players", "im-user", self.slotPlayers)
+ self.actionChat = self.kajonggToggleAction("chat", "call-start",
+ shortcut=Qt.Key_H, actionData=ChatWindow)
+ game = self.game
+ self.actionChat.setEnabled(bool(game) and bool(game.client))
+ self.actionChat.setChecked(bool(game) and bool(game.client) and bool(game.client.table.chatWindow))
self.actionScoring = self.kajonggToggleAction("scoring", "draw-freehand",
shortcut=Qt.Key_S, actionData=ScoringDialog)
self.actionScoring.setEnabled(False)
@@ -671,6 +677,7 @@
self.actionScoreTable.setText(m18nc('kajongg', "&Score Table"))
self.actionExplain.setText(m18n("&Explain Scores"))
self.actionAutoPlay.setText(m18n("&Demo Mode"))
+ self.actionChat.setText(m18n("C&hat"))
def changeEvent(self, event):
"""when the applicationwide language changes, recreate GUI"""
@@ -827,6 +834,9 @@
actionData = action.data().toPyObject()
if checked:
if isinstance(actionData, type):
+ if actionData == ChatWindow:
+ actionData = ChatWindow.createFor(self.game.client.table)
+ else:
actionData = actionData(self.game)
action.setData(QVariant(actionData))
if isinstance(actionData, ScoringDialog):
@@ -891,6 +901,8 @@
self.discardBoard.setVisible(bool(game) and not scoring)
self.actionScoring.setEnabled(scoring and not game.finished())
self.actionAutoPlay.setEnabled(not self.startingGame)
+ self.actionChat.setEnabled(bool(game) and not self.startingGame)
+ self.actionChat.setChecked(bool(game) and bool(game.client) and bool(game.client.table.chatWindow))
if self.actionScoring.isChecked():
self.actionScoring.setChecked(scoring and not game.finished())
for view in [self.scoringDialog, self.explainView, self.scoreTable]:
--- trunk/KDE/kdegames/kajongg/src/server.py #1286779:1286780
@@ -54,7 +54,7 @@
from scoringengine import Ruleset
from util import m18n, m18nE, m18ncE, logInfo, logDebug, logWarning, SERVERMARK, \
Duration, socketName, logError
-from message import Message
+from message import Message, ChatMessage
from common import elements, Debug
from sound import Voice
from deferredutil import DeferredBlock
@@ -126,6 +126,8 @@
"""a table on the game server"""
# pylint: disable=R0902
# pylint we need more than 10 instance attributes
+ # pylint: disable=R0904
+ # pylint we have too many public methods
def __init__(self, server, owner, rulesetStr, playOpen, autoPlay, wantedGame):
self.server = server
@@ -176,6 +178,13 @@
result -= sum (x.name.startswith('ROBOT') for x in self.preparedGame.players)
return result
+ def sendChatMessage(self, chatLine):
+ """sends a chat messages to all clients"""
+ if Debug.chat:
+ logDebug('server sends chat msg %s' % chatLine)
+ for other in self.users:
+ self.server.callRemote(other, 'chat', chatLine.serialize())
+
def addUser(self, user):
"""add user to this table"""
if user.name in list(x.name for x in self.users):
@@ -183,6 +192,9 @@
if len(self.users) == self.maxSeats():
raise srvError(pb.Error, m18nE('All seats are already taken'))
self.users.append(user)
+ self.sendChatMessage(ChatMessage(self.tableid, user.name,
+ m18nE('takes a seat'), isStatusMessage=True))
+
if len(self.users) == self.maxSeats():
self.readyForGameStart(self.owner)
@@ -191,6 +203,8 @@
if user in self.users:
self.game = None
self.users.remove(user)
+ self.sendChatMessage(ChatMessage(self.tableid, user.name,
+ m18nE('leaves the table'), isStatusMessage=True))
if user is self.owner:
# silently pass ownership
if self.users:
@@ -743,6 +757,13 @@
self.users = list()
Players.load()
+ def chat(self, chatString):
+ """a client sent us a chat message"""
+ chatLine = ChatMessage(chatString)
+ if Debug.chat:
+ logDebug('server got chat message %s' % chatLine)
+ self.tables[chatLine.tableid].sendChatMessage(chatLine)
+
def login(self, user):
"""accept a new user"""
if not user in self.users:
@@ -988,6 +1009,9 @@
def perspective_logout(self):
"""perspective_* methods are to be called remotely"""
self.detached(None)
+ def perspective_chat(self, chatString):
+ """perspective_* methods are to be called remotely"""
+ return self.server.chat(chatString)
def __str__(self):
return '%d:%s' % (id(self) % 10000, self.name)
--- trunk/KDE/kdegames/kajongg/src/tables.py #1286779:1286780
@@ -41,6 +41,7 @@
from sound import Voice
from common import InternalParameters, Debug, PREF
from client import ClientTable
+from chat import ChatWindow
from modeltest import ModelTest
class TablesModel(QAbstractTableModel):
@@ -182,6 +183,9 @@
self.compareButton.clicked.connect(self.compareRuleset)
self.compareButton.setIcon(KIcon("preferences-plugin-script"))
self.compareButton.setToolTip(m18n('Compare the rules of this table with my own rulesets'))
+ self.chatButton = buttonBox.addButton(m18n('&Chat'), QDialogButtonBox.AcceptRole)
+ self.chatButton.setIcon(KIcon("call-start"))
+ self.chatButton.clicked.connect(self.chat)
self.startButton = buttonBox.addButton(m18n('&Start'), QDialogButtonBox.AcceptRole)
self.startButton.clicked.connect(self.startGame)
self.startButton.setIcon(KIcon("arrow-right"))
@@ -199,6 +203,10 @@
StateSaver(self, self.view.horizontalHeader())
self.login()
+ def chat(self):
+ """chat"""
+ ChatWindow.createFor(self.selectedTable())
+
@apply
def hideForever(): # pylint: disable=E0202
"""we never want to see this table list for local games,
@@ -313,6 +321,12 @@
self.startButton.setEnabled(not suspendedLocalGame and hasTable \
and self.client.username == table.playerNames[0])
self.compareButton.setEnabled(hasTable and table.myRuleset is None)
+ self.chatButton.setVisible(not self.client.hasLocalServer())
+ self.chatButton.setEnabled(self.leaveButton.isEnabled())
+ if self.chatButton.isEnabled():
+ self.chatButton.setToolTip(m18n("Chat with others on this table"))
+ else:
+ self.chatButton.setToolTip(m18n("For chatting with others on this table, please first take a seat"))
def selectionChanged(self, selected, dummyDeselected):
"""update button states according to selection"""
@@ -405,6 +419,18 @@
"""leave a table"""
self.client.callServer('leaveTable', self.selectedTable().tableid)
+ def __keepChatWindows(self, tables):
+ """copy chatWindows from the old table list which will be thrown away"""
+ if self.view.model():
+ chatWindows = dict((x.tableid, x.chatWindow) for x in self.view.model().tables)
+ unusedWindows = set(x.chatWindow for x in self.view.model().tables)
+ for table in tables:
+ table.chatWindow = chatWindows.get(table.tableid, None)
+ unusedWindows -= set([table.chatWindow])
+ for unusedWindow in unusedWindows:
+ if unusedWindow:
+ unusedWindow.hide()
+
def loadTables(self, tables):
"""build and use a model around the tables.
Show all new tables (no gameid given yet) and all suspended
@@ -418,6 +444,7 @@
elif not table.gameExistsLocally():
logDebug('%s does not exist locally' % table)
tables = [x for x in tables if not x.gameid or x.gameExistsLocally()]
+ self.__keepChatWindows(tables)
model = TablesModel(tables)
self.view.setModel(model)
if Debug.modelTest:
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic