Mana
Loading...
Searching...
No Matches
chatwindow.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2004-2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 *
6 * This file is part of The Mana Client.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include "chatwindow.h"
23
24#include "actorspritemanager.h"
25#include "channelmanager.h"
26#include "configuration.h"
27#include "localplayer.h"
28#include "playerrelations.h"
29
30#include "gui/recorder.h"
31#include "gui/setup.h"
32
34#include "gui/widgets/chattab.h"
36#include "gui/widgets/layout.h"
41
42#include "net/chathandler.h"
43#include "net/net.h"
44
45#include "utils/gettext.h"
46#include "utils/stringutils.h"
47
48#include <guichan/focushandler.hpp>
49#include <guichan/focuslistener.hpp>
50
51#include <sstream>
52
56class ChatInput : public TextField, public gcn::FocusListener
57{
58 public:
60 TextField(std::string(), false)
61 {
62 setVisible(false);
63 addFocusListener(this);
64 }
65
70 void focusLost(const gcn::Event &event) override
71 {
72 setVisible(false);
73 }
74};
75
77{
78 void getAutoCompleteList(std::vector<std::string> &list) const override
79 {
80 auto tab = static_cast<ChatTab *>(chatWindow->mChatTabs->getSelectedTab());
81 tab->getAutoCompleteList(list);
82 }
83};
84
86 Window(SkinType::Popup, _("Chat")),
87 mItemLinkHandler(new ItemLinkHandler(this)),
88 mChatInput(new ChatInput),
89 mAutoComplete(new ChatAutoComplete),
90 mChatTabs(new TabbedArea)
91{
94
95 setWindowName("Chat");
96
98
99 // no title presented, title bar is padding so window can be moved.
100 setTitleBarHeight(getPadding() + 4);
101 setShowTitle(false);
102 setResizable(true);
103 setDefaultVisible(true);
104 setSaveVisible(true);
106 setMinWidth(150);
107 setMinHeight(90);
108
109 mChatInput->setActionEventId("chatinput");
110 mChatInput->addActionListener(this);
111
112 // Override the padding from the theme since we want the content very close
113 // to the border on this window.
114 setPadding(std::min<unsigned>(getPadding(), 6));
116
117 place(0, 0, mChatTabs, 3, 3);
118 place(0, 3, mChatInput, 3).setPadding(mChatInput->getFrameSize());
119
121
124
125 mRecorder = new Recorder(this);
126}
127
129{
130 delete mRecorder;
132 delete mItemLinkHandler;
133 delete mAutoComplete;
134}
135
141
143{
144 return static_cast<ChatTab*>(mChatTabs->getSelectedTab());
145}
146
148{
149 if (auto tab = getFocused())
150 tab->clearText();
151}
152
154{
155 int tab = mChatTabs->getSelectedTabIndex();
156
157 if (tab == 0)
158 tab = mChatTabs->getNumberOfTabs();
159 tab--;
160
162}
163
165{
166 int tab = mChatTabs->getSelectedTabIndex();
167
168 tab++;
169 if (tab == mChatTabs->getNumberOfTabs())
170 tab = 0;
171
173}
174
175void ChatWindow::action(const gcn::ActionEvent &event)
176{
177 if (event.getId() == "chatinput")
178 {
179 std::string message = mChatInput->getText();
180
181 if (!message.empty())
182 {
183 // Send the message to the server
184 chatInput(message);
185
186 // Clear the text from the chat input
187 mChatInput->setText(std::string());
188 }
189
190 if (message.empty() || !config.returnTogglesChat)
191 {
192 // Remove focus and hide input
193 mFocusHandler->focusNone();
194
195 // If the chatWindow is shown up because you want to send a message
196 // It should hide now
197 if (mTmpVisible)
198 setVisible(false);
199 }
200 }
201}
202
204{
205 // Make sure chatWindow is visible
206 if (!isVisible())
207 {
208 setVisible(true);
209
210 /*
211 * This is used to hide chatWindow after sending the message. There is
212 * a trick here, because setVisible will set mTmpVisible to false, you
213 * have to put this sentence *after* setVisible, not before it
214 */
215 mTmpVisible = true;
216 }
217
218 // Don't do anything else if the input is already visible and has focus
219 if (mChatInput->isVisible() && mChatInput->isFocused())
220 return false;
221
222 // Give focus to the chat input
223 mChatInput->setVisible(true);
224 mChatInput->requestFocus();
225 return true;
226}
227
229{
230 return mChatInput->isFocused();
231}
232
234{
235 mChatTabs->removeTab(tab);
236}
237
239{
240 // Make sure we don't end up with duplicates in the gui
241 // TODO
242
243 tab->mTextOutput->setPalette(getSkin().palette);
244 mChatTabs->addTab(tab, tab->mScrollArea);
245
246 // Update UI
247 logic();
248}
249
250void ChatWindow::removeWhisper(const std::string &nick)
251{
252 std::string tempNick = nick;
253 toLower(tempNick);
254 mWhispers.erase(tempNick);
255}
256
258{
259 // Swap with empty container before deleting, because each tab will try to
260 // remove itself from mWhispers when it gets deleted, possibly invalidating
261 // our iterator.
262 std::map<const std::string, ChatTab *> whispers;
263 mWhispers.swap(whispers);
264
265 for (auto &[_, tab] : whispers)
266 delete tab;
267}
268
269void ChatWindow::chatInput(const std::string &msg)
270{
271 ChatTab *tab = getFocused();
272 tab->chatInput(msg);
273}
274
276{
277 std::string response;
278 int playercount = 0;
279
280 for (auto actor : actorSpriteManager->getAll())
281 {
282 if (actor->getType() == ActorSprite::PLAYER)
283 {
284 if (!response.empty())
285 {
286 response += ", ";
287 }
288 response += static_cast<Being*>(actor)->getName();
289 ++playercount;
290 }
291 }
292
293 std::string log = strprintf(_("Present: %s; %d players are present."),
294 response.c_str(), playercount);
295
296 if (mRecorder->isRecording())
297 {
298 // Get the current system time
299 time_t t;
300 time(&t);
301
302 // Format the time string properly
303 std::ostringstream timeStr;
304 timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "")
305 << (int) (((t / 60) / 60) % 24)
306 << ":" << (((t / 60) % 60 < 10) ? "0" : "")
307 << (int) ((t / 60) % 60)
308 << "] ";
309
310 mRecorder->record(timeStr.str() + log);
311 getFocused()->chatLog(_("Attendance written to record log."),
312 BY_SERVER, true);
313 }
314 else
315 {
317 }
318}
319
320void ChatWindow::scroll(int amount)
321{
322 if (!isVisible())
323 return;
324
325 ChatTab *tab = getFocused();
326 if (tab)
327 tab->scroll(amount);
328}
329
330void ChatWindow::mousePressed(gcn::MouseEvent &event)
331{
333
334 if (event.isConsumed())
335 return;
336
337 // Enable dragging the chat window also in the tab area, since it doesn't
338 // have much of a title bar.
339 if (!mouseResize)
340 {
341 const int dragHeight = getFocused()->getHeight() +
342 static_cast<int>(getTitleBarHeight());
343
344 mMoved = event.getY() < dragHeight;
345 mDragOffsetX = event.getX();
346 mDragOffsetY = event.getY();
347 }
348}
349
350void ChatWindow::mouseDragged(gcn::MouseEvent &event)
351{
353
354 if (event.isConsumed())
355 return;
356
357 if (isMovable() && mMoved)
358 {
359 int newX = std::max(0, getX() + event.getX() - mDragOffsetX);
360 int newY = std::max(0, getY() + event.getY() - mDragOffsetY);
361 newX = std::min(graphics->getWidth() - getWidth(), newX);
362 newY = std::min(graphics->getHeight() - getHeight(), newY);
363 setPosition(newX, newY);
364 }
365}
366
367void ChatWindow::event(Event::Channel channel, const Event &event)
368{
369 if (channel == Event::NoticesChannel)
370 {
371 if (event.getType() == Event::ServerNotice)
372 localChatTab->chatLog(event.getString("message"), BY_SERVER);
373 }
374 else if (channel == Event::ChatChannel)
375 {
376 if (event.getType() == Event::Whisper)
377 {
378 whisper(event.getString("nick"), event.getString("message"));
379 }
380 else if (event.getType() == Event::WhisperError)
381 {
382 whisper(event.getString("nick"),
383 event.getString("error"), BY_SERVER);
384 }
385 else if (event.getType() == Event::Player)
386 {
387 localChatTab->chatLog(event.getString("message"), BY_PLAYER);
388 }
389 else if (event.getType() == Event::Announcement)
390 {
391 // Show on local tab
392 localChatTab->chatLog(event.getString("message"), BY_GM);
393 // Show on selected tab if it is not the global one
394 ChatTab *selected = getFocused();
395 if (selected && selected != localChatTab)
396 selected->chatLog(event.getString("message"), BY_GM);
397 }
398 else if (event.getType() == Event::Being)
399 {
400 if (event.getInt("permissions") & PlayerPermissions::SPEECH_LOG)
401 localChatTab->chatLog(event.getString("message"), BY_OTHER);
402 }
403 }
404}
405
406void ChatWindow::addInputText(const std::string &text)
407{
408 const int caretPos = mChatInput->getCaretPosition();
409 const std::string inputText = mChatInput->getText();
410
411 std::ostringstream ss;
412 ss << inputText.substr(0, caretPos) << text << " ";
413 ss << inputText.substr(caretPos);
414
415 mChatInput->setText(ss.str());
416 mChatInput->setCaretPosition(caretPos + text.length() + 1);
418}
419
420void ChatWindow::addItemText(const std::string &item)
421{
422 std::ostringstream text;
423 text << "[" << item << "]";
424 addInputText(text.str());
425}
426
427void ChatWindow::setVisible(bool isVisible)
428{
429 Window::setVisible(isVisible);
430
431 /*
432 * For whatever reason, if setVisible is called, the mTmpVisible effect
433 * should be disabled.
434 */
435 mTmpVisible = false;
436}
437
438void ChatWindow::setRecordingFile(const std::string &msg)
439{
441}
442
443void ChatWindow::whisper(const std::string &nick,
444 const std::string &mes, Own own)
445{
446 if (mes.empty())
447 return;
448
449 std::string playerName = local_player->getName();
450 std::string tempNick = nick;
451
452 toLower(playerName);
453 toLower(tempNick);
454
455 if (tempNick == playerName)
456 return;
457
458 ChatTab *tab = nullptr;
459 auto i = mWhispers.find(tempNick);
460
461 if (i != mWhispers.end())
462 tab = i->second;
463 else if (config.whisperTab)
464 tab = addWhisperTab(nick);
465
466 if (tab)
467 {
468 if (own == BY_PLAYER)
469 {
470 tab->chatInput(mes);
471 }
472 else if (own == BY_SERVER)
473 {
474 tab->chatLog(mes);
475 }
476 else
477 {
478 tab->chatLog(nick, mes);
479 local_player->afkRespond(tab, nick);
480 }
481 }
482 else
483 {
484 if (own == BY_PLAYER)
485 {
487
488 localChatTab->chatLog(strprintf(_("Whispering to %s: %s"),
489 nick.c_str(), mes.c_str()), BY_PLAYER);
490 }
491 else
492 {
493 localChatTab->chatLog(nick + " : " + mes, ACT_WHISPER, false);
494 }
495 }
496}
497
498ChatTab *ChatWindow::addWhisperTab(const std::string &nick, bool switchTo)
499{
500 std::string playerName = local_player->getName();
501 std::string tempNick = nick;
502
503 toLower(playerName);
504 toLower(tempNick);
505
506 if (mWhispers.find(tempNick) != mWhispers.end() || tempNick == playerName)
507 return nullptr;
508
509 ChatTab *ret = new WhisperTab(nick);
510 mWhispers[tempNick] = ret;
511
512 if (switchTo)
514
515 return ret;
516}
ActorSpriteManager * actorSpriteManager
Definition game.cpp:110
Own
Definition chatwindow.h:46
@ BY_GM
Definition chatwindow.h:47
@ ACT_WHISPER
Definition chatwindow.h:52
@ BY_OTHER
Definition chatwindow.h:49
@ BY_PLAYER
Definition chatwindow.h:48
@ BY_SERVER
Definition chatwindow.h:50
const ActorSprites & getAll() const
Returns the whole list of beings.
Definition being.h:65
const std::string & getName() const
Returns the name of the being.
Definition being.h:190
void setPalette(int palette)
Definition browserbox.h:90
void getAutoCompleteList(std::vector< std::string > &list) const override
The chat input hides when it loses focus.
void focusLost(const gcn::Event &event) override
Called if the chat input loses focus.
A tab for the chat window.
Definition chattab.h:36
void chatLog(std::string line, Own own=BY_SERVER, bool ignoreRecord=false)
Adds a line of text to our message list.
Definition chattab.cpp:111
ScrollArea * mScrollArea
Definition chattab.h:130
void scroll(int amount)
Scrolls the chat window.
Definition chattab.cpp:303
void getAutoCompleteList(std::vector< std::string > &names) const override
Definition chattab.cpp:332
void chatInput(const std::string &msg)
Determines whether the message is a command or message, then sends the given message to the game serv...
Definition chattab.cpp:259
void clearText()
Clears the text from the tab.
Definition chattab.cpp:312
BrowserBox * mTextOutput
Definition chattab.h:131
void whisper(const std::string &nick, const std::string &mes, Own own=BY_OTHER)
void clearTab()
Clear the current tab.
void addItemText(const std::string &item)
Called to add item to chat.
ChatInput * mChatInput
Input box for typing chat messages.
Definition chatwindow.h:190
TabbedArea * mChatTabs
Tabbed area for holding each channel.
Definition chatwindow.h:199
bool isInputFocused() const
Checks whether ChatWindow is Focused or not.
void setVisible(bool visible) override
Override to reset mTmpVisible.
void setRecordingFile(const std::string &msg)
Sets the file being recorded to.
void removeWhisper(const std::string &nick)
~ChatWindow() override
Destructor: used to write back values to the config file.
void addInputText(const std::string &text)
Add the given text to the chat input.
bool mTmpVisible
Definition chatwindow.h:196
friend class WhisperTab
Definition chatwindow.h:172
void mouseDragged(gcn::MouseEvent &event) override
bool requestChatFocus()
Request focus for typing chat message.
void scroll(int amount)
Scrolls the chat window.
ItemLinkHandler * mItemLinkHandler
Used for showing item popup on clicking links.
Definition chatwindow.h:186
void removeTab(ChatTab *tab)
Remove the given tab from the window.
AutoCompleteLister * mAutoComplete
Definition chatwindow.h:193
void nextTab()
Switch to the next tab in order.
TextHistory mHistory
Definition chatwindow.h:192
ChatTab * addWhisperTab(const std::string &nick, bool switchTo=false)
void action(const gcn::ActionEvent &event) override
Performs action.
void mousePressed(gcn::MouseEvent &event) override
void doPresent()
void chatInput(const std::string &msg)
Passes the text to the current tab as input.
void prevTab()
Switch to the previous tab in order.
void removeAllWhispers()
std::map< const std::string, ChatTab * > mWhispers
Manage whisper tabs.
Definition chatwindow.h:202
void resetToDefaultSize() override
Reset the chat window and recorder window attached to it to their default positions.
Recorder * mRecorder
Definition chatwindow.h:187
void addTab(ChatTab *tab)
Add the tab to the window.
ChatTab * getFocused() const
Gets the focused tab.
void event(Event::Channel channel, const Event &event) override
void listen(Event::Channel channel)
Definition event.h:42
@ ServerNotice
Definition event.h:95
@ Announcement
Definition event.h:62
@ Being
Definition event.h:63
@ Whisper
Definition event.h:102
@ Player
Definition event.h:92
@ WhisperError
Definition event.h:103
Channel
Definition event.h:45
@ ChatChannel
Definition event.h:49
@ NoticesChannel
Definition event.h:54
int getHeight() const
Returns the logical height of the screen.
Definition graphics.h:226
int getWidth() const
Returns the logical width of the screen.
Definition graphics.h:221
LayoutCell & setPadding(int p)
Sets the padding around the cell content.
Definition layout.h:179
void afkRespond(ChatTab *tab, const std::string &nick)
virtual void privateMessage(const std::string &recipient, const std::string &text)=0
A light version of the Window class.
Definition popup.h:48
void setRecordingFile(const std::string &msg)
Sets the file being recorded to.
Definition recorder.cpp:68
bool isRecording()
Whether or not the recorder is in use.
Definition recorder.h:60
void record(const std::string &msg)
Outputs the message to the recorder file.
Definition recorder.cpp:62
void registerWindowForReset(Window *window)
Enables the Reset Windows button.
Definition setup.cpp:108
A tabbed area, the same as the guichan tabbed area in 0.8, but extended.
Definition tabbedarea.h:40
void addTab(gcn::Tab *tab, gcn::Widget *widget) override
Add a tab.
void removeTab(gcn::Tab *tab) override
Override the remove tab function as it's broken in guichan 0.8.
void setSelectedTab(unsigned int index) override
Definition tabbedarea.h:101
int getNumberOfTabs() const
Return how many tabs have been created.
A text field.
Definition textfield.h:72
void setAutoComplete(AutoCompleteLister *lister)
Sets the TextField's source of autocomplete.
Definition textfield.h:133
void setHistory(TextHistory *history)
Sets the TextField's source of input history.
Definition textfield.h:145
A window.
Definition window.h:59
const Skin & getSkin() const
Returns the Skin used by this window.
Definition window.cpp:332
virtual void setVisible(bool visible)
Overloads window setVisible by Guichan to allow sticky window handling.
Definition window.cpp:282
void setDefaultVisible(bool save)
Sets whether the window is visible by default.
Definition window.h:215
void setMinHeight(int height)
Sets the minimum height of the window.
Definition window.cpp:197
Layout & getLayout()
Gets the layout handler for this window.
Definition window.cpp:714
void setWindowName(const std::string &name)
Sets the name of the window.
Definition window.h:272
void mouseDragged(gcn::MouseEvent &event) override
Implements window resizing and makes sure the window is not dragged/resized outside of the screen.
Definition window.cpp:397
virtual void resetToDefaultSize()
Reset the win pos and size to default.
Definition window.cpp:600
void setResizable(bool resize)
Sets whether or not the window can be resized.
Definition window.cpp:212
void setSaveVisible(bool save)
Sets whether the window will save it's visibility.
Definition window.h:225
LayoutCell & place(int x, int y, gcn::Widget *, int w=1, int h=1)
Adds a widget to the window and sets it at given cell.
Definition window.cpp:737
void setShowTitle(bool flag)
Sets flag to show a title or not.
Definition window.h:176
void setDefaultSize()
Set the default win pos and size to the current ones.
Definition window.cpp:545
void loadWindowState()
Reads the position (and the size for resizable windows) in the configuration based on the given strin...
Definition window.cpp:467
void mousePressed(gcn::MouseEvent &event) override
Starts window resizing when appropriate.
Definition window.cpp:304
static int mouseResize
Active resize handles.
Definition window.h:383
void setMinWidth(int width)
Sets the minimum width of the window.
Definition window.cpp:192
Config config
Global settings (config.xml)
Definition client.cpp:97
Graphics * graphics
Definition client.cpp:104
ChatTab * localChatTab
Definition game.cpp:117
ChatWindow * chatWindow
Definition game.cpp:93
#define _(s)
Definition gettext.h:38
LocalPlayer * local_player
ChatHandler * getChatHandler()
Definition net.cpp:70
Setup * setupWindow
Definition setup.cpp:120
std::string & toLower(std::string &str)
Converts the given string to lower case.
std::string strprintf(char const *format,...)
A safe version of sprintf that returns a std::string of the result.
bool returnTogglesChat
bool whisperTab
SkinType
Definition theme.h:69