ManaPlus
chattab.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2008-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2019 The ManaPlus Developers
6  * Copyright (C) 2019-2021 Andrei Karas
7  *
8  * This file is part of The ManaPlus Client.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
25 
26 #include "chatlogger.h"
27 #include "configuration.h"
28 #include "settings.h"
29 #include "soundmanager.h"
30 
31 #include "being/localplayer.h"
32 
33 #include "const/sound.h"
34 
35 #include "gui/chatlog.h"
36 #include "gui/windowmanager.h"
37 
38 #include "gui/windows/chatwindow.h"
39 #include "gui/windows/helpwindow.h"
40 
41 #include "gui/widgets/scrollarea.h"
43 #include "gui/widgets/tabbedarea.h"
44 
45 #include "input/inputmanager.h"
46 
47 #include "net/chathandler.h"
48 #include "net/net.h"
49 
50 #include "utils/chatutils.h"
51 #include "utils/delete2.h"
52 #include "utils/gettext.h"
53 
54 #ifdef WIN32
55 #include <sys/time.h>
56 #endif // WIN32
57 
58 #include <sstream>
59 
60 #include "debug.h"
61 
62 ChatTab *localChatTab = nullptr;
63 ChatTab *debugChatTab = nullptr;
64 
65 static const unsigned int MAX_WORD_SIZE = 50;
66 
67 ChatTab::ChatTab(const Widget2 *const widget,
68  const std::string &name,
69  const std::string &channel,
70  const std::string &logName,
71  const ChatTabTypeT &type) :
72  Tab(widget),
73  mTextOutput(new BrowserBox(this, Opaque_true,
74  "browserbox.xml")),
75  mScrollArea(new ScrollArea(this,
76  mTextOutput, Opaque_false, std::string())),
77  mChannelName(channel),
78  mLogName(logName),
79  mType(type),
80  mAllowHightlight(true),
81  mRemoveNames(false),
82  mNoAway(false),
83  mShowOnline(false)
84 {
85  setCaption(name);
86 
88  mTextOutput->setMaxRow(config.getIntValue("ChatLogLength"));
89  if (chatWindow != nullptr)
92 
96 
97  if (chatWindow != nullptr)
98  chatWindow->addTab(this);
99  mTextOutput->updateSize(true);
100 }
101 
103 {
104  if (chatWindow != nullptr)
105  chatWindow->removeTab(this);
106 
109 }
110 
111 void ChatTab::chatLog(std::string line,
112  ChatMsgTypeT own,
113  const IgnoreRecord ignoreRecord,
114  const TryRemoveColors tryRemoveColors)
115 {
116  // Trim whitespace
117  trim(line);
118 
119  if (line.empty())
120  return;
121 
122  if (tryRemoveColors == TryRemoveColors_true &&
123  own == ChatMsgType::BY_OTHER &&
124  config.getBoolValue("removeColors"))
125  {
126  line = removeColors(line);
127  if (line.empty())
128  return;
129  }
130 
131  const unsigned lineLim = config.getIntValue("chatMaxCharLimit");
132  if (lineLim > 0 && line.length() > lineLim)
133  line = line.substr(0, lineLim);
134 
135  if (line.empty())
136  return;
137 
138  CHATLOG tmp;
139  tmp.own = own;
140  tmp.nick.clear();
141  tmp.text = line;
142 
143  const size_t pos = line.find(" : ");
144  if (pos != std::string::npos)
145  {
146  if (line.length() <= pos + 3)
147  return;
148 
149  tmp.nick = line.substr(0, pos);
150  tmp.text = line.substr(pos + 3);
151  }
152  else
153  {
154  // Fix the owner of welcome message.
155  if (line.length() > 7 && line.substr(0, 7) == "Welcome")
157  }
158 
159  // *implements actions in a backwards compatible way*
160  if ((own == ChatMsgType::BY_PLAYER || own == ChatMsgType::BY_OTHER) &&
161  tmp.text.at(0) == '*' &&
162  tmp.text.at(tmp.text.length()-1) == '*')
163  {
164  tmp.text[0] = ' ';
165  tmp.text.erase(tmp.text.length() - 1);
166  own = ChatMsgType::ACT_IS;
167  }
168 
169  std::string lineColor("##C");
170  switch (own)
171  {
172  case ChatMsgType::BY_GM:
173  if (tmp.nick.empty())
174  {
175  // TRANSLATORS: chat message
176  tmp.nick = std::string(_("Global announcement:")).append(" ");
177  lineColor = "##G";
178  }
179  else
180  {
181  // TRANSLATORS: chat message
182  tmp.nick = strprintf(_("Global announcement from %s:"),
183  tmp.nick.c_str()).append(" ");
184  lineColor = "##g"; // Equiv. to BrowserBox::RED
185  }
186  break;
188  tmp.nick.append(": ");
189  lineColor = "##Y";
190  break;
193  tmp.nick.append(": ");
194  lineColor = "##C";
195  break;
197  // TRANSLATORS: chat message
198  tmp.nick.clear();
199  tmp.text = line;
200  lineColor = "##S";
201  break;
203  tmp.nick.clear();
204  lineColor = "##2"; // Equiv. to BrowserBox::GREEN
205  break;
207  // TRANSLATORS: chat message
208  tmp.nick = strprintf(_("%s whispers: %s"), tmp.nick.c_str(), "");
209  lineColor = "##W";
210  break;
211  case ChatMsgType::ACT_IS:
212  lineColor = "##I";
213  break;
215  tmp.nick.clear();
216  tmp.text = line;
217  lineColor = "##L";
218  break;
219  default:
220  break;
221  }
222 
223  if (tmp.nick == ": ")
224  {
225  tmp.nick.clear();
226  lineColor = "##S";
227  }
228 
229  // if configured, move magic messages log to debug chat tab
231  && (localChatTab != nullptr) && this == localChatTab
232  && ((config.getBoolValue("showMagicInDebug")
233  && own == ChatMsgType::BY_PLAYER
234  && tmp.text.length() > 1
235  && tmp.text.at(0) == '#'
236  && tmp.text.at(1) != '#')
237  || (config.getBoolValue("serverMsgInDebug")
238  && (own == ChatMsgType::BY_SERVER
239  || tmp.nick.empty()))))
240  {
241  if (debugChatTab != nullptr)
242  debugChatTab->chatLog(line, own, ignoreRecord, tryRemoveColors);
243  return;
244  }
245 
246  // Get the current system time
247  time_t t;
248  time(&t);
249 
250  if (config.getBoolValue("useLocalTime"))
251  {
252  const tm *const timeInfo = localtime(&t);
253  if (timeInfo != nullptr)
254  {
255  line = strprintf("%s[%02d:%02d] %s%s", lineColor.c_str(),
256  timeInfo->tm_hour, timeInfo->tm_min, tmp.nick.c_str(),
257  tmp.text.c_str());
258  }
259  else
260  {
261  line = strprintf("%s %s%s", lineColor.c_str(),
262  tmp.nick.c_str(), tmp.text.c_str());
263  }
264  }
265  else
266  {
267  // Format the time string properly
268  std::stringstream timeStr;
269  timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "")
270  << CAST_S32(((t / 60) / 60) % 24)
271  << ":" << (((t / 60) % 60 < 10) ? "0" : "")
272  << CAST_S32((t / 60) % 60)
273  << "] ";
274  line = std::string(lineColor).append(timeStr.str()).append(
275  tmp.nick).append(tmp.text);
276  }
277 
278  if (config.getBoolValue("enableChatLog"))
279  saveToLogFile(line);
280 
281  mTextOutput->setMaxRow(config.getIntValue("chatMaxLinesLimit"));
282 
283  // We look if the Vertical Scroll Bar is set at the max before
284  // adding a row, otherwise the max will always be a row higher
285  // at comparison.
288  {
289  addRow(line);
292  }
293  else
294  {
295  addRow(line);
296  }
297 
298  if ((chatWindow != nullptr) && this == localChatTab)
299  chatWindow->addToAwayLog(line);
300 
301  mScrollArea->logic();
302  if (own != ChatMsgType::BY_PLAYER)
303  {
304  if (own == ChatMsgType::BY_SERVER &&
305  (getType() == ChatTabType::PARTY ||
308  {
309  return;
310  }
311 
312  const TabbedArea *const tabArea = getTabbedArea();
313  if (tabArea == nullptr)
314  return;
315 
316  const bool notFocused = WindowManager::getIsMinimized() ||
319 
320  if (this != tabArea->getSelectedTab() || notFocused)
321  {
322  if (getFlash() == 0)
323  {
324  if (chatWindow != nullptr &&
326  {
327  setFlash(2);
329  }
330  else
331  {
332  setFlash(1);
333  }
334  }
335  else if (getFlash() == 2)
336  {
337  if (chatWindow != nullptr &&
339  {
341  }
342  }
343  }
344 
345  if ((getAllowHighlight() ||
346  own == ChatMsgType::BY_GM) &&
347  (this != tabArea->getSelectedTab() ||
348  notFocused))
349  {
350  if (own == ChatMsgType::BY_GM)
351  {
352  if (chatWindow != nullptr)
355  }
356  else if (own != ChatMsgType::BY_SERVER)
357  {
358  if (chatWindow != nullptr)
361  }
363  }
364  }
365 }
366 
367 void ChatTab::chatLog(const std::string &nick, std::string msg)
368 {
369  if (localPlayer == nullptr)
370  return;
371 
372  const ChatMsgTypeT byWho = (nick == localPlayer->getName()
374  if (byWho == ChatMsgType::BY_OTHER && config.getBoolValue("removeColors"))
375  msg = removeColors(msg);
376  chatLog(std::string(nick).append(" : ").append(msg),
377  byWho,
380 }
381 
382 void ChatTab::chatInput(const std::string &message)
383 {
384  std::string msg = message;
385  trim(msg);
386 
387  if (msg.empty())
388  return;
389 
391  replaceVars(msg);
392 
393  switch (msg[0])
394  {
395  case '/':
396  handleCommandStr(std::string(msg, 1));
397  break;
398  case '?':
399  if (msg.size() > 1 &&
400  msg[1] != '!' &&
401  msg[1] != '?' &&
402  msg[1] != '.' &&
403  msg[1] != ' ' &&
404  msg[1] != ',')
405  {
406  handleHelp(std::string(msg, 1));
407  }
408  else
409  {
410  handleInput(msg);
411  }
412  break;
413  default:
414  handleInput(msg);
415  break;
416  }
417 }
418 
419 void ChatTab::scroll(const int amount)
420 {
421  const int range = mScrollArea->getHeight() / 8 * amount;
422  Rect scr;
423  scr.y = mScrollArea->getVerticalScrollAmount() + range;
424  scr.height = abs(range);
425  mTextOutput->showPart(scr);
426 }
427 
429 {
431 }
432 
433 void ChatTab::handleInput(const std::string &msg)
434 {
435  if (chatHandler)
436  {
438  }
439 }
440 
441 void ChatTab::handleCommandStr(const std::string &msg)
442 {
443  const size_t pos = msg.find(' ');
444  const std::string type(msg, 0, pos);
445  std::string args(msg, pos == std::string::npos ? msg.size() : pos + 1);
446 
447  args = trim(args);
448  if (!handleCommand(type, args))
449  inputManager.executeChatCommand(type, args, this);
450 }
451 
452 void ChatTab::handleHelp(const std::string &msg)
453 {
454  if (helpWindow != nullptr)
455  {
458  }
459 }
460 
461 bool ChatTab::handleCommands(const std::string &type, const std::string &args)
462 {
463  // need split to commands and call each
464 
465  return handleCommand(type, args);
466 }
467 
468 void ChatTab::saveToLogFile(const std::string &msg) const
469 {
470  if (chatLogger != nullptr)
471  {
472  if (getType() == ChatTabType::INPUT)
473  {
474  chatLogger->log(msg);
475  }
476  else if (getType() == ChatTabType::DEBUG)
477  {
478  if (config.getBoolValue("enableDebugLog"))
479  chatLogger->log("#Debug", msg);
480  }
481  else if (!mLogName.empty())
482  {
484  }
485  }
486 }
487 
488 void ChatTab::addRow(std::string &line)
489 {
490  if (line.find("[@@http") == std::string::npos)
491  {
492  size_t idx = 0;
493  for (size_t f = 0; f < line.length(); f++)
494  {
495  if (line.at(f) == ' ')
496  {
497  idx = f;
498  }
499  else if (f - idx > MAX_WORD_SIZE)
500  {
501  line.insert(f, " ");
502  idx = f;
503  }
504  }
505  }
506  mTextOutput->addRow(line,
507  false);
508 }
509 
510 void ChatTab::loadFromLogFile(const std::string &name)
511 {
512  if (chatLogger != nullptr)
513  {
514  std::list<std::string> list;
515  chatLogger->loadLast(name, list, 5);
516  std::list<std::string>::const_iterator i = list.begin();
517  while (i != list.end())
518  {
519  std::string line("##o" + *i);
520  addRow(line);
521  ++i;
522  }
523  }
524 }
525 
526 void ChatTab::addNewRow(std::string &line)
527 {
530  {
531  addRow(line);
534  }
535  else
536  {
537  addRow(line);
538  }
539  mScrollArea->logic();
540 }
541 
543 {
545 }
546 
547 void ChatTab::showOnline(const std::string &nick,
548  const Online online)
549 {
550  if (!mShowOnline)
551  return;
552 
553  if (online == Online_true)
554  {
555  // TRANSLATORS: chat message
556  chatLog(strprintf(_("%s is now Online."), nick.c_str()),
560  }
561  else
562  {
563  // TRANSLATORS: chat message
564  chatLog(strprintf(_("%s is now Offline."), nick.c_str()),
568  }
569 }
#define CAST_S32
Definition: cast.h:30
Net::ChatHandler * chatHandler
Definition: net.cpp:86
ChatLogger * chatLogger
Definition: chatlogger.cpp:43
ChatMsgType ::T ChatMsgTypeT
Definition: chatmsgtype.h:41
static const unsigned int MAX_WORD_SIZE
Definition: chattab.cpp:65
ChatTab * debugChatTab
Definition: chattab.cpp:63
ChatTab * localChatTab
Definition: chattab.cpp:62
ChatTabType ::T ChatTabTypeT
Definition: chattabtype.h:49
ChatWindow * chatWindow
Definition: chatwindow.cpp:94
const std::string & getName() const
Definition: being.h:232
void setAlwaysUpdate(const bool n)
Definition: browserbox.h:130
void setMaxRow(unsigned max)
Definition: browserbox.h:81
void updateSize(const bool always)
Definition: browserbox.cpp:863
void addRow(const std::string &row, const bool atTop)
Definition: browserbox.cpp:171
void setLinkHandler(LinkHandler *linkHandler)
Definition: browserbox.cpp:166
void clearRows()
Definition: browserbox.cpp:359
void setOpaque(Opaque opaque)
Definition: browserbox.h:75
void loadLast(std::string name, std::list< std::string > &list, const unsigned int n) const
Definition: chatlogger.cpp:197
void log(std::string str)
Definition: chatlogger.cpp:91
bool mShowOnline
Definition: chattab.h:215
ChatTab(const Widget2 *const widget, const std::string &name, const std::string &channel, const std::string &logName, const ChatTabTypeT &type)
Definition: chattab.cpp:67
void saveToLogFile(const std::string &msg) const
Definition: chattab.cpp:468
virtual void handleInput(const std::string &msg)
Definition: chattab.cpp:433
virtual bool handleCommand(const std::string &type, const std::string &args)
Definition: chattab.h:128
ChatTabTypeT getType() const
Definition: chattab.h:145
std::string mLogName
Definition: chattab.h:210
virtual void handleHelp(const std::string &msg)
Definition: chattab.cpp:452
void addRow(std::string &line)
Definition: chattab.cpp:488
bool getAllowHighlight() const
Definition: chattab.h:158
void addNewRow(std::string &line)
Definition: chattab.cpp:526
ScrollArea * mScrollArea
Definition: chattab.h:208
~ChatTab()
Definition: chattab.cpp:102
virtual bool handleCommands(const std::string &type, const std::string &args)
Definition: chattab.cpp:461
void scroll(const int amount)
Definition: chattab.cpp:419
void chatLog(std::string line, ChatMsgTypeT own, const IgnoreRecord ignoreRecord, const TryRemoveColors tryRemoveColors)
Definition: chattab.cpp:111
void chatInput(const std::string &msg)
Definition: chattab.cpp:382
void showOnline(const std::string &nick, const Online online)
Definition: chattab.cpp:547
virtual void handleCommandStr(const std::string &msg)
Definition: chattab.cpp:441
void clearText()
Definition: chattab.cpp:428
void loadFromLogFile(const std::string &name)
Definition: chattab.cpp:510
virtual void playNewMessageSound() const
Definition: chattab.cpp:542
BrowserBox * mTextOutput
Definition: chattab.h:207
void addTab(ChatTab *const tab)
Definition: chatwindow.cpp:589
void unHideWindow()
ItemLinkHandler * mItemLinkHandler
Definition: chatwindow.h:341
void removeTab(ChatTab *const tab)
Definition: chatwindow.cpp:584
static std::string doReplace(const std::string &msg)
bool findHighlight(const std::string &str)
void addToAwayLog(const std::string &line)
bool getBoolValue(const std::string &key) const
int getIntValue(const std::string &key) const
void search(const std::string &text)
Definition: helpwindow.cpp:187
bool executeChatCommand(const std::string &cmd, const std::string &args, ChatTab *const tab)
virtual void talk(const std::string &text) const =0
Definition: rect.h:74
int y
Definition: rect.h:214
int height
Definition: rect.h:224
void setVerticalScrollAmount(const int vScroll)
void setScrollPolicy(const ScrollPolicy hPolicy, const ScrollPolicy vPolicy)
int getVerticalMaxScroll()
void setScrollAmount(const int hScroll, const int vScroll)
int getVerticalScrollAmount() const
Definition: scrollarea.h:274
void logic()
Definition: scrollarea.cpp:273
bool mouseFocused
Definition: settings.h:156
KeyboardFocusT inputFocused
Definition: settings.h:155
void playGuiSound(const std::string &name)
Definition: tab.h:88
void setFlash(const int flash)
Definition: tab.h:175
int getFlash() const
Definition: tab.h:178
void setCaption(const std::string &caption)
Definition: tab.cpp:458
TabbedArea * getTabbedArea() const
Definition: tab.cpp:453
Tab * getSelectedTab() const
Definition: tabbedarea.h:175
virtual void requestMoveToTop()
Definition: widget.cpp:213
virtual void showPart(const Rect &rectangle)
Definition: widget.cpp:511
int getHeight() const
Definition: widget.h:240
Configuration config
#define new
Definition: debug_new.h:147
#define delete2(var)
Definition: delete2.h:25
#define _(s)
Definition: gettext.h:35
HelpWindow * helpWindow
Definition: helpwindow.cpp:54
bool IgnoreRecord
Definition: ignorerecord.h:30
const bool IgnoreRecord_false
Definition: ignorerecord.h:30
InputManager inputManager
LocalPlayer * localPlayer
bool msg(InputEvent &event)
Definition: chat.cpp:39
void replaceVars(std::string &data)
std::string trim(std::string const &str)
ServerTypeT getNetworkType()
Definition: net.cpp:189
bool Online
Definition: online.h:30
const bool Online_true
Definition: online.h:30
const bool Opaque_false
Definition: opaque.h:30
const bool Opaque_true
Definition: opaque.h:30
Settings settings
Definition: settings.cpp:32
static const std::string SOUND_GLOBAL
Definition: sound.h:33
static const std::string SOUND_HIGHLIGHT
Definition: sound.h:32
static const std::string SOUND_WHISPER
Definition: sound.h:31
SoundManager soundManager
std::string removeColors(std::string msg)
std::string strprintf(const char *const format,...)
void replaceItemLinks(std::string &msg)
std::string text
Definition: chatlog.h:46
ChatMsgTypeT own
Definition: chatlog.h:47
std::string nick
Definition: chatlog.h:45
const bool TryRemoveColors_true
bool TryRemoveColors
const bool TryRemoveColors_false