/** * @file llchatitemscontainer.cpp * @brief chat history scrolling panel implementation * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llchatitemscontainerctrl.h" #include "llchatmsgbox.h" #include "lltextbox.h" #include "llavataractions.h" #include "llavatariconctrl.h" #include "llcommandhandler.h" #include "llfloaterreg.h" #include "lllocalcliprect.h" #include "lltrans.h" #include "llfloaterimnearbychat.h" #include "llviewercontrol.h" #include "llagentdata.h" #include "llslurl.h" static constexpr S32 msg_left_offset = 10; static constexpr S32 msg_right_offset = 10; static constexpr S32 msg_height_pad = 5; //******************************************************************************************************************* // LLObjectHandler //******************************************************************************************************************* // handle secondlife:///app/object//inspect SLURLs class LLObjectHandler : public LLCommandHandler { public: LLObjectHandler() : LLCommandHandler("object", UNTRUSTED_BLOCK) { } bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { if (params.size() < 2) return false; LLUUID object_id; if (!object_id.set(params[0], false)) { return false; } const std::string verb = params[1].asString(); if (verb == "inspect") { LLFloaterReg::showInstance("inspect_object", LLSD().with("object_id", object_id)); return true; } return false; } }; LLObjectHandler gObjectHandler; //******************************************************************************************************************* //LLFloaterIMNearbyChatToastPanel //******************************************************************************************************************* LLFloaterIMNearbyChatToastPanel* LLFloaterIMNearbyChatToastPanel::createInstance() { LLFloaterIMNearbyChatToastPanel* item = new LLFloaterIMNearbyChatToastPanel(); item->buildFromFile("panel_chat_item.xml"); item->setFollows(FOLLOWS_NONE); return item; } void LLFloaterIMNearbyChatToastPanel::reshape (S32 width, S32 height, bool called_from_parent ) { LLPanel::reshape(width, height,called_from_parent); // reshape() may be called from LLView::initFromParams() before the children are created. // We call findChild() instead of getChild() here to avoid creating dummy controls. LLUICtrl* msg_text = findChild("msg_text", false); LLUICtrl* icon = findChild("avatar_icon", false); if (!msg_text || !icon) { return; } LLRect msg_text_rect = msg_text->getRect(); LLRect avatar_rect = icon->getRect(); avatar_rect.setLeftTopAndSize(2,height-2,avatar_rect.getWidth(),avatar_rect.getHeight()); icon->setRect(avatar_rect); msg_text_rect.setLeftTopAndSize( avatar_rect.mRight + msg_left_offset, height - msg_height_pad, width - avatar_rect.mRight - msg_left_offset - msg_right_offset, height - 2*msg_height_pad); msg_text->reshape( msg_text_rect.getWidth(), msg_text_rect.getHeight(), 1); msg_text->setRect(msg_text_rect); } bool LLFloaterIMNearbyChatToastPanel::postBuild() { return LLPanel::postBuild(); } void LLFloaterIMNearbyChatToastPanel::addMessage(LLSD& notification) { std::string messageText = notification["message"].asString(); // UTF-8 line of text std::string color_name = notification["text_color"].asString(); LLUIColor textColor = LLUIColorTable::instance().getColor(color_name); F32 textAlpha = (F32)notification["color_alpha"].asReal(); S32 font_size = notification["font_size"].asInteger(); LLFontGL* messageFont; switch(font_size) { case 0: messageFont = LLFontGL::getFontSansSerifSmall(); break; default: case 1: messageFont = LLFontGL::getFontSansSerif(); break; case 2: messageFont = LLFontGL::getFontSansSerifBig(); break; } //append text { LLStyle::Params style_params; style_params.color(textColor); style_params.alpha(textAlpha); std::string font_name = LLFontGL::nameFromFont(messageFont); std::string font_style_size = LLFontGL::sizeFromFont(messageFont); style_params.font.name(font_name); style_params.font.size(font_style_size); int chat_type = notification["chat_type"].asInteger(); if(notification["chat_style"].asInteger()== CHAT_STYLE_IRC) { style_params.font.style = "ITALIC"; } else if( chat_type == CHAT_TYPE_SHOUT) { style_params.font.style = "BOLD"; } else if( chat_type == CHAT_TYPE_WHISPER) { style_params.font.style = "ITALIC"; } mMsgText->appendText(messageText, true, style_params); } snapToMessageHeight(); } void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) { std::string messageText = notification["message"].asString(); // UTF-8 line of text std::string fromName = notification["from"].asString(); // agent or object name mFromID = notification["from_id"].asUUID(); // agent id or object id mFromName = fromName; int sType = notification["source"].asInteger(); mSourceType = (EChatSourceType)sType; mIsFromScript = notification["is_lua"].asBoolean(); std::string color_name = notification["text_color"].asString(); LLUIColor textColor = LLUIColorTable::instance().getColor(color_name); F32 textAlpha = (F32)notification["color_alpha"].asReal(); S32 font_size = notification["font_size"].asInteger(); LLFontGL* messageFont; switch(font_size) { case 0: messageFont = LLFontGL::getFontSansSerifSmall(); break; default: case 1: messageFont = LLFontGL::getFontSansSerif(); break; case 2: messageFont = LLFontGL::getFontSansSerifBig(); break; } mMsgText = getChild("msg_text", false); mMsgText->setContentTrusted(false); mMsgText->setIsFriendCallback(LLAvatarActions::isFriend); mMsgText->setText(std::string("")); if ( notification["chat_style"].asInteger() != CHAT_STYLE_IRC ) { std::string str_sender; str_sender = mIsFromScript ? LLTrans::getString("ScriptBy") + fromName : fromName; str_sender+=" "; //append sender name if (mSourceType == CHAT_SOURCE_AGENT || mSourceType == CHAT_SOURCE_OBJECT) { LLStyle::Params style_params_name; style_params_name.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); style_params_name.font.name = LLFontGL::nameFromFont(messageFont); style_params_name.font.size = LLFontGL::sizeFromFont(messageFont); style_params_name.link_href = notification["sender_slurl"].asString(); style_params_name.is_link = true; mMsgText->appendText(str_sender, false, style_params_name); } else { mMsgText->appendText(str_sender, false); } } S32 chars_in_line = mMsgText->getRect().getWidth() / messageFont->getWidth("c"); S32 max_lines = notification["available_height"].asInteger() / (mMsgText->getTextPixelHeight() + 4); int lines = 0; int chars = 0; //Remove excessive chars if message does not fit in available height. MAINT-6891 std::string::iterator it; for (it = messageText.begin(); it < messageText.end() && lines < max_lines; it++) { if (*it == '\n') ++lines; else ++chars; if (chars >= chars_in_line) { chars = 0; ++lines; } } if (it < messageText.end()) { messageText.erase(it, messageText.end()); messageText += " ..."; } //append text { LLStyle::Params style_params; style_params.color(textColor); style_params.alpha(textAlpha); std::string font_name = LLFontGL::nameFromFont(messageFont); std::string font_style_size = LLFontGL::sizeFromFont(messageFont); style_params.font.name(font_name); style_params.font.size(font_style_size); int chat_type = notification["chat_type"].asInteger(); if(notification["chat_style"].asInteger()== CHAT_STYLE_IRC) { style_params.font.style = "ITALIC"; } else if( chat_type == CHAT_TYPE_SHOUT) { style_params.font.style = "BOLD"; } else if( chat_type == CHAT_TYPE_WHISPER) { style_params.font.style = "ITALIC"; } mMsgText->appendText(messageText, false, style_params); } snapToMessageHeight(); mIsDirty = true;//will set Avatar Icon in draw } void LLFloaterIMNearbyChatToastPanel::snapToMessageHeight () { S32 new_height = llmax (mMsgText->getTextPixelHeight() + 2*mMsgText->getVPad() + 2*msg_height_pad, 25); LLRect panel_rect = getRect(); panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth(), new_height); reshape( getRect().getWidth(), getRect().getHeight(), 1); setRect(panel_rect); } void LLFloaterIMNearbyChatToastPanel::onMouseLeave (S32 x, S32 y, MASK mask) { } void LLFloaterIMNearbyChatToastPanel::onMouseEnter (S32 x, S32 y, MASK mask) { if(mSourceType != CHAT_SOURCE_AGENT) return; } bool LLFloaterIMNearbyChatToastPanel::handleMouseDown (S32 x, S32 y, MASK mask) { return LLPanel::handleMouseDown(x,y,mask); } bool LLFloaterIMNearbyChatToastPanel::handleMouseUp (S32 x, S32 y, MASK mask) { /* fix for request EXT-4780 leaving this commented since I don't remember why ew block those messages... if(mSourceType != CHAT_SOURCE_AGENT) return LLPanel::handleMouseUp(x,y,mask); */ S32 local_x = x - mMsgText->getRect().mLeft; S32 local_y = y - mMsgText->getRect().mBottom; //if text_box process mouse up (ussually this is click on url) - we didn't show nearby_chat. if (mMsgText->pointInView(local_x, local_y)) { if (mMsgText->handleMouseUp(local_x, local_y, mask)) return true; LLFloaterReg::getTypedInstance("nearby_chat")->showHistory(); return false; } LLFloaterReg::getTypedInstance("nearby_chat")->showHistory(); return LLPanel::handleMouseUp(x, y, mask); } void LLFloaterIMNearbyChatToastPanel::setHeaderVisibility(EShowItemHeader e) { LLUICtrl* icon = getChild("avatar_icon", false); if(icon) icon->setVisible(e == CHATITEMHEADER_SHOW_ONLY_ICON || e==CHATITEMHEADER_SHOW_BOTH); } bool LLFloaterIMNearbyChatToastPanel::canAddText () { LLChatMsgBox* msg_text = findChild("msg_text"); if(!msg_text) return false; return msg_text->getLineCount()<10; } bool LLFloaterIMNearbyChatToastPanel::handleRightMouseDown(S32 x, S32 y, MASK mask) { LLUICtrl* avatar_icon = getChild("avatar_icon", false); S32 local_x = x - avatar_icon->getRect().mLeft; S32 local_y = y - avatar_icon->getRect().mBottom; //eat message for avatar icon if msg was from object if(avatar_icon->pointInView(local_x, local_y) && mSourceType != CHAT_SOURCE_AGENT) return true; return LLPanel::handleRightMouseDown(x,y,mask); } void LLFloaterIMNearbyChatToastPanel::draw() { LLPanel::draw(); if(mIsDirty) { LLAvatarIconCtrl* icon = getChild("avatar_icon", false); if(icon) { icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT); if(mSourceType == CHAT_SOURCE_OBJECT) icon->setValue(LLSD("OBJECT_Icon")); else if(mSourceType == CHAT_SOURCE_SYSTEM) icon->setValue(LLSD("SL_Logo")); else if(mSourceType == CHAT_SOURCE_AGENT) icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD(mFromID)); else if(!mFromID.isNull()) icon->setValue(mFromID); } mIsDirty = false; } }