1 /*
2     This file is part of the KDE games library
3     SPDX-FileCopyrightText: 2001-2002 Andreas Beckermann <b_mann@gmx.de>
4     SPDX-FileCopyrightText: 2001 Martin Heni <kde at heni-online.de>
5 
6     SPDX-License-Identifier: LGPL-2.0-only
7 */
8 
9 #include "kgamechat.h"
10 
11 // own
12 #include "../kchatbase_p.h"
13 #include "kgame.h"
14 #include "kplayer.h"
15 #include "kgameproperty.h"
16 #include "kgamemessage.h"
17 // KF
18 #include <KLocalizedString>
19 // Qt
20 #include <QMap>
21 
22 //FIXME:
23 #define FIRST_ID 2 // first id, that is free of use, aka not defined above
24 
25 class KGameChatPrivate : public KChatBasePrivate
26 {
27 public:
KGameChatPrivate(KChatBaseModel * model,KChatBaseItemDelegate * delegate,QWidget * parent)28 	KGameChatPrivate(KChatBaseModel* model, KChatBaseItemDelegate* delegate, QWidget* parent)
29 	    : KChatBasePrivate(model, delegate, parent)
30 	{
31 		mFromPlayer = nullptr;
32 		mGame = nullptr;
33 
34 		mToMyGroup = -1;
35 	}
36 
37 	KGame* mGame;
38 	KPlayer* mFromPlayer;
39 	int mMessageId;
40 
41 
42 	QMap<int, int> mSendId2PlayerId;
43 	int mToMyGroup; // just as the above - but for the group, not for players
44 };
45 
KGameChat(KGame * g,int msgid,QWidget * parent,KChatBaseModel * model,KChatBaseItemDelegate * delegate)46 KGameChat::KGameChat(KGame* g, int msgid, QWidget* parent, KChatBaseModel* model, KChatBaseItemDelegate* delegate)
47     : KChatBase(*new KGameChatPrivate(model, delegate, parent), parent, false)
48 {
49  init(g, msgid);
50 }
51 
KGameChat(KGame * g,int msgid,KPlayer * fromPlayer,QWidget * parent,KChatBaseModel * model,KChatBaseItemDelegate * delegate)52 KGameChat::KGameChat(KGame* g, int msgid, KPlayer* fromPlayer, QWidget* parent, KChatBaseModel* model, KChatBaseItemDelegate* delegate)
53     : KChatBase(*new KGameChatPrivate(model, delegate, parent), parent, false)
54 {
55  init(g, msgid);
56  setFromPlayer(fromPlayer);
57 }
58 
KGameChat(QWidget * parent)59 KGameChat::KGameChat(QWidget* parent)
60     : KChatBase(*new KGameChatPrivate(nullptr, nullptr, parent), parent, false)
61 {
62  init(nullptr, -1);
63 }
64 
~KGameChat()65 KGameChat::~KGameChat()
66 {
67  qCDebug(GAMES_PRIVATE_KGAME) ;
68 }
69 
init(KGame * g,int msgId)70 void KGameChat::init(KGame* g, int msgId)
71 {
72  qCDebug(GAMES_PRIVATE_KGAME) ;
73  setMessageId(msgId);
74 
75  setKGame(g);
76 }
77 
addMessage(int fromId,const QString & text)78 void KGameChat::addMessage(int fromId, const QString& text)
79 {
80     Q_D(KGameChat);
81 
82  if (!d->mGame) {
83 	qCWarning(GAMES_PRIVATE_KGAME) << "no KGame object has been set";
84 	addMessage(i18n("Player %1", fromId), text);
85  } else {
86 	KPlayer* p = d->mGame->findPlayer(fromId);
87 	if (p) {
88 		qCDebug(GAMES_PRIVATE_KGAME) << "adding message of player" << p->name() << "id=" << fromId;
89 		addMessage(p->name(), text);
90 	} else {
91 		qCWarning(GAMES_PRIVATE_KGAME) << "Could not find player id" << fromId;
92 		addMessage(i18nc("Unknown player", "Unknown"), text);
93 	}
94  }
95 }
96 
returnPressed(const QString & text)97 void KGameChat::returnPressed(const QString& text)
98 {
99     Q_D(KGameChat);
100 
101  if (!d->mFromPlayer) {
102 	qCWarning(GAMES_PRIVATE_KGAME) << ": You must set a player first!";
103 	return;
104  }
105  if (!d->mGame) {
106 	qCWarning(GAMES_PRIVATE_KGAME) << ": You must set a game first!";
107 	return;
108  }
109 
110  qCDebug(GAMES_PRIVATE_KGAME) << "from:" << d->mFromPlayer->id() << "==" << d->mFromPlayer->name();
111 
112  int id = sendingEntry();
113 
114  if (isToGroupMessage(id)) {
115 	// note: there is currently no support for other groups than the players
116 	// group! It might be useful to send to other groups, too
117 	QString group = d->mFromPlayer->group();
118 	qCDebug(GAMES_PRIVATE_KGAME) << "send to group" << group;
119 	int sender = d->mFromPlayer->id();
120 	d->mGame->sendGroupMessage(text, messageId(), sender, group);
121 
122 	//TODO
123 	//AB: this message is never received!! we need to connect to
124 	//KPlayer::networkData!!!
125 	//TODO
126 
127  } else {
128 	int toPlayer = 0;
129 	if (!isSendToAllMessage(id) && isToPlayerMessage(id)) {
130 		toPlayer = playerId(id);
131 		if (toPlayer == -1) {
132 			qCCritical(GAMES_PRIVATE_KGAME) << ": don't know that player "
133 					<< "- internal ERROR";
134 		}
135 	}
136 	int receiver = toPlayer;
137 	int sender = d->mFromPlayer->id();
138 	d->mGame->sendMessage(text, messageId(), receiver, sender);
139  }
140 }
141 
setMessageId(int msgid)142 void KGameChat::setMessageId(int msgid)
143 {
144     Q_D(KGameChat);
145 
146     d->mMessageId = msgid;
147 }
148 
messageId() const149 int KGameChat::messageId() const
150 {
151     Q_D(const KGameChat);
152 
153     return d->mMessageId;
154 }
155 
isSendToAllMessage(int id) const156 bool KGameChat::isSendToAllMessage(int id) const
157 {
158     return (id == KChatBase::SendToAll);
159 }
160 
isToGroupMessage(int id) const161 bool KGameChat::isToGroupMessage(int id) const
162 {
163     Q_D(const KGameChat);
164 
165     return (id == d->mToMyGroup);
166 }
167 
isToPlayerMessage(int id) const168 bool KGameChat::isToPlayerMessage(int id) const
169 {
170     Q_D(const KGameChat);
171 
172     return d->mSendId2PlayerId.contains(id);
173 }
174 
sendToPlayerEntry(const QString & name) const175 QString KGameChat::sendToPlayerEntry(const QString& name) const
176 {
177     return i18n("Send to %1", name);
178 }
179 
playerId(int id) const180 int KGameChat::playerId(int id) const
181 {
182     Q_D(const KGameChat);
183 
184  if (!isToPlayerMessage(id)) {
185 	return -1;
186  }
187 
188  return d->mSendId2PlayerId[id];
189 }
190 
sendingId(int playerId) const191 int KGameChat::sendingId(int playerId) const
192 {
193     Q_D(const KGameChat);
194 
195  QMap<int, int>::ConstIterator it;
196  for (it = d->mSendId2PlayerId.begin(); it != d->mSendId2PlayerId.end(); ++it) {
197 	if (it.value() == playerId) {
198 		return it.key();
199 	}
200  }
201  return -1;
202 }
203 
fromName() const204 QString KGameChat::fromName() const
205 {
206     Q_D(const KGameChat);
207 
208     return d->mFromPlayer ? d->mFromPlayer->name() : QString();
209 }
210 
hasPlayer(int id) const211 bool KGameChat::hasPlayer(int id) const
212 {
213  return (sendingId(id) != -1);
214 }
215 
setFromPlayer(KPlayer * p)216 void KGameChat::setFromPlayer(KPlayer* p)
217 {
218     Q_D(KGameChat);
219 
220  if (!p) {
221 	qCCritical(GAMES_PRIVATE_KGAME) << ": NULL player";
222 	removeSendingEntry(d->mToMyGroup);
223 	d->mFromPlayer = nullptr;
224 	return;
225  }
226  if (d->mFromPlayer) {
227 	changeSendingEntry(p->group(), d->mToMyGroup);
228  } else {
229 	if (d->mToMyGroup != -1) {
230 		qCWarning(GAMES_PRIVATE_KGAME) << "send to my group exists already - removing";
231 		removeSendingEntry(d->mToMyGroup);
232 	}
233 	d->mToMyGroup = nextId();
234 	addSendingEntry(i18n("Send to My Group (\"%1\")", p->group()), d->mToMyGroup);
235  }
236  d->mFromPlayer = p;
237  qCDebug(GAMES_PRIVATE_KGAME) << "player=" << p;
238 }
239 
240 
setKGame(KGame * g)241 void KGameChat::setKGame(KGame* g)
242 {
243     Q_D(KGameChat);
244 
245  if (d->mGame) {
246 	slotUnsetKGame();
247  }
248  qCDebug(GAMES_PRIVATE_KGAME) << "game=" << g;
249  d->mGame = g;
250 
251  if (d->mGame) {
252 	connect(d->mGame, &KGame::signalPlayerJoinedGame, this, &KGameChat::slotAddPlayer);
253 	connect(d->mGame, &KGame::signalPlayerLeftGame, this, &KGameChat::slotRemovePlayer);
254 	connect(d->mGame, &KGame::signalNetworkData, this, &KGameChat::slotReceiveMessage);
255 	connect(d->mGame, &KGame::destroyed, this, &KGameChat::slotUnsetKGame);
256 
257 	QList<KPlayer*> playerList = *d->mGame->playerList();
258 	for (int i = 0; i < playerList.count(); i++) {
259 		slotAddPlayer(playerList.at(i));
260 	}
261  }
262 }
263 
game() const264 KGame* KGameChat::game() const
265 {
266     Q_D(const KGameChat);
267 
268  return d->mGame;
269 }
270 
fromPlayer() const271 KPlayer* KGameChat::fromPlayer() const
272 {
273     Q_D(const KGameChat);
274 
275  return d->mFromPlayer;
276 }
277 
slotUnsetKGame()278 void KGameChat::slotUnsetKGame()
279 {
280 //TODO: test this method!
281     Q_D(KGameChat);
282 
283  if (!d->mGame) {
284 	return;
285  }
286  disconnect(d->mGame, nullptr, this, nullptr);
287  removeSendingEntry(d->mToMyGroup);
288  QMap<int, int>::Iterator it;
289  for (it = d->mSendId2PlayerId.begin(); it != d->mSendId2PlayerId.end(); ++it) {
290 	removeSendingEntry(it.value());
291  }
292 }
293 
slotAddPlayer(KPlayer * p)294 void KGameChat::slotAddPlayer(KPlayer* p)
295 {
296     Q_D(KGameChat);
297 
298  if (!p) {
299 	qCCritical(GAMES_PRIVATE_KGAME) << ": cannot add NULL player";
300 	return;
301  }
302  if (hasPlayer(p->id())) {
303 	qCCritical(GAMES_PRIVATE_KGAME) << ": player was added before";
304 	return;
305  }
306 
307  int sendingId = nextId();
308  addSendingEntry(comboBoxItem(p->name()), sendingId);
309  d->mSendId2PlayerId.insert(sendingId, p->id());
310  connect(p, &KPlayer::signalPropertyChanged, this, &KGameChat::slotPropertyChanged);
311  connect(p, &KPlayer::signalNetworkData, this, &KGameChat::slotReceivePrivateMessage);
312 }
313 
slotRemovePlayer(KPlayer * p)314 void KGameChat::slotRemovePlayer(KPlayer* p)
315 {
316     Q_D(KGameChat);
317 
318  if (!p) {
319 	qCCritical(GAMES_PRIVATE_KGAME) << ": NULL player";
320 	return;
321  }
322  if (!hasPlayer(p->id())) {
323 	qCCritical(GAMES_PRIVATE_KGAME) << ": cannot remove non-existent player";
324 	return;
325  }
326 
327  int id = sendingId(p->id());
328  removeSendingEntry(id);
329  p->disconnect(this);
330  d->mSendId2PlayerId.remove(id);
331 }
332 
slotPropertyChanged(KGamePropertyBase * prop,KPlayer * player)333 void KGameChat::slotPropertyChanged(KGamePropertyBase* prop, KPlayer* player)
334 {
335  if (prop->id() == KGamePropertyBase::IdName) {
336 //	qCDebug(GAMES_PRIVATE_KGAME) << "new Name";
337 	changeSendingEntry(player->name(), sendingId(player->id()));
338 /*
339 	mCombo->changeItem(comboBoxItem(player->name()), index);
340  */
341  } else if (prop->id() == KGamePropertyBase::IdGroup) {
342  //TODO
343  }
344 }
345 
slotReceivePrivateMessage(int msgid,const QByteArray & buffer,quint32 sender,KPlayer * me)346 void KGameChat::slotReceivePrivateMessage(int msgid, const QByteArray& buffer, quint32 sender, KPlayer* me)
347 {
348  if (!me || me != fromPlayer()) {
349 	qCDebug(GAMES_PRIVATE_KGAME) << "nope - not for us!";
350 	return;
351  }
352  slotReceiveMessage(msgid, buffer, me->id(), sender);
353 }
354 
slotReceiveMessage(int msgid,const QByteArray & buffer,quint32,quint32 sender)355 void KGameChat::slotReceiveMessage(int msgid, const QByteArray& buffer, quint32 , quint32 sender)
356 {
357  QDataStream msg(buffer);
358  if (msgid != messageId()) {
359 	return;
360  }
361 
362  QString text;
363  msg >> text;
364 
365  addMessage(sender, text);
366 }
367 
368