llchathistory.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:25k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llchathistory.cpp
  3.  * @brief LLTextEditor base class
  4.  *
  5.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2001-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llinstantmessage.h"
  34. #include "llimview.h"
  35. #include "llchathistory.h"
  36. #include "llcommandhandler.h"
  37. #include "llpanel.h"
  38. #include "lluictrlfactory.h"
  39. #include "llscrollcontainer.h"
  40. #include "llavatariconctrl.h"
  41. #include "llcallingcard.h" //for LLAvatarTracker
  42. #include "llagentdata.h"
  43. #include "llavataractions.h"
  44. #include "lltrans.h"
  45. #include "llfloaterreg.h"
  46. #include "llmutelist.h"
  47. #include "llstylemap.h"
  48. #include "llslurl.h"
  49. #include "lllayoutstack.h"
  50. #include "llagent.h"
  51. #include "llnotificationsutil.h"
  52. #include "lltoastnotifypanel.h"
  53. #include "lltooltip.h"
  54. #include "llviewerregion.h"
  55. #include "llviewertexteditor.h"
  56. #include "llworld.h"
  57. #include "lluiconstants.h"
  58. #include "llsidetray.h"//for blocked objects panel
  59. static LLDefaultChildRegistry::Register<LLChatHistory> r("chat_history");
  60. const static std::string NEW_LINE(rawstr_to_utf8("n"));
  61. const static U32 LENGTH_OF_TIME_STR = std::string("12:00").length();
  62. const static std::string SLURL_APP_AGENT = "secondlife:///app/agent/";
  63. const static std::string SLURL_ABOUT = "/about";
  64. // support for secondlife:///app/objectim/{UUID}/ SLapps
  65. class LLObjectIMHandler : public LLCommandHandler
  66. {
  67. public:
  68. // requests will be throttled from a non-trusted browser
  69. LLObjectIMHandler() : LLCommandHandler("objectim", UNTRUSTED_THROTTLE) {}
  70. bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
  71. {
  72. if (params.size() < 1)
  73. {
  74. return false;
  75. }
  76. LLUUID object_id;
  77. if (!object_id.set(params[0], FALSE))
  78. {
  79. return false;
  80. }
  81. LLSD payload;
  82. payload["object_id"] = object_id;
  83. payload["owner_id"] = query_map["owner"];
  84. payload["name"] = query_map["name"];
  85. payload["slurl"] = query_map["slurl"];
  86. payload["group_owned"] = query_map["groupowned"];
  87. LLFloaterReg::showInstance("inspect_remote_object", payload);
  88. return true;
  89. }
  90. };
  91. LLObjectIMHandler gObjectIMHandler;
  92. class LLChatHistoryHeader: public LLPanel
  93. {
  94. public:
  95. static LLChatHistoryHeader* createInstance(const std::string& file_name)
  96. {
  97. LLChatHistoryHeader* pInstance = new LLChatHistoryHeader;
  98. LLUICtrlFactory::getInstance()->buildPanel(pInstance, file_name);
  99. return pInstance;
  100. }
  101. BOOL handleMouseUp(S32 x, S32 y, MASK mask)
  102. {
  103. return LLPanel::handleMouseUp(x,y,mask);
  104. }
  105. //*TODO remake it using mouse enter/leave and static LLHandle<LLIconCtrl> to add/remove as a child
  106. BOOL handleToolTip(S32 x, S32 y, MASK mask)
  107. {
  108. LLTextBase* name = getChild<LLTextBase>("user_name");
  109. if (name && name->parentPointInView(x, y) && mAvatarID.notNull() && mFrom.size() && SYSTEM_FROM != mFrom)
  110. {
  111. // Spawn at right side of the name textbox.
  112. LLRect sticky_rect = name->calcScreenRect();
  113. S32 icon_x = llmin(sticky_rect.mLeft + name->getTextBoundingRect().getWidth() + 7, sticky_rect.mRight - 3);
  114. LLToolTip::Params params;
  115. params.background_visible(false);
  116. params.click_callback(boost::bind(&LLChatHistoryHeader::onHeaderPanelClick, this, 0, 0, 0));
  117. params.delay_time(0.0f); // spawn instantly on hover
  118. params.image(LLUI::getUIImage("Info_Small"));
  119. params.message("");
  120. params.padding(0);
  121. params.pos(LLCoordGL(icon_x, sticky_rect.mTop - 2));
  122. params.sticky_rect(sticky_rect);
  123. LLToolTipMgr::getInstance()->show(params);
  124. return TRUE;
  125. }
  126. return LLPanel::handleToolTip(x, y, mask);
  127. }
  128. void onObjectIconContextMenuItemClicked(const LLSD& userdata)
  129. {
  130. std::string level = userdata.asString();
  131. if (level == "profile")
  132. {
  133. LLSD params;
  134. params["object_id"] = getAvatarId();
  135. LLFloaterReg::showInstance("inspect_object", params);
  136. }
  137. else if (level == "block")
  138. {
  139. LLMuteList::getInstance()->add(LLMute(getAvatarId(), mFrom, LLMute::OBJECT));
  140. LLSideTray::getInstance()->showPanel("panel_block_list_sidetray", LLSD().with("blocked_to_select", getAvatarId()));
  141. }
  142. }
  143. void onAvatarIconContextMenuItemClicked(const LLSD& userdata)
  144. {
  145. std::string level = userdata.asString();
  146. if (level == "profile")
  147. {
  148. LLAvatarActions::showProfile(getAvatarId());
  149. }
  150. else if (level == "im")
  151. {
  152. LLAvatarActions::startIM(getAvatarId());
  153. }
  154. else if (level == "add")
  155. {
  156. LLAvatarActions::requestFriendshipDialog(getAvatarId(), mFrom);
  157. }
  158. else if (level == "remove")
  159. {
  160. LLAvatarActions::removeFriendDialog(getAvatarId());
  161. }
  162. }
  163. BOOL postBuild()
  164. {
  165. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  166. registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2));
  167. registrar.add("ObjectIcon.Action", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemClicked, this, _2));
  168. LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_avatar_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  169. mPopupMenuHandleAvatar = menu->getHandle();
  170. menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_object_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  171. mPopupMenuHandleObject = menu->getHandle();
  172. setDoubleClickCallback(boost::bind(&LLChatHistoryHeader::onHeaderPanelClick, this, _2, _3, _4));
  173. return LLPanel::postBuild();
  174. }
  175. bool pointInChild(const std::string& name,S32 x,S32 y)
  176. {
  177. LLUICtrl* child = findChild<LLUICtrl>(name);
  178. if(!child)
  179. return false;
  180. LLView* parent = child->getParent();
  181. if(parent!=this)
  182. {
  183. x-=parent->getRect().mLeft;
  184. y-=parent->getRect().mBottom;
  185. }
  186. S32 local_x = x - child->getRect().mLeft ;
  187. S32 local_y = y - child->getRect().mBottom ;
  188. return  child->pointInView(local_x, local_y);
  189. }
  190. BOOL handleRightMouseDown(S32 x, S32 y, MASK mask)
  191. {
  192. if(pointInChild("avatar_icon",x,y) || pointInChild("user_name",x,y))
  193. {
  194. showContextMenu(x,y);
  195. return TRUE;
  196. }
  197. return LLPanel::handleRightMouseDown(x,y,mask);
  198. }
  199. void onHeaderPanelClick(S32 x, S32 y, MASK mask)
  200. {
  201. if (mSourceType == CHAT_SOURCE_OBJECT)
  202. {
  203. LLFloaterReg::showInstance("inspect_object", LLSD().with("object_id", mAvatarID));
  204. }
  205. else if (mSourceType == CHAT_SOURCE_AGENT)
  206. {
  207. LLFloaterReg::showInstance("inspect_avatar", LLSD().with("avatar_id", mAvatarID));
  208. }
  209. //if chat source is system, you may add "else" here to define behaviour.
  210. }
  211. const LLUUID& getAvatarId () const { return mAvatarID;}
  212. void setup(const LLChat& chat,const LLStyle::Params& style_params) 
  213. {
  214. mAvatarID = chat.mFromID;
  215. mSessionID = chat.mSessionID;
  216. mSourceType = chat.mSourceType;
  217. gCacheName->get(mAvatarID, FALSE, boost::bind(&LLChatHistoryHeader::nameUpdatedCallback, this, _1, _2, _3, _4));
  218. //*TODO overly defensive thing, source type should be maintained out there
  219. if((chat.mFromID.isNull() && chat.mFromName.empty()) || chat.mFromName == SYSTEM_FROM)
  220. {
  221. mSourceType = CHAT_SOURCE_SYSTEM;
  222. }
  223. LLTextBox* userName = getChild<LLTextBox>("user_name");
  224. userName->setReadOnlyColor(style_params.readonly_color());
  225. userName->setColor(style_params.color());
  226. userName->setValue(chat.mFromName);
  227. mFrom = chat.mFromName;
  228. if (chat.mFromName.empty() || CHAT_SOURCE_SYSTEM == mSourceType)
  229. {
  230. mFrom = LLTrans::getString("SECOND_LIFE");
  231. userName->setValue(mFrom);
  232. }
  233. mMinUserNameWidth = style_params.font()->getWidth(userName->getWText().c_str()) + PADDING;
  234. setTimeField(chat);
  235. LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon");
  236. if(mSourceType != CHAT_SOURCE_AGENT)
  237. icon->setDrawTooltip(false);
  238. switch (mSourceType)
  239. {
  240. case CHAT_SOURCE_AGENT:
  241. icon->setValue(chat.mFromID);
  242. break;
  243. case CHAT_SOURCE_OBJECT:
  244. icon->setValue(LLSD("OBJECT_Icon"));
  245. break;
  246. case CHAT_SOURCE_SYSTEM:
  247. icon->setValue(LLSD("SL_Logo"));
  248. }
  249. }
  250. /*virtual*/ void draw()
  251. {
  252. LLTextBox* user_name = getChild<LLTextBox>("user_name");
  253. LLTextBox* time_box = getChild<LLTextBox>("time_box");
  254. LLRect user_name_rect = user_name->getRect();
  255. S32 user_name_width = user_name_rect.getWidth();
  256. S32 time_box_width = time_box->getRect().getWidth();
  257. if (time_box->getVisible() && user_name_width <= mMinUserNameWidth)
  258. {
  259. time_box->setVisible(FALSE);
  260. user_name_rect.mRight += time_box_width;
  261. user_name->reshape(user_name_rect.getWidth(), user_name_rect.getHeight());
  262. user_name->setRect(user_name_rect);
  263. }
  264. if (!time_box->getVisible() && user_name_width > mMinUserNameWidth + time_box_width)
  265. {
  266. user_name_rect.mRight -= time_box_width;
  267. user_name->reshape(user_name_rect.getWidth(), user_name_rect.getHeight());
  268. user_name->setRect(user_name_rect);
  269. time_box->setVisible(TRUE);
  270. }
  271. LLPanel::draw();
  272. }
  273. void nameUpdatedCallback(const LLUUID& id,const std::string& first,const std::string& last,BOOL is_group)
  274. {
  275. if (id != mAvatarID)
  276. return;
  277. mFrom = first + " " + last;
  278. }
  279. protected:
  280. static const S32 PADDING = 20;
  281. void showContextMenu(S32 x,S32 y)
  282. {
  283. if(mSourceType == CHAT_SOURCE_SYSTEM)
  284. showSystemContextMenu(x,y);
  285. if(mSourceType == CHAT_SOURCE_AGENT)
  286. showAvatarContextMenu(x,y);
  287. if(mSourceType == CHAT_SOURCE_OBJECT && SYSTEM_FROM != mFrom)
  288. showObjectContextMenu(x,y);
  289. }
  290. void showSystemContextMenu(S32 x,S32 y)
  291. {
  292. }
  293. void showObjectContextMenu(S32 x,S32 y)
  294. {
  295. LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleObject.get();
  296. if(menu)
  297. LLMenuGL::showPopup(this, menu, x, y);
  298. }
  299. void showAvatarContextMenu(S32 x,S32 y)
  300. {
  301. LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleAvatar.get();
  302. if(menu)
  303. {
  304. bool is_friend = LLAvatarTracker::instance().getBuddyInfo(mAvatarID) != NULL;
  305. menu->setItemEnabled("Add Friend", !is_friend);
  306. menu->setItemEnabled("Remove Friend", is_friend);
  307. if(gAgentID == mAvatarID)
  308. {
  309. menu->setItemEnabled("Add Friend", false);
  310. menu->setItemEnabled("Send IM", false);
  311. menu->setItemEnabled("Remove Friend", false);
  312. }
  313. if (mSessionID == LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, mAvatarID))
  314. {
  315. menu->setItemVisible("Send IM", false);
  316. }
  317. menu->buildDrawLabels();
  318. menu->updateParent(LLMenuGL::sMenuContainer);
  319. LLMenuGL::showPopup(this, menu, x, y);
  320. }
  321. }
  322. private:
  323. void setTimeField(const LLChat& chat)
  324. {
  325. LLTextBox* time_box = getChild<LLTextBox>("time_box");
  326. LLRect rect_before = time_box->getRect();
  327. time_box->setValue(chat.mTimeStr);
  328. // set necessary textbox width to fit all text
  329. time_box->reshapeToFitText();
  330. LLRect rect_after = time_box->getRect();
  331. // move rect to the left to correct position...
  332. S32 delta_pos_x = rect_before.getWidth() - rect_after.getWidth();
  333. S32 delta_pos_y = rect_before.getHeight() - rect_after.getHeight();
  334. time_box->translate(delta_pos_x, delta_pos_y);
  335. //... & change width of the name control
  336. LLView* user_name = getChild<LLView>("user_name");
  337. const LLRect& user_rect = user_name->getRect();
  338. user_name->reshape(user_rect.getWidth() + delta_pos_x, user_rect.getHeight());
  339. }
  340. protected:
  341. LLHandle<LLView> mPopupMenuHandleAvatar;
  342. LLHandle<LLView> mPopupMenuHandleObject;
  343. LLUUID     mAvatarID;
  344. EChatSourceType mSourceType;
  345. std::string mFrom;
  346. LLUUID mSessionID;
  347. S32 mMinUserNameWidth;
  348. };
  349. LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)
  350. : LLUICtrl(p),
  351. mMessageHeaderFilename(p.message_header),
  352. mMessageSeparatorFilename(p.message_separator),
  353. mLeftTextPad(p.left_text_pad),
  354. mRightTextPad(p.right_text_pad),
  355. mLeftWidgetPad(p.left_widget_pad),
  356. mRightWidgetPad(p.right_widget_pad),
  357. mTopSeparatorPad(p.top_separator_pad),
  358. mBottomSeparatorPad(p.bottom_separator_pad),
  359. mTopHeaderPad(p.top_header_pad),
  360. mBottomHeaderPad(p.bottom_header_pad)
  361. {
  362. LLTextEditor::Params editor_params(p);
  363. editor_params.rect = getLocalRect();
  364. editor_params.follows.flags = FOLLOWS_ALL;
  365. editor_params.enabled = false; // read only
  366. editor_params.show_context_menu = "true";
  367. mEditor = LLUICtrlFactory::create<LLTextEditor>(editor_params, this);
  368. }
  369. LLChatHistory::~LLChatHistory()
  370. {
  371. this->clear();
  372. }
  373. void LLChatHistory::initFromParams(const LLChatHistory::Params& p)
  374. {
  375. static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
  376. LLRect stack_rect = getLocalRect();
  377. stack_rect.mRight -= scrollbar_size;
  378. LLLayoutStack::Params layout_p;
  379. layout_p.rect = stack_rect;
  380. layout_p.follows.flags = FOLLOWS_ALL;
  381. layout_p.orientation = "vertical";
  382. layout_p.mouse_opaque = false;
  383. LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p, this);
  384. const S32 NEW_TEXT_NOTICE_HEIGHT = 20;
  385. LLPanel::Params panel_p;
  386. panel_p.name = "spacer";
  387. panel_p.background_visible = false;
  388. panel_p.has_border = false;
  389. panel_p.mouse_opaque = false;
  390. stackp->addPanel(LLUICtrlFactory::create<LLPanel>(panel_p), 0, 30, true, false, LLLayoutStack::ANIMATE);
  391. panel_p.name = "new_text_notice_holder";
  392. LLRect new_text_notice_rect = getLocalRect();
  393. new_text_notice_rect.mTop = new_text_notice_rect.mBottom + NEW_TEXT_NOTICE_HEIGHT;
  394. panel_p.rect = new_text_notice_rect;
  395. panel_p.background_opaque = true;
  396. panel_p.background_visible = true;
  397. panel_p.visible = false;
  398. mMoreChatPanel = LLUICtrlFactory::create<LLPanel>(panel_p);
  399. LLTextBox::Params text_p(p.more_chat_text);
  400. text_p.rect = mMoreChatPanel->getLocalRect();
  401. text_p.follows.flags = FOLLOWS_ALL;
  402. text_p.name = "more_chat_text";
  403. mMoreChatText = LLUICtrlFactory::create<LLTextBox>(text_p, mMoreChatPanel);
  404. mMoreChatText->setClickedCallback(boost::bind(&LLChatHistory::onClickMoreText, this));
  405. stackp->addPanel(mMoreChatPanel, 0, 0, false, false, LLLayoutStack::ANIMATE);
  406. }
  407. /*void LLChatHistory::updateTextRect()
  408. {
  409. static LLUICachedControl<S32> texteditor_border ("UITextEditorBorder", 0);
  410. LLRect old_text_rect = mVisibleTextRect;
  411. mVisibleTextRect = mScroller->getContentWindowRect();
  412. mVisibleTextRect.stretch(-texteditor_border);
  413. mVisibleTextRect.mLeft += mLeftTextPad;
  414. mVisibleTextRect.mRight -= mRightTextPad;
  415. if (mVisibleTextRect != old_text_rect)
  416. {
  417. needsReflow();
  418. }
  419. }*/
  420. LLView* LLChatHistory::getSeparator()
  421. {
  422. LLPanel* separator = LLUICtrlFactory::getInstance()->createFromFile<LLPanel>(mMessageSeparatorFilename, NULL, LLPanel::child_registry_t::instance());
  423. return separator;
  424. }
  425. LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params)
  426. {
  427. LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename);
  428. header->setup(chat,style_params);
  429. return header;
  430. }
  431. void LLChatHistory::onClickMoreText()
  432. {
  433. mEditor->endOfDoc();
  434. }
  435. void LLChatHistory::clear()
  436. {
  437. mLastFromName.clear();
  438. mEditor->clear();
  439. mLastFromID = LLUUID::null;
  440. }
  441. void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LLStyle::Params& input_append_params)
  442. {
  443. bool use_plain_text_chat_history = args["use_plain_text_chat_history"].asBoolean();
  444. if (!mEditor->scrolledToEnd() && chat.mFromID != gAgent.getID() && !chat.mFromName.empty())
  445. {
  446. mUnreadChatSources.insert(chat.mFromName);
  447. mMoreChatPanel->setVisible(TRUE);
  448. std::string chatters;
  449. for (unread_chat_source_t::iterator it = mUnreadChatSources.begin();
  450. it != mUnreadChatSources.end();)
  451. {
  452. chatters += *it;
  453. if (++it != mUnreadChatSources.end())
  454. {
  455. chatters += ", ";
  456. }
  457. }
  458. LLStringUtil::format_map_t args;
  459. args["SOURCES"] = chatters;
  460. if (mUnreadChatSources.size() == 1)
  461. {
  462. mMoreChatText->setValue(LLTrans::getString("unread_chat_single", args));
  463. }
  464. else
  465. {
  466. mMoreChatText->setValue(LLTrans::getString("unread_chat_multiple", args));
  467. }
  468. S32 height = mMoreChatText->getTextPixelHeight() + 5;
  469. mMoreChatPanel->reshape(mMoreChatPanel->getRect().getWidth(), height);
  470. }
  471. LLColor4 txt_color = LLUIColorTable::instance().getColor("White");
  472. LLViewerChat::getChatColor(chat,txt_color);
  473. LLFontGL* fontp = LLViewerChat::getChatFont();
  474. std::string font_name = LLFontGL::nameFromFont(fontp);
  475. std::string font_size = LLFontGL::sizeFromFont(fontp);
  476. LLStyle::Params style_params;
  477. style_params.color(txt_color);
  478. style_params.readonly_color(txt_color);
  479. style_params.font.name(font_name);
  480. style_params.font.size(font_size);
  481. style_params.font.style(input_append_params.font.style);
  482. std::string prefix = chat.mText.substr(0, 4);
  483. //IRC styled /me messages.
  484. bool irc_me = prefix == "/me " || prefix == "/me'";
  485. // Delimiter after a name in header copy/past and in plain text mode
  486. std::string delimiter = ": ";
  487. std::string shout = LLTrans::getString("shout");
  488. std::string whisper = LLTrans::getString("whisper");
  489. if (chat.mChatType == CHAT_TYPE_SHOUT || 
  490. chat.mChatType == CHAT_TYPE_WHISPER ||
  491. chat.mText.compare(0, shout.length(), shout) == 0 ||
  492. chat.mText.compare(0, whisper.length(), whisper) == 0)
  493. {
  494. delimiter = " ";
  495. }
  496. // Don't add any delimiter after name in irc styled messages
  497. if (irc_me || chat.mChatStyle == CHAT_STYLE_IRC)
  498. {
  499. delimiter = LLStringUtil::null;
  500. style_params.font.style = "ITALIC";
  501. }
  502. //*HACK we graying out chat history by graying out messages that contains full date in a time string
  503. bool message_from_log = chat.mTimeStr.length() > LENGTH_OF_TIME_STR; 
  504. if (message_from_log)
  505. {
  506. style_params.color(LLColor4::grey);
  507. style_params.readonly_color(LLColor4::grey);
  508. }
  509. if (use_plain_text_chat_history)
  510. {
  511. mEditor->appendText("[" + chat.mTimeStr + "] ", mEditor->getText().size() != 0, style_params);
  512. if (utf8str_trim(chat.mFromName).size() != 0)
  513. {
  514. // Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text.
  515. if ( chat.mSourceType == CHAT_SOURCE_OBJECT )
  516. {
  517. // for object IMs, create a secondlife:///app/objectim SLapp
  518. std::string url = LLSLURL::buildCommand("objectim", chat.mFromID, "");
  519. url += "?name=" + chat.mFromName;
  520. url += "&owner=" + args["owner_id"].asString();
  521. std::string slurl = args["slurl"].asString();
  522. if (slurl.empty())
  523. {
  524. LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
  525. if (region)
  526. {
  527. S32 x, y, z;
  528. LLSLURL::globalPosToXYZ(LLVector3d(chat.mPosAgent), x, y, z);
  529. slurl = region->getName() + llformat("/%d/%d/%d", x, y, z);
  530. }
  531. }
  532. url += "&slurl=" + slurl;
  533. // set the link for the object name to be the objectim SLapp
  534. // (don't let object names with hyperlinks override our objectim Url)
  535. LLStyle::Params link_params(style_params);
  536. link_params.color.control = "HTMLLinkColor";
  537. link_params.link_href = url;
  538. mEditor->appendText("<nolink>" + chat.mFromName + "</nolink>"  + delimiter,
  539. false, link_params);
  540. }
  541. else if ( chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log)
  542. {
  543. LLStyle::Params link_params(style_params);
  544. link_params.overwriteFrom(LLStyleMap::instance().lookupAgent(chat.mFromID));
  545. // Convert the name to a hotlink and add to message.
  546. mEditor->appendText(chat.mFromName + delimiter, false, link_params);
  547. }
  548. else
  549. {
  550. mEditor->appendText(chat.mFromName + delimiter, false, style_params);
  551. }
  552. }
  553. }
  554. else
  555. {
  556. LLView* view = NULL;
  557. LLInlineViewSegment::Params p;
  558. p.force_newline = true;
  559. p.left_pad = mLeftWidgetPad;
  560. p.right_pad = mRightWidgetPad;
  561. LLDate new_message_time = LLDate::now();
  562. if (mLastFromName == chat.mFromName 
  563. && mLastFromID == chat.mFromID
  564. && mLastMessageTime.notNull() 
  565. && (new_message_time.secondsSinceEpoch() - mLastMessageTime.secondsSinceEpoch()) < 60.0
  566. && mLastMessageTimeStr.size() == chat.mTimeStr.size())  //*HACK to distinguish between current and previous chat session's histories
  567. {
  568. view = getSeparator();
  569. p.top_pad = mTopSeparatorPad;
  570. p.bottom_pad = mBottomSeparatorPad;
  571. }
  572. else
  573. {
  574. view = getHeader(chat, style_params);
  575. if (mEditor->getText().size() == 0)
  576. p.top_pad = 0;
  577. else
  578. p.top_pad = mTopHeaderPad;
  579. p.bottom_pad = mBottomHeaderPad;
  580. }
  581. p.view = view;
  582. //Prepare the rect for the view
  583. LLRect target_rect = mEditor->getDocumentView()->getRect();
  584. // squeeze down the widget by subtracting padding off left and right
  585. target_rect.mLeft += mLeftWidgetPad + mEditor->getHPad();
  586. target_rect.mRight -= mRightWidgetPad;
  587. view->reshape(target_rect.getWidth(), view->getRect().getHeight());
  588. view->setOrigin(target_rect.mLeft, view->getRect().mBottom);
  589. std::string widget_associated_text = "n[" + chat.mTimeStr + "] ";
  590. if (utf8str_trim(chat.mFromName).size() != 0 && chat.mFromName != SYSTEM_FROM)
  591. widget_associated_text += chat.mFromName + delimiter;
  592. mEditor->appendWidget(p, widget_associated_text, false);
  593. mLastFromName = chat.mFromName;
  594. mLastFromID = chat.mFromID;
  595. mLastMessageTime = new_message_time;
  596. mLastMessageTimeStr = chat.mTimeStr;
  597. }
  598.    if (chat.mNotifId.notNull())
  599. {
  600. LLNotificationPtr notification = LLNotificationsUtil::find(chat.mNotifId);
  601. if (notification != NULL)
  602. {
  603. LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(
  604. notification);
  605. //we can't set follows in xml since it broke toasts behavior
  606. notify_box->setFollowsLeft();
  607. notify_box->setFollowsRight();
  608. notify_box->setFollowsTop();
  609. ctrl_list_t ctrls = notify_box->getControlPanel()->getCtrlList();
  610. S32 offset = 0;
  611. for (ctrl_list_t::iterator it = ctrls.begin(); it != ctrls.end(); it++)
  612. {
  613. LLButton * button = dynamic_cast<LLButton*> (*it);
  614. if (button != NULL)
  615. {
  616. button->setOrigin( offset,
  617. button->getRect().mBottom);
  618. button->setLeftHPad(2 * HPAD);
  619. button->setRightHPad(2 * HPAD);
  620. // set zero width before perform autoResize()
  621. button->setRect(LLRect(button->getRect().mLeft,
  622. button->getRect().mTop, button->getRect().mLeft,
  623. button->getRect().mBottom));
  624. button->setAutoResize(true);
  625. button->autoResize();
  626. offset += 2 * HPAD + button->getRect().getWidth();
  627. button->setFollowsNone();
  628. }
  629. }
  630. LLTextEditor* text_editor = notify_box->getChild<LLTextEditor>("text_editor_box", TRUE);
  631. S32 text_heigth = 0;
  632. if(text_editor != NULL)
  633. {
  634. text_heigth = text_editor->getTextBoundingRect().getHeight();
  635. }
  636. //Prepare the rect for the view
  637. LLRect target_rect = mEditor->getDocumentView()->getRect();
  638. // squeeze down the widget by subtracting padding off left and right
  639. target_rect.mLeft += mLeftWidgetPad + mEditor->getHPad();
  640. target_rect.mRight -= mRightWidgetPad;
  641. notify_box->reshape(target_rect.getWidth(),
  642. notify_box->getRect().getHeight());
  643. notify_box->setOrigin(target_rect.mLeft, notify_box->getRect().mBottom);
  644. if (text_editor != NULL)
  645. {
  646. S32 text_heigth_delta =
  647. text_editor->getTextBoundingRect().getHeight()
  648. - text_heigth;
  649. notify_box->reshape(target_rect.getWidth(),
  650. notify_box->getRect().getHeight() + text_heigth_delta);
  651. }
  652. LLInlineViewSegment::Params params;
  653. params.view = notify_box;
  654. params.left_pad = mLeftWidgetPad;
  655. params.right_pad = mRightWidgetPad;
  656. mEditor->appendWidget(params, "n", false);
  657. }
  658. }
  659. else
  660. {
  661. std::string message = irc_me ? chat.mText.substr(3) : chat.mText;
  662. //MESSAGE TEXT PROCESSING
  663. //*HACK getting rid of redundant sender names in system notifications sent using sender name (see EXT-5010)
  664. if (use_plain_text_chat_history && gAgentID != chat.mFromID && chat.mFromID.notNull())
  665. {
  666. std::string slurl_about = SLURL_APP_AGENT + chat.mFromID.asString() + SLURL_ABOUT;
  667. if (message.length() > slurl_about.length() && 
  668. message.compare(0, slurl_about.length(), slurl_about) == 0)
  669. {
  670. message = message.substr(slurl_about.length(), message.length()-1);
  671. }
  672. }
  673. if (irc_me && !use_plain_text_chat_history)
  674. {
  675. message = chat.mFromName + message;
  676. }
  677. mEditor->appendText(message, FALSE, style_params);
  678. }
  679. mEditor->blockUndo();
  680. // automatically scroll to end when receiving chat from myself
  681. if (chat.mFromID == gAgentID)
  682. {
  683. mEditor->setCursorAndScrollToEnd();
  684. }
  685. }
  686. void LLChatHistory::draw()
  687. {
  688. if (mEditor->scrolledToEnd())
  689. {
  690. mUnreadChatSources.clear();
  691. mMoreChatPanel->setVisible(FALSE);
  692. }
  693. LLUICtrl::draw();
  694. }
  695. void LLChatHistory::reshape(S32 width, S32 height, BOOL called_from_parent)
  696. {
  697. bool is_scrolled_to_end = mEditor->scrolledToEnd();
  698. LLUICtrl::reshape( width, height, called_from_parent );
  699. // update scroll
  700. if (is_scrolled_to_end)
  701. mEditor->setCursorAndScrollToEnd();
  702. }