1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2012 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
6 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
7 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
9 // This program is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU Affero General Public License as
11 // published by the Free Software Foundation, either version 3 of the
12 // License, or (at your option) any later version.
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU Affero General Public License for more details.
19 // You should have received a copy of the GNU Affero General Public License
20 // along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "game_share/shard_names.h"
30 #include "../r2/editor.h"
32 #include "chat_window.h"
33 #include "chat_text_manager.h"
34 #include "../user_entity.h"
35 #include "people_interraction.h"
36 #include "../connection.h"
38 #include "nel/gui/group_container.h"
39 #include "nel/gui/group_editbox.h"
40 #include "nel/gui/group_tab.h"
41 #include "interface_manager.h"
42 #include "nel/gui/action_handler.h"
43 #include "../client_chat_manager.h"
45 #include "../session_browser_impl.h"
47 #include "../r2/editor.h"
48 #include "../r2/dmc/client_edition_module.h"
50 using namespace NLMISC
;
57 CChatWindow
*CChatWindow::_ChatWindowLaunchingCommand
= NULL
;
64 extern NLMISC::CLog g_log
;
65 extern CClientChatManager ChatMngr
;
71 CChatWindowDesc::CChatWindowDesc() : InsertPosition(-1),
83 //=================================================================================
84 CChatWindow::CChatWindow() : _Listener(NULL
), _Chat(NULL
), _EB(NULL
), _ParentBlink(false)
88 //=================================================================================
89 bool CChatWindow::create(const CChatWindowDesc
&desc
, const std::string
&chatId
)
92 CInterfaceManager
*im
= CInterfaceManager::getInstance();
94 // get the father container
95 CGroupContainer
*fatherContainer
= NULL
;
96 if (!desc
.FatherContainer
.empty())
98 if (desc
.FatherContainer
!= "ui:interface" )
100 fatherContainer
= dynamic_cast<CGroupContainer
*>(CWidgetManager::getInstance()->getElementFromId(desc
.FatherContainer
));
101 if (!fatherContainer
)
103 nlwarning("<CChatWindow::create> Can't get father group, or bad type");
109 // get the good template
110 std::string chatTemplate
;
111 if (desc
.ChatTemplate
.empty())
113 // no chat template provided : use default
114 chatTemplate
= "chat_id";
118 chatTemplate
= desc
.ChatTemplate
;
122 CChatWindowDesc::TTemplateParams params
;
123 params
.push_back(make_pair(string("id"), chatId
));
124 params
.insert(params
.end(), desc
.ChatTemplateParams
.begin(), desc
.ChatTemplateParams
.end());
126 // create a chat container from the template
127 CInterfaceGroup
*chatGroup
= CWidgetManager::getInstance()->getParser()->createGroupInstance(chatTemplate
, "ui:interface", params
);
130 _Chat
= dynamic_cast<CGroupContainer
*>(chatGroup
);
133 nlwarning("<CChatWindow::create> Bad type for chat group");
137 _Chat
->setLocalize (desc
.Localize
);
138 _Chat
->setTitle(desc
.Title
);
139 _Chat
->setSavable(desc
.Savable
);
141 // groups like system info don't have edit box.
142 _EB
= dynamic_cast<CGroupEditBox
*>(_Chat
->getGroup("eb"));
145 _EB
->setAHOnEnter("chat_box_entry");
148 CInterfaceGroup
*pRoot
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface"));
152 fatherContainer
->attachContainer(_Chat
, desc
.InsertPosition
);
156 if (desc
.FatherContainer
== "ui:interface")
158 CWidgetManager::getInstance()->addWindowToMasterGroup("ui:interface", _Chat
);
159 _Chat
->setParent(pRoot
);
160 _Chat
->setMovable(true);
161 _Chat
->setActive(false);
162 _Chat
->setOpen(true);
165 _ParentBlink
= desc
.ParentBlink
;
166 _Listener
= desc
.Listener
;
168 pRoot
->addGroup (_Chat
);
178 //=================================================================================
179 bool CChatWindow::isVisible() const
181 if (!_Chat
) return false;
184 CInterfaceGroup
*ig
= _Chat
;
187 if (ig
->isGroupContainer())
189 if (!static_cast<CGroupContainer
*>(ig
)->isOpen()) break;
191 if (!ig
->getActive()) break;
192 ig
= ig
->getParent();
195 return ig
== NULL
; // all parent windows must be open & visible
203 //=================================================================================
204 void CChatWindow::displayMessage(const string
&msg
, NLMISC::CRGBA col
, CChatGroup::TGroupType gt
, uint32 dynamicChatDbIndex
, uint numBlinks
/* = 0*/, bool *windowVisible
/*= NULL*/)
208 if (msg
!= "WRN: <CChatWindow::displayMessage> There's no global chat")
209 nlwarning("<CChatWindow::displayMessage> There's no global chat");
214 CChatTextManager
&ctm
= getChatTextMngr();
216 gl
= dynamic_cast<CGroupList
*>(_Chat
->getGroup("cb:text_list"));
217 if (gl
) gl
->addChild(ctm
.createMsgText(msg
, col
));
219 // if the group is closed, make it blink
220 if (!_Chat
->isOpen())
222 if (numBlinks
) _Chat
->enableBlink(numBlinks
);
226 CGroupContainer
*father
= dynamic_cast<CGroupContainer
*>(_Chat
->getParent());
227 if (father
&& !father
->isOpen())
229 father
->enableBlink(numBlinks
);
232 if (windowVisible
!= NULL
)
234 *windowVisible
= isVisible();
236 /*for(std::vector<IObserver *>::iterator it = _Observers.begin(); it != _Observers.end(); ++it)
238 (*it)->displayMessage(this, msg, col, numBlinks);
242 //=================================================================================
243 void CChatWindow::setMenu(const std::string
&menuName
)
246 if (_Chat
->getHeaderOpened())
248 _Chat
->getHeaderOpened()->setRightClickHandler("active_menu");
249 _Chat
->getHeaderOpened()->setRightClickHandlerParams("menu=" + menuName
);
251 if (_Chat
->getHeaderClosed())
253 _Chat
->getHeaderClosed()->setRightClickHandler("active_menu");
254 _Chat
->getHeaderClosed()->setRightClickHandlerParams("menu=" + menuName
);
258 //=================================================================================
259 void CChatWindow::setPrompt(const string
&prompt
)
262 CGroupEditBox
*eb
= dynamic_cast<CGroupEditBox
*>(_Chat
->getGroup("eb"));
264 eb
->setPrompt(prompt
);
267 void CChatWindow::setPromptColor(NLMISC::CRGBA col
)
272 CGroupEditBox
*eb
= dynamic_cast<CGroupEditBox
*>(_Chat
->getGroup("eb"));
279 //=================================================================================
280 void CChatWindow::deleteContainer()
283 CGroupContainer
*proprietaryContainer
= _Chat
->getProprietaryContainer();
284 if (proprietaryContainer
)
286 if (_Chat
->isPopuped())
288 _Chat
->popin(-1, false); // popin & detach
292 proprietaryContainer
->detachContainer(_Chat
); // just detach
294 CInterfaceManager
*im
= CInterfaceManager::getInstance();
295 CInterfaceGroup
*pRoot
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface"));
296 pRoot
->delGroup (_Chat
);
300 CWidgetManager::getInstance()->unMakeWindow(_Chat
);
301 if (_Chat
->getParent())
303 _Chat
->getParent()->delGroup(_Chat
);
306 // Removes from parent group
311 //=================================================================================
312 bool CChatWindow::rename(const string
&newName
, bool newNameLocalize
)
314 return getChatWndMgr().rename(getTitle(), newName
, newNameLocalize
);
317 //=================================================================================
318 void CChatWindow::setKeyboardFocus()
320 if (!_EB
|| !_Chat
) return;
321 CWidgetManager::getInstance()->setCaptureKeyboard(_EB
);
322 if (!_Chat
->isOpenable() || _Chat
->isOpenWhenPopup())
324 if (_Chat
->isPopable() && !_Chat
->isPopuped())
327 if (_Chat
->getPopupW() != -1) // restore previous popup position if there's one
329 _Chat
->setX(_Chat
->getPopupX());
330 _Chat
->setY(_Chat
->getPopupY());
331 _Chat
->setW(_Chat
->getPopupW());
332 // must resize the children to get correct height
333 //_Chat->setChildrenH(_Chat->getPopupChildrenH());
339 //=================================================================================
340 void CChatWindow::enableBlink(uint numBlinks
)
343 _Chat
->enableBlink(numBlinks
);
347 //=================================================================================
348 void CChatWindow::setCommand(const std::string
&command
, bool execute
)
351 _EB
->setCommand(command
, execute
);
354 //=================================================================================
355 void CChatWindow::setEntry(const string
&entry
)
358 _EB
->setInputString(entry
);
361 //=================================================================================
362 string
CChatWindow::getTitle() const
370 return _Chat
->getTitle();
374 //=================================================================================
375 void CChatWindow::addObserver(IObserver
*obs
)
379 nlwarning("NULL observer is invalid");
384 nlwarning("Observer added twice");
387 _Observers
.push_back(obs
);
390 //=================================================================================
391 void CChatWindow::removeObserver(IObserver
*obs
)
393 std::vector
<IObserver
*>::iterator it
= std::find(_Observers
.begin(), _Observers
.end(), obs
);
394 if (it
== _Observers
.end())
396 nlwarning("Observer doesn't belong to this chatbox");
399 _Observers
.erase(it
);
402 //=================================================================================
403 bool CChatWindow::isObserver(const IObserver
*obs
) const
405 std::vector
<IObserver
*>::const_iterator it
= std::find(_Observers
.begin(), _Observers
.end(), obs
);
406 return it
!= _Observers
.end();
409 //=================================================================================
410 CChatWindow::~CChatWindow()
412 for(std::vector
<IObserver
*>::iterator it
= _Observers
.begin(); it
!= _Observers
.end(); ++it
)
414 (*it
)->chatWindowRemoved(this);
416 if (this == _ChatWindowLaunchingCommand
)
418 _ChatWindowLaunchingCommand
= NULL
;
422 //=================================================================================
423 void CChatWindow::setAHOnActive(const std::string
&n
)
425 if (_Chat
) _Chat
->setOnActiveHandler(n
);
428 //=================================================================================
429 void CChatWindow::setAHOnActiveParams(const std::string
&n
)
431 if (_Chat
) _Chat
->setOnActiveParams(n
);
434 //=================================================================================
435 void CChatWindow::setAHOnDeactive(const std::string
&n
)
437 if (_Chat
) _Chat
->setOnDeactiveHandler(n
);
440 //=================================================================================
441 void CChatWindow::setAHOnDeactiveParams(const std::string
&n
)
443 if (_Chat
) _Chat
->setOnDeactiveParams(n
);
446 //=================================================================================
447 void CChatWindow::setAHOnCloseButton(const std::string
&n
)
449 if (_Chat
) _Chat
->setOnCloseButtonHandler(n
);
452 //=================================================================================
453 void CChatWindow::setAHOnCloseButtonParams(const std::string
&n
)
455 if (_Chat
) _Chat
->setOnCloseButtonParams(n
);
458 //=================================================================================
459 void CChatWindow::setHeaderColor(const std::string
&n
)
461 if (_Chat
) _Chat
->setHeaderColor(n
);
464 //=================================================================================
465 void CChatWindow::displayLocalPlayerTell(const string
&receiver
, const string
&msg
, uint numBlinks
/*= 0*/)
468 CInterfaceProperty prop
;
469 prop
.readRGBA("UI:SAVE:CHAT:COLORS:SPEAKER"," ");
470 encodeColorTag(prop
.getRGBA(), finalMsg
, false);
472 string
csr(CHARACTER_TITLE::isCsrTitle(UserEntity
->getTitleRaw()) ? "(CSR) " : "");
473 finalMsg
+= csr
+ CI18N::get("youTell") + ": ";
474 prop
.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," ");
475 encodeColorTag(prop
.getRGBA(), finalMsg
, true);
478 string s
= CI18N::get("youTellPlayer");
479 strFindReplace(s
, "%name", receiver
);
480 strFindReplace(finalMsg
, CI18N::get("youTell"), s
);
481 displayMessage(finalMsg
, prop
.getRGBA(), CChatGroup::tell
, 0, numBlinks
);
482 CInterfaceManager::getInstance()->log(finalMsg
, CChatGroup::groupTypeToString(CChatGroup::tell
));
485 void CChatWindow::encodeColorTag(const NLMISC::CRGBA
&color
, std::string
&text
, bool append
)
487 // WARNING : The lookup table MUST contains 17 element (with the last doubled)
488 // because we add 7 to the 8 bit color before shifting to right in order to match color
490 // Have 17 entry remove the need for a %16 for each color component.
491 // By the way, this comment is more longer to type than to add the %16...
493 static char ConvTable
[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'F'};
497 str
.reserve(7 + str
.size());
504 str
+= ConvTable
[(uint(color
.R
)+7)>>4];
505 str
+= ConvTable
[(uint(color
.G
)+7)>>4];
506 str
+= ConvTable
[(uint(color
.B
)+7)>>4];
507 str
+= ConvTable
[(uint(color
.A
)+7)>>4];
514 //=================================================================================
515 void CChatWindow::clearMessages(CChatGroup::TGroupType
/* gt */, uint32
/* dynamicChatDbIndex */)
517 // if not correctly init, abort
521 // get the group list
522 CGroupList
*gl
= dynamic_cast<CGroupList
*>(_Chat
->getGroup("cb:text_list"));
523 if (gl
) gl
->deleteAllChildren();
527 //////////////////////
528 // CChatGroupWindow //
529 //////////////////////
531 void CChatGroupWindow::displayMessage(const string
&msg
, NLMISC::CRGBA col
, CChatGroup::TGroupType gt
, uint32 dynamicChatDbIndex
, uint numBlinks
, bool *windowVisible
)
535 if (msg
!= "WRN: <CChatGroupWindow::displayMessage> There's no global chat")
536 nlwarning("<CChatGroupWindow::displayMessage> There's no global chat");
540 CChatTextManager
&ctm
= getChatTextMngr();
542 if (_Chat
->getHeaderOpened()==NULL
)
546 // *** Display the message in the correct tab window
547 // get the gl and tab according to filter
550 getAssociatedSubWindow(gt
, dynamicChatDbIndex
, gl
, tab
);
552 // on a new message, change the Tab color
553 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
554 CRGBA newMsgColor
= CRGBA::stringToRGBA(CWidgetManager::getInstance()->getParser()->getDefine("chat_group_tab_color_newmsg").c_str());
561 gl
->addChild(ctm
.createMsgText(newmsg
, col
));
562 if (!gl
->getParent()->getActive())
564 tab
->setTextColorNormal(newMsgColor
);
567 // *** Display the message in the UserChat (special case)
569 tab
= dynamic_cast<CCtrlTabButton
*>(_Chat
->getCtrl("header_opened:channel_select:tab5"));
571 CGroupList
*gl2
= dynamic_cast<CGroupList
*>(_Chat
->getGroup("content:cb:user:text_list"));
573 CChatWindow
*cw
= PeopleInterraction
.TheUserChat
.Window
;
574 CChatStdInput
&ci
= PeopleInterraction
.ChatInput
;
579 case CChatGroup::arround
:
580 case CChatGroup::say
: if (ci
.AroundMe
.isListeningWindow(cw
)) gl
= gl2
; break;
581 case CChatGroup::region
: if (ci
.Region
.isListeningWindow(cw
)) gl
= gl2
; break;
582 case CChatGroup::team
: if (ci
.Team
.isListeningWindow(cw
)) gl
= gl2
; break;
583 case CChatGroup::guild
: if (ci
.Guild
.isListeningWindow(cw
)) gl
= gl2
; break;
584 case CChatGroup::system
: if (ci
.SystemInfo
.isListeningWindow(cw
)) gl
= gl2
; break;
585 case CChatGroup::universe
: if (ci
.Universe
.isListeningWindow(cw
)) gl
= gl2
; break;
586 case CChatGroup::dyn_chat
:
587 if (ci
.DynamicChat
[dynamicChatDbIndex
].isListeningWindow(cw
))
591 // Add dyn chan number before string
592 string prefix
= "[" + NLMISC::toString(dynamicChatDbIndex
) + "]";
593 // Find position to put the new string
595 size_t pos
= newmsg
.find("]");
596 size_t colonpos
= newmsg
.find(": @{");
597 // If no ] found or if found but after the colon (so part of the user chat)
598 if (pos
== string::npos
|| (colonpos
< pos
))
600 // No timestamp, so put it right after the color and add a space
601 pos
= newmsg
.find("}");
605 if (pos
== string::npos
)
606 newmsg
= prefix
+ newmsg
;
608 newmsg
= newmsg
.substr(0, pos
+ 1) + prefix
+ newmsg
.substr(pos
+ 1);
610 // Add dynchannel number and optionally name before text if user channel
611 CCDBNodeLeaf
* node
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_DYN_CHANNEL_NAME_IN_CHAT_CB", false);
612 if (node
&& node
->getValueBool())
614 uint32 textId
= ChatMngr
.getDynamicChannelNameFromDbIndex(dynamicChatDbIndex
);
616 STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId
, title
);
617 prefix
= (title
.empty() ? "" : " ") + title
;
618 pos
= newmsg
.find("] ");
620 if (pos
== string::npos
)
621 newmsg
= prefix
+ newmsg
;
623 newmsg
= newmsg
.substr(0, pos
) + prefix
+ newmsg
.substr(pos
);
631 gl
->addChild(ctm
.createMsgText(newmsg
, col
));
632 if (!gl
->getParent()->getActive())
634 tab
->setTextColorNormal(newMsgColor
);
639 // *** Blink and visibility event
640 // if the group is closed, make it blink
641 if (!_Chat
->isOpen())
643 if (numBlinks
) _Chat
->enableBlink(numBlinks
);
647 CGroupContainer
*father
= dynamic_cast<CGroupContainer
*>(_Chat
->getParent());
648 if (father
&& !father
->isOpen())
650 father
->enableBlink(numBlinks
);
653 if (windowVisible
!= NULL
)
655 *windowVisible
= isVisible();
659 //=================================================================================
660 void CChatGroupWindow::displayTellMessage(const string
&msg
, NLMISC::CRGBA col
, const string
&sender
)
662 // If we are here with a tell message this is because the teller doesn't belong to any people list
663 CGroupContainer
*gcChat
= createFreeTeller(sender
);
666 nlwarning("<CChatGroupWindow::displayTellMessage> cannot open chat.");
670 gcChat
->requireAttention();
672 CWidgetManager::getInstance()->setTopWindow(gcChat
);
674 // add the text to this window
675 CGroupList
*gl
= dynamic_cast<CGroupList
*>(gcChat
->getGroup("text_list"));
678 nlwarning("<CChatGroupWindow::displayTellMessage> can't get text_list.");
682 gl
->addChild(getChatTextMngr().createMsgText(msg
, col
));
685 //=================================================================================
686 sint32
CChatGroupWindow::getTabIndex()
688 CGroupTab
*pTab
= dynamic_cast<CGroupTab
*>(_Chat
->getGroup("header_opened:channel_select"));
690 return pTab
->getSelection();
695 //=================================================================================
696 void CChatGroupWindow::setTabIndex(sint32 n
)
698 CGroupTab
*pTab
= dynamic_cast<CGroupTab
*>(_Chat
->getGroup("header_opened:channel_select"));
702 // if the current button is hidden, select default not hid
703 pTab
->selectDefaultIfCurrentHid();
707 //=================================================================================
708 const string
CChatGroupWindow::getValidUiStringId(const string
&stringId
)
710 string validStringId
;
712 for (uint32 i
=0; i
< stringId
.length(); i
++)
714 if ((stringId
[i
] < 'a') || (stringId
[i
] > 'z'))
715 validStringId
+= '_';
717 validStringId
+= stringId
[i
];
719 return validStringId
;
722 //=================================================================================
723 CGroupContainer
*CChatGroupWindow::createFreeTeller(const string
&winNameIn
, const string
&winColor
)
725 // must parse the entity name, and eventually make it Full with shard name (eg: 'ani.yoyo' becomes 'yoyo(Aniro)')
726 string winNameFull
= CShardNames::getInstance().makeFullNameFromRelative(PlayerSelectedMainland
, winNameIn
);
728 // remove shard name if necessary
729 string winName
= CEntityCL::removeShardFromName(winNameFull
);
732 string sWinColor
= winColor
;
733 if (sWinColor
.empty())
734 sWinColor
= "UI:SAVE:WIN:COLORS:COM";
736 // Look if the free teller do not already exists
738 string sWinName
= winName
;
739 sWinName
= toLower(sWinName
);
740 for (i
= 0; i
< _FreeTellers
.size(); ++i
)
742 CGroupContainer
*pGC
= _FreeTellers
[i
];
743 if (toLower(pGC
->getTitle()) == sWinName
)
746 // Create container if not present
747 if (i
== _FreeTellers
.size())
749 // Corresponding Chat not created -> create and open
750 vector
<pair
<string
,string
> > properties
;
751 properties
.push_back(make_pair(string("posparent"), string("parent")));
752 properties
.push_back(make_pair(string("id"), "free_chat_" + getValidUiStringId(sWinName
)));
753 properties
.push_back(make_pair(string("title"), std::string("")));
754 properties
.push_back(make_pair(string("header_color"), sWinColor
));
756 std::string templateName
= "contact_chat_friend";
758 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
759 CInterfaceGroup
*pIG
= CWidgetManager::getInstance()->getParser()->createGroupInstance(templateName
, "ui:interface", properties
);
760 if (!pIG
) return NULL
;
761 CGroupContainer
*pGC
= dynamic_cast<CGroupContainer
*>(pIG
);
765 nlwarning("<CChatGroupWindow::createFreeTeller> group is not a container.(%s)", winName
.c_str());
768 // set title from the name
769 pGC
->setTitle(winName
);
771 pGC
->setSavable(true);
772 pGC
->setEscapable(true);
774 CInterfaceGroup
*pRoot
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface"));
775 pRoot
->addGroup (pGC
);
776 pGC
->setParent(pRoot
); // must be done before makeWindow
777 CWidgetManager::getInstance()->makeWindow(pGC
);
781 _FreeTellers
.push_back(pGC
);
783 CInterfaceElement
*result
= pRoot
->findFromShortId(string("invite"));
786 CCtrlBaseButton
* inviteButton
= dynamic_cast<CCtrlBaseButton
*>(result
);
790 R2::CEditor::TMode mode
= R2::getEditor().getMode();
791 if (mode
!= R2::CEditor::NotInitialized
)
793 isDM
= R2::getEditor().getDMC().getEditionModule().isSessionOwner()
794 && uint32(R2::CEditor::AnimationModeLoading
) <= uint32(mode
)
795 && uint32(mode
) <= uint32(R2::CEditor::AnimationModeGoingToPlay
);
797 inviteButton
->setActive(isDM
);
801 // the group is only active on the current desktop
802 pGC
->setActive(true);
805 if (!winColor
.empty())
806 _FreeTellers
[i
]->setHeaderColor(winColor
);
808 // updateFreeTellerHeader(*_FreeTellers[i]);
809 return _FreeTellers
[i
];
812 //=================================================================================
813 void CChatGroupWindow::updateAllFreeTellerHeaders()
815 for(uint k
= 0; k
< _FreeTellers
.size(); ++k
)
819 updateFreeTellerHeader(*_FreeTellers
[k
]);
824 //=================================================================================
825 void CChatGroupWindow::updateFreeTellerHeader(CGroupContainer
&ft
)
827 string name
= ft
.getTitle();
828 CCtrlBaseButton
*newFriendBut
= dynamic_cast<CCtrlBaseButton
*>(ft
.getCtrl("new_friend"));
829 CCtrlBaseButton
*ignoreBut
= dynamic_cast<CCtrlBaseButton
*>(ft
.getCtrl("ignore"));
830 CCtrlBaseButton
*inviteBut
= dynamic_cast<CCtrlBaseButton
*>(ft
.getCtrl("invite"));
833 newFriendBut
->setFrozen(PeopleInterraction
.isContactInList(name
, 0));
837 ignoreBut
->setFrozen(PeopleInterraction
.isContactInList(name
, 1));
843 R2::CEditor::TMode mode
= R2::getEditor().getMode();
844 if (mode
!= R2::CEditor::NotInitialized
)
846 isDM
= R2::getEditor().getDMC().getEditionModule().isSessionOwner()
847 && uint32(R2::CEditor::AnimationModeLoading
) <= uint32(mode
)
848 && uint32(mode
) <= uint32(R2::CEditor::AnimationModeGoingToPlay
);
851 inviteBut
->setActive(isDM
);
854 inviteBut
->setFrozen(false); // TODO Boris : true if player is already invited in anim + do
855 // PeopleInterraction.updateAllFreeTellerHeaders() when list is updated
860 //=================================================================================
861 void CChatGroupWindow::setActiveFreeTeller(const string
&winName
, bool bActive
)
863 CGroupContainer
*pGC
= createFreeTeller(winName
);
865 pGC
->setActive(bActive
);
868 //=================================================================================
869 string
CChatGroupWindow::getFreeTellerName(const std::string
&containerID
)
872 for (i
= 0; i
< _FreeTellers
.size(); ++i
)
874 CGroupContainer
*pGC
= _FreeTellers
[i
];
875 if (pGC
->getId() == containerID
)
878 if (i
== _FreeTellers
.size())
880 return _FreeTellers
[i
]->getTitle();
883 //=================================================================================
884 bool CChatGroupWindow::removeFreeTeller(const std::string
&containerID
)
887 for (i
= 0; i
< _FreeTellers
.size(); ++i
)
889 CGroupContainer
*pGC
= _FreeTellers
[i
];
890 if (pGC
->getId() == containerID
)
893 if (i
== _FreeTellers
.size())
895 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
896 pIM
->removeGroupContainerImageFromDesktops(_FreeTellers
[i
]->getId());
898 CInterfaceGroup
*pRoot
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface"));
899 CWidgetManager::getInstance()->unMakeWindow(_FreeTellers
[i
]);
900 pRoot
->delGroup (_FreeTellers
[i
]);
901 _FreeTellers
[i
] = NULL
;
902 _FreeTellers
.erase(_FreeTellers
.begin()+i
);
906 //=================================================================================
907 void CChatGroupWindow::removeAllFreeTellers()
909 while (!_FreeTellers
.empty())
913 removeFreeTeller(_FreeTellers
[0]->getId());
917 _FreeTellers
.erase(_FreeTellers
.begin());
922 //=================================================================================
923 void CChatGroupWindow::saveFreeTeller(NLMISC::IStream
&f
)
927 // Save the free teller only if it is present in the friend list to avoid the only-growing situation
928 // because free tellers are never deleted in game if we save/load all the free tellers, we just create more
929 // and more container.
931 uint32 i
, nNbFreeTellerSaved
= 0;
932 for (i
= 0; i
< _FreeTellers
.size(); ++i
)
933 if (PeopleInterraction
.FriendList
.getIndexFromName(_FreeTellers
[i
]->getTitle()) != -1)
934 nNbFreeTellerSaved
++;
936 f
.serial(nNbFreeTellerSaved
);
938 for (i
= 0; i
< _FreeTellers
.size(); ++i
)
940 CGroupContainer
*pGC
= _FreeTellers
[i
];
942 if (PeopleInterraction
.FriendList
.getIndexFromName(pGC
->getTitle()) != -1)
944 string sTitle
= pGC
->getTitle();
950 //=================================================================================
951 void CChatGroupWindow::loadFreeTeller(NLMISC::IStream
&f
)
953 sint ver
= f
.serialVersion(3);
957 // Old serialized FreeTellIdCounter (deprecated with v2).
962 uint32 i
, nNbFreeTellerSaved
= 0;
963 f
.serial(nNbFreeTellerSaved
);
965 for (i
= 0; i
< nNbFreeTellerSaved
; ++i
)
969 // Old serialized sID (deprecated with v2).
976 ucstring sTitle
; // Old UTF-16 serial
978 title
= sTitle
.toUtf8();
981 CGroupContainer
*pGC
= createFreeTeller(title
, "");
983 // With version 1 all tells are active because windows information have "title based" ids and no "sID based".
984 if ((ver
== 1) && (pGC
!= NULL
))
985 pGC
->setActive(false);
989 //=================================================================================
990 void CChatGroupWindow::clearMessages(CChatGroup::TGroupType gt
, uint32 dynamicChatDbIndex
)
992 // if not correctly init, abort
996 // get the gl and tab according to filter
999 getAssociatedSubWindow(gt
, dynamicChatDbIndex
, gl
, tab
);
1001 // delete all text lines
1004 gl
->deleteAllChildren();
1008 //=================================================================================
1009 void CChatGroupWindow::getAssociatedSubWindow(CChatGroup::TGroupType gt
, uint32 dynamicChatDbIndex
, CGroupList
*&gl
, CCtrlTabButton
*&tab
)
1018 case CChatGroup::say
:
1019 gl
= dynamic_cast<CGroupList
*>(_Chat
->getGroup("content:cb:around:text_list"));
1020 tab
= dynamic_cast<CCtrlTabButton
*>(_Chat
->getCtrl("header_opened:channel_select:tab0"));
1022 case CChatGroup::team
:
1023 gl
= dynamic_cast<CGroupList
*>(_Chat
->getGroup("content:cb:team:text_list"));
1024 tab
= dynamic_cast<CCtrlTabButton
*>(_Chat
->getCtrl("header_opened:channel_select:tab2"));
1026 case CChatGroup::guild
:
1027 gl
= dynamic_cast<CGroupList
*>(_Chat
->getGroup("content:cb:guild:text_list"));
1028 tab
= dynamic_cast<CCtrlTabButton
*>(_Chat
->getCtrl("header_opened:channel_select:tab3"));
1030 case CChatGroup::system
:
1031 gl
= dynamic_cast<CGroupList
*>(_Chat
->getGroup("content:cb:sysinfo:text_list"));
1032 tab
= dynamic_cast<CCtrlTabButton
*>(_Chat
->getCtrl("header_opened:channel_select:tab4"));
1034 case CChatGroup::region
:
1035 gl
= dynamic_cast<CGroupList
*>(_Chat
->getGroup("content:cb:region:text_list"));
1036 tab
= dynamic_cast<CCtrlTabButton
*>(_Chat
->getCtrl("header_opened:channel_select:tab1"));
1038 case CChatGroup::dyn_chat
:
1040 // use dynamicChatDbIndex to get the wanted tab button/group
1041 gl
= dynamic_cast<CGroupList
*>(_Chat
->getGroup(toString("content:cb:dyn_chat%d:text_list", dynamicChatDbIndex
)));
1042 tab
= dynamic_cast<CCtrlTabButton
*>(_Chat
->getCtrl(toString("header_opened:channel_select:tab_array0_%d",dynamicChatDbIndex
)));
1045 case CChatGroup::universe
:
1046 gl
= dynamic_cast<CGroupList
*>(_Chat
->getGroup("content:cb:universe:text_list"));
1047 tab
= dynamic_cast<CCtrlTabButton
*>(_Chat
->getCtrl("header_opened:channel_select:tab6"));
1053 ////////////////////////
1054 // CChatWindowManager //
1055 ////////////////////////
1057 //=================================================================================
1058 CChatWindowManager::CChatWindowManager() : _WindowID(0)
1062 //=================================================================================
1063 CChatWindowManager::~CChatWindowManager()
1065 for(TChatWindowMap::iterator it
= _ChatWindowMap
.begin(); it
!= _ChatWindowMap
.end(); ++it
)
1071 //=================================================================================
1072 CChatWindow
*CChatWindowManager::createChatWindow(const CChatWindowDesc
&desc
)
1074 if (getChatWindow(desc
.Title
))
1076 return NULL
; // duplicate name encountered
1079 w
= new CChatWindow
;
1081 if (desc
.Id
.empty())
1082 zeId
= NLMISC::toString("chat_window_id_%d", (int) _WindowID
);
1086 if (w
->create(desc
, zeId
))
1088 if (desc
.Id
.empty())
1091 _ChatWindowMap
[desc
.Title
] = w
;
1093 w
->setAHOnActive(desc
.AHOnActive
);
1094 w
->setAHOnActiveParams(desc
.AHOnActiveParams
);
1095 w
->setAHOnDeactive(desc
.AHOnDeactive
);
1096 w
->setAHOnDeactiveParams(desc
.AHOnDeactiveParams
);
1097 w
->setAHOnCloseButton(desc
.AHOnCloseButton
);
1098 w
->setAHOnCloseButtonParams(desc
.AHOnCloseButtonParams
);
1099 if (!desc
.HeaderColor
.empty())
1100 w
->setHeaderColor(desc
.HeaderColor
);
1110 //=================================================================================
1111 CChatWindow
*CChatWindowManager::createChatGroupWindow(const CChatWindowDesc
&desc
)
1113 if (getChatWindow(desc
.Title
))
1115 return NULL
; // duplicate name encountered
1117 CChatGroupWindow
*w
;
1118 w
= new CChatGroupWindow
;
1120 if (desc
.Id
.empty())
1121 zeId
= NLMISC::toString("chat_window_id_%d", (int) _WindowID
);
1125 if (w
->create(desc
, zeId
))
1127 if (desc
.Id
.empty())
1130 _ChatWindowMap
[desc
.Title
] = w
;
1132 w
->setAHOnActive(desc
.AHOnActive
);
1133 w
->setAHOnActiveParams(desc
.AHOnActiveParams
);
1134 w
->setAHOnDeactive(desc
.AHOnDeactive
);
1135 w
->setAHOnDeactiveParams(desc
.AHOnDeactiveParams
);
1136 w
->setAHOnCloseButton(desc
.AHOnCloseButton
);
1137 w
->setAHOnCloseButtonParams(desc
.AHOnCloseButtonParams
);
1138 if (!desc
.HeaderColor
.empty())
1139 w
->setHeaderColor(desc
.HeaderColor
);
1142 // because root group was created from template, element from scrollbar target attribute was not created yet
1143 CInterfaceGroup
*pIG
= w
->getContainer()->getGroup("header_opened:channel_select");
1146 CCtrlScroll
*sb
= dynamic_cast<CCtrlScroll
*>(w
->getContainer()->getCtrl("channel_scroll"));
1147 if (sb
) sb
->setTarget(pIG
);
1158 //=================================================================================
1159 CChatWindow
*CChatWindowManager::getChatWindow(const string
&title
)
1161 TChatWindowMap::iterator it
= _ChatWindowMap
.find(title
);
1162 if (it
== _ChatWindowMap
.end())
1166 nlassert(it
->second
!= NULL
);
1171 //=================================================================================
1172 void CChatWindowManager::removeChatWindow(const string
&title
)
1174 TChatWindowMap::iterator it
= _ChatWindowMap
.find(title
);
1175 if (it
== _ChatWindowMap
.end())
1177 nlwarning("Unknown chat window '%s'", title
.c_str());
1180 it
->second
->deleteContainer();
1182 _ChatWindowMap
.erase(it
);
1185 //=================================================================================
1186 CChatWindowManager
&CChatWindowManager::getInstance()
1188 static CChatWindowManager instance
;
1192 //=================================================================================
1193 CChatWindow
*CChatWindowManager::getChatWindowFromCaller(CCtrlBase
*caller
)
1195 // retrieve pointer on the CChatWindow instance associated with the ui
1196 // find first enclosing group container
1197 CGroupContainer
*father
= NULL
;
1200 father
= dynamic_cast<CGroupContainer
*>(caller
);
1202 caller
= caller
->getParent();
1204 if (!father
) return NULL
;
1206 return getChatWindow(father
->getTitle());
1209 //=================================================================================
1210 bool CChatWindowManager::rename(const string
&oldName
, const string
&newName
, bool newNameLocalize
)
1212 // if (oldName == newName) return true;
1213 CChatWindow
*newWin
= getChatWindow(newName
);
1214 if (newWin
!= NULL
) return false; // target window exists
1215 TChatWindowMap::iterator it
= _ChatWindowMap
.find(oldName
);
1216 if (it
== _ChatWindowMap
.end()) return false;
1217 _ChatWindowMap
[newName
] = it
->second
;
1218 it
->second
->getContainer()->setLocalize(newNameLocalize
);
1219 it
->second
->getContainer()->setTitle(newName
);
1220 _ChatWindowMap
.erase(it
);
1224 //=================================================================================
1225 CGroupEditBox
*CChatWindow::getEditBox() const
1227 if (!_Chat
) return NULL
;
1228 return dynamic_cast<CGroupEditBox
*>(_Chat
->getGroup("eb"));
1231 //=================================================================================
1232 void CChatWindowManager::removeChatWindow(CChatWindow
*cw
)
1235 removeChatWindow(cw
->getTitle());
1238 //=================================================================================
1239 CChatWindow
*CChatWindowManager::getChatWindowByIndex(uint index
)
1241 TChatWindowMap::iterator it
= _ChatWindowMap
.begin();
1242 while (index
--) { ++it
; }
1246 /////////////////////
1247 // ACTION HANDLERS //
1248 /////////////////////
1251 // ***************************************************************************************
1252 class CHandlerChatBoxEntry
: public IActionHandler
1255 void execute (CCtrlBase
*pCaller
, const std::string
&/* sParams */)
1257 CGroupEditBox
*pEB
= dynamic_cast<CGroupEditBox
*>(pCaller
);
1258 if (pEB
== NULL
) return;
1259 string text
= pEB
->getInputString();
1260 // If the line is empty, do nothing
1265 CChatWindow
*chat
= getChatWndMgr().getChatWindowFromCaller(pCaller
);
1268 nlwarning("No chat box associated with %s", pEB
->getId().c_str());
1272 // Parse any tokens in the text
1273 if ( ! CInterfaceManager::parseTokens(text
))
1275 pEB
->setInputString(std::string());
1279 // if, it s a command, execute it and don't send the command to the server
1282 CChatWindow::_ChatWindowLaunchingCommand
= chat
;
1284 string cmdWithArgs
= str
.substr(1);
1286 // Get the command name from the string, can contain spaces
1287 string cmd
= cmdWithArgs
.substr(0, cmdWithArgs
.find(' '));
1288 if (cmdWithArgs
.find('"') == 0)
1290 string::size_type pos
= cmdWithArgs
.find('"', 1);
1291 if (string::npos
!= pos
)
1293 cmd
= cmdWithArgs
.substr(1, pos
- 1);
1297 if ( NLMISC::ICommand::exists( cmd
) )
1299 NLMISC::ICommand::execute( cmdWithArgs
, g_log
);
1303 CInterfaceManager
*im
= CInterfaceManager::getInstance();
1304 im
->displaySystemInfo (cmd
+ ": " + CI18N::get ("uiCommandNotExists"));
1309 if (chat
->getListener())
1311 chat
->getListener()->msgEntered(text
, chat
);
1314 // Clear input string
1315 pEB
->setInputString (std::string());
1316 CGroupContainer
*gc
= static_cast< CGroupContainer
* >( pEB
->getEnclosingContainer() );
1320 // Restore position of enclosing container if it hasn't been moved/scaled/poped by the user
1321 if (!gc
->getTouchFlag(true))
1323 gc
->restorePosition();
1328 REGISTER_ACTION_HANDLER(CHandlerChatBoxEntry
, "chat_box_entry");
1332 static string
getFreeTellerName(CInterfaceElement
*pCaller
)
1334 if (!pCaller
) return string();
1335 CChatGroupWindow
*cgw
= PeopleInterraction
.getChatGroupWindow();
1336 if (!cgw
) return string();
1337 CInterfaceGroup
*freeTeller
= pCaller
->getParentContainer();
1338 if (!freeTeller
) return string();
1339 return cgw
->getFreeTellerName( freeTeller
->getId() );
1342 // ***************************************************************************************
1343 class CHandlerAddTellerToFriendList
: public IActionHandler
1346 void execute (CCtrlBase
*pCaller
, const std::string
&/* sParams */)
1348 string playerName
= ::getFreeTellerName(pCaller
);
1349 if (!playerName
.empty())
1351 sint playerIndex
= PeopleInterraction
.IgnoreList
.getIndexFromName(playerName
);
1352 // if already in friend list, ask to move rather than add
1353 if (playerIndex
!= -1)
1355 PeopleInterraction
.askMoveContact(playerIndex
, &PeopleInterraction
.IgnoreList
, &PeopleInterraction
.FriendList
);
1359 PeopleInterraction
.askAddContact(playerName
, &PeopleInterraction
.FriendList
);
1364 REGISTER_ACTION_HANDLER(CHandlerAddTellerToFriendList
, "add_teller_to_friend_list");
1367 // ***************************************************************************************
1368 class CHandlerAddTellerToIgnoreList
: public IActionHandler
1371 void execute (CCtrlBase
*pCaller
, const std::string
&sParams
)
1373 CInterfaceManager
*im
= CInterfaceManager::getInstance();
1374 std::string callerId
= getParam(sParams
, "id");
1375 CInterfaceElement
*prevCaller
= CWidgetManager::getInstance()->getElementFromId(callerId
);
1376 string playerName
= ::getFreeTellerName(prevCaller
);
1377 if (!playerName
.empty())
1379 // if already in friend list, ask to move rather than add
1380 sint playerIndex
= PeopleInterraction
.FriendList
.getIndexFromName(playerName
);
1381 if (playerIndex
!= -1)
1383 PeopleInterraction
.askMoveContact(playerIndex
, &PeopleInterraction
.FriendList
, &PeopleInterraction
.IgnoreList
);
1387 PeopleInterraction
.askAddContact(playerName
, &PeopleInterraction
.IgnoreList
);
1391 CInterfaceGroup
*win
= prevCaller
->getParentContainer();
1394 static_cast< CGroupContainer
* >( win
)->setActive(false);
1400 REGISTER_ACTION_HANDLER(CHandlerAddTellerToIgnoreList
, "add_teller_to_ignore_list");
1402 // ***************************************************************************************
1403 class CHandlerInviteToRingSession
: public IActionHandler
1406 void execute (CCtrlBase
*pCaller
, const std::string
&/* sParams */)
1408 string playerName
= ::getFreeTellerName(pCaller
);
1409 if (!playerName
.empty())
1411 // ask the SBS to invite the character in the session
1412 CSessionBrowserImpl::getInstance().inviteCharacterByName(CSessionBrowserImpl::getInstance().getCharId(), playerName
);
1413 // additionaly, send a tell to signal the player he has been invited to a ring session
1414 ChatMngr
.tell(playerName
, CI18N::get("uiRingInviteNotification"));
1416 CInterfaceManager
*im
= CInterfaceManager::getInstance();
1417 im
->displaySystemInfo("@{6F6F}" + playerName
+" @{FFFF}" + CI18N::get("uiRingInvitationSent"), "BC");
1418 // force a refresh of the ui
1419 CLuaManager::getInstance().executeLuaScript("CharTracking:forceRefresh()");
1423 REGISTER_ACTION_HANDLER(CHandlerInviteToRingSession
, "invite_to_ring_session");