From 9e0e0e4d54c73288a159beae3a654771a75f3714 Mon Sep 17 00:00:00 2001 From: Yuri Chebotarev Date: Mon, 30 Nov 2009 15:35:48 +0200 Subject: no ticket. addition to "(EXT-2894)- Add support for the viewer 1.23 chat history style (widget-less)" change all messages style when chaning chat style in preference. --HG-- branch : product-engine --- indra/newview/llfloaterpreference.cpp | 3 +++ indra/newview/llnearbychat.cpp | 26 +++++++++++++++++++++++++- indra/newview/llnearbychat.h | 8 +++++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 83c784c1f7..5128a7b861 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -106,6 +106,7 @@ #include "llviewermedia.h" #include "llpluginclassmedia.h" #include "llteleporthistorystorage.h" +#include "llnearbychat.h" #include @@ -361,6 +362,8 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) BOOL LLFloaterPreference::postBuild() { gSavedSettings.getControl("PlainTextChatHistory")->getSignal()->connect(boost::bind(&LLIMFloater::processChatHistoryStyleUpdate, _2)); + + gSavedSettings.getControl("PlainTextChatHistory")->getSignal()->connect(boost::bind(&LLNearbyChat::processChatHistoryStyleUpdate, _2)); LLTabContainer* tabcontainer = getChild("pref core"); if (!tabcontainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index 8f1dec1431..ee3be0a5e3 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -57,6 +57,7 @@ #include "lltrans.h" #include "llbottomtray.h" #include "llnearbychatbar.h" +#include "llfloaterreg.h" static const S32 RESIZE_BAR_THICKNESS = 3; @@ -145,7 +146,7 @@ std::string appendTime() return timeStr; } -void LLNearbyChat::addMessage(const LLChat& chat) +void LLNearbyChat::addMessage(const LLChat& chat,bool archive) { if (chat.mChatType == CHAT_TYPE_DEBUG_MSG) { @@ -207,6 +208,13 @@ void LLNearbyChat::addMessage(const LLChat& chat) mChatHistory->appendMessage(chat,use_plain_text_chat_history); } } + + if(archive) + { + mMessageArchive.push_back(chat); + if(mMessageArchive.size()>200) + mMessageArchive.erase(mMessageArchive.begin()); + } } void LLNearbyChat::onNearbySpeakers() @@ -256,3 +264,19 @@ void LLNearbyChat::getAllowedRect(LLRect& rect) { rect = gViewerWindow->getWorldViewRectScaled(); } + +void LLNearbyChat::updateChatHistoryStyle() +{ + mChatHistory->clear(); + for(std::vector::iterator it = mMessageArchive.begin();it!=mMessageArchive.end();++it) + { + addMessage(*it,false); + } +} +//static +void LLNearbyChat::processChatHistoryStyleUpdate(const LLSD& newvalue) +{ + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance("nearby_chat", LLSD()); + if(nearby_chat) + nearby_chat->updateChatHistoryStyle(); +} diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h index efcaf4263b..1cbc2a3478 100644 --- a/indra/newview/llnearbychat.h +++ b/indra/newview/llnearbychat.h @@ -47,7 +47,7 @@ public: ~LLNearbyChat(); BOOL postBuild (); - void addMessage (const LLChat& message); + void addMessage (const LLChat& message,bool archive = true); void onNearbyChatContextMenuItemClicked(const LLSD& userdata); bool onNearbyChatCheckContextMenuItem(const LLSD& userdata); @@ -57,6 +57,10 @@ public: virtual void setRect (const LLRect &rect); + virtual void updateChatHistoryStyle(); + + static void processChatHistoryStyleUpdate(const LLSD& newvalue); + private: virtual void applySavedVariables(); @@ -68,6 +72,8 @@ private: private: LLHandle mPopupMenuHandle; LLChatHistory* mChatHistory; + + std::vector mMessageArchive; }; #endif -- cgit v1.2.3 From d3ae1d909eba60471e79ae7e44eff0c3ce34b64a Mon Sep 17 00:00:00 2001 From: Alexei Arabadji Date: Tue, 1 Dec 2009 12:24:46 +0200 Subject: =?UTF-8?q?fixed=20EXT-2958=20=E2=80=9CThe=20states=20of=20checkbo?= =?UTF-8?q?xes=20from=20Notes&Privacy=20tab=20are=20not=20saved=20after=20?= =?UTF-8?q?having=20been=20modified=E2=80=9D;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --HG-- branch : product-engine --- indra/newview/llpanelavatar.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 97c1e96175..125d9c3934 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -254,11 +254,19 @@ void LLPanelAvatarNotes::onCommitRights() const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); bool allow_modify_objects = childGetValue("objects_check").asBoolean(); + + // if modify objects checkbox clicked if (buddy_relationship->isRightGrantedTo( LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects) { confirmModifyRights(allow_modify_objects, rights); } + // only one checkbox can trigger commit, so store the rest of rights + else + { + LLAvatarPropertiesProcessor::getInstance()->sendFriendRights( + getAvatarId(), rights); + } } void LLPanelAvatarNotes::processProperties(void* data, EAvatarProcessorType type) -- cgit v1.2.3 From ab5e6c93c927935943b7135a8e70dd50256e3c2e Mon Sep 17 00:00:00 2001 From: Alexei Arabadji Date: Tue, 1 Dec 2009 15:16:12 +0200 Subject: =?UTF-8?q?implemented=20EXT-2799=20=E2=80=9CRecord=20to=20IM=20hi?= =?UTF-8?q?story=20notification=20about=20L$=20payments=20by=20other=20ava?= =?UTF-8?q?tar=E2=80=9D;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --HG-- branch : product-engine --- indra/newview/llnotificationhandlerutil.cpp | 5 +++-- indra/newview/llviewermessage.cpp | 23 +++++++++++++++++++++- .../newview/skins/default/xui/en/notifications.xml | 7 +++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index 05da338513..857b7e9796 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -43,13 +43,14 @@ using namespace LLNotificationsUI; const static std::string GRANTED_MODIFY_RIGHTS("GrantedModifyRights"), REVOKED_MODIFY_RIGHTS("RevokedModifyRights"), OBJECT_GIVE_ITEM( "ObjectGiveItem"), OBJECT_GIVE_ITEM_UNKNOWN_USER( - "ObjectGiveItemUnknownUser"); + "ObjectGiveItemUnknownUser"), PAYMENT_RECIVED("PaymentRecived"); // static bool LLHandlerUtil::canLogToIM(const LLNotificationPtr& notification) { return GRANTED_MODIFY_RIGHTS == notification->getName() - || REVOKED_MODIFY_RIGHTS == notification->getName(); + || REVOKED_MODIFY_RIGHTS == notification->getName() + || PAYMENT_RECIVED == notification->getName(); } // static diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 9fc818e1ff..a5e06e7cff 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4347,7 +4347,28 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) // *TODO: Translate LLSD args; args["MESSAGE"] = desc; - LLNotificationsUtil::add("SystemMessage", args); + + // this is a marker to retrieve avatar name from server message: + // " paid you L$" + const std::string marker = "paid you L$"; + + // extract avatar name from system message + std::string name = desc.substr(0, desc.find(marker, 0)); + LLStringUtil::trim(name); + + // if name extracted and name cache contains avatar id send loggable notification + LLUUID from_id; + if(name.size() > 0 && gCacheName->getUUID(name, from_id)) + { + args["NAME"] = name; + LLSD payload; + payload["from_id"] = from_id; + LLNotificationsUtil::add("PaymentRecived", args, payload); + } + else + { + LLNotificationsUtil::add("SystemMessage", args); + } // Once the 'recent' container gets large enough, chop some // off the beginning. diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index cb0614797a..254c8a0f21 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -4609,6 +4609,13 @@ Please select at least one type of content to search (PG, Mature, or Adult). [MESSAGE] + +[MESSAGE] + + Date: Tue, 1 Dec 2009 15:55:24 +0200 Subject: fix for normal EXT-2820 [BSI] Functionality loss: Can't open groups from Resident's profile --HG-- branch : product-engine --- indra/newview/llgroupactions.cpp | 6 +++--- indra/newview/llpanelavatar.cpp | 11 +++++------ indra/newview/llpanelavatar.h | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index 6fe8ed0e4d..99b58f2170 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -100,9 +100,9 @@ public: } if (tokens[1].asString() == "inspect") { - LLSD key; - key["group_id"] = group_id; - LLFloaterReg::showInstance("inspect_group", key); + if (group_id.isNull()) + return true; + LLGroupActions::show(group_id); return true; } return false; diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 97c1e96175..c2bf881a60 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -522,20 +522,19 @@ void LLPanelAvatarProfile::processGroupProperties(const LLAvatarGroups* avatar_g for(; it_end != it; ++it) { LLAvatarGroups::LLGroupData group_data = *it; - - // Check if there is no duplicates for this group - if (std::find(mGroups.begin(), mGroups.end(), group_data.group_name) == mGroups.end()) - mGroups.push_back(group_data.group_name); + mGroups[group_data.group_name] = group_data.group_id; } // Creating string, containing group list std::string groups = ""; - for (group_list_t::const_iterator it = mGroups.begin(); it != mGroups.end(); ++it) + for (group_map_t::iterator it = mGroups.begin(); it != mGroups.end(); ++it) { if (it != mGroups.begin()) groups += ", "; - groups += *it; + + std::string group_url="[secondlife:///app/group/" + it->second.asString() + "/about " + it->first + "]"; + groups += group_url; } childSetValue("sl_groups", groups); diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index f54aeee4eb..b19c5cca49 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -192,8 +192,8 @@ protected: private: - typedef std::list group_list_t; - group_list_t mGroups; + typedef std::map< std::string,LLUUID> group_map_t; + group_map_t mGroups; LLToggleableMenu* mProfileMenu; }; -- cgit v1.2.3 From 176f29106de904433d62530b00df05a23c21eb8c Mon Sep 17 00:00:00 2001 From: Dmitry Zaporozhan Date: Tue, 1 Dec 2009 16:16:21 +0200 Subject: Workaround for major bug EXT-2879 - Only 'Online' accordion is present in the People panel / Friends tab. --HG-- branch : product-engine --- indra/newview/llviewerinventory.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index d0ae5d1e38..f9e1a94def 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -509,7 +509,10 @@ bool LLViewerInventoryCategory::fetchDescendents() // This comes from LLInventoryFilter from llfolderview.h U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1; - std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents"); + // *NOTE + // Temporary workaround for bug EXT-2879, see ticket for details. + // Commented gAgent.getRegion()->getCapability in order to use the old system. + std::string url;//= gAgent.getRegion()->getCapability("WebFetchInventoryDescendents"); if (!url.empty()) //Capability found. Build up LLSD and use it. { -- cgit v1.2.3 From cf3d40462e3c0421884a098505413c00f9004e6a Mon Sep 17 00:00:00 2001 From: Yuri Chebotarev Date: Tue, 1 Dec 2009 16:53:15 +0200 Subject: fix for normal EXT-1713 Nearby Chat: Objects have tooltips (???)(???) --HG-- branch : product-engine --- indra/newview/llavatariconctrl.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp index 8f3eba98a6..44cbbbb6b2 100644 --- a/indra/newview/llavatariconctrl.cpp +++ b/indra/newview/llavatariconctrl.cpp @@ -303,5 +303,9 @@ void LLAvatarIconCtrl::nameUpdatedCallback( { setToolTip(mFirstName + " " + mLastName); } + else + { + setToolTip(std::string("")); + } } } -- cgit v1.2.3 From f5e64315e27877e994b755d0de9d35dde0ccc674 Mon Sep 17 00:00:00 2001 From: Mike Antipov Date: Tue, 1 Dec 2009 17:04:47 +0200 Subject: Work on EXT-2985 (Implement Avaline calls processing in Voice Control Panel) -- updated reaction to accepting incoming call: added session URI argument. For now avaline caller is shown in the voice controls. --HG-- branch : product-engine --- indra/newview/llimview.cpp | 3 ++- indra/newview/llimview.h | 9 +++++++-- indra/newview/llvoicechannel.cpp | 6 ++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index be719c0a78..c5c412d4ee 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -1348,7 +1348,8 @@ void LLIncomingCallDialog::processCallResponse(S32 response) session_id = gIMMgr->addP2PSession( mPayload["session_name"].asString(), mPayload["caller_id"].asUUID(), - mPayload["session_handle"].asString()); + mPayload["session_handle"].asString(), + mPayload["session_uri"].asString()); if (voice) { diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 40e3a8fb69..b2d3c6b921 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -277,11 +277,16 @@ public: const LLUUID& other_participant_id, const LLDynamicArray& ids); - // Creates a P2P session with the requisite handle for responding to voice calls + /** + * Creates a P2P session with the requisite handle for responding to voice calls. + * + * @param caller_uri - sip URI of caller. It should be always be passed into the method to avoid + * incorrect working of LLVoiceChannel instances. See EXT-2985. + */ LLUUID addP2PSession(const std::string& name, const LLUUID& other_participant_id, const std::string& voice_session_handle, - const std::string& caller_uri = LLStringUtil::null); + const std::string& caller_uri); /** * Leave the session with session id. Send leave session notification diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 3554528d19..a0396bc790 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -750,6 +750,8 @@ LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string mReceivedCall(FALSE) { // make sure URI reflects encoded version of other user's agent id + // *NOTE: in case of Avaline call generated SIP URL will be incorrect. + // But it will be overridden in LLVoiceChannelP2P::setSessionHandle() called when agent accepts call setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id)); } @@ -867,6 +869,10 @@ void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::s } else { + LL_WARNS("Voice") << "incoming SIP URL is not provided. Channel may not work properly." << LL_ENDL; + // In case of incoming AvaLine call generated URI will be differ from original one. + // This is because Avatar-2-Avatar URI is based on avatar UUID but Avaline is not. + // See LLVoiceClient::sessionAddedEvent() -> setUUIDFromStringHash() setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID)); } -- cgit v1.2.3 From 32887cdc5407c7ced2d030cc8423fb0ab688170f Mon Sep 17 00:00:00 2001 From: Sergey Borushevsky Date: Tue, 1 Dec 2009 17:13:35 +0200 Subject: Implemented normal task EXT-2750 (Add context menu for group and ad-hoc chiclet) Added menu to ad-hoc chiclet, which contains one 'End Session' item. --HG-- branch : product-engine --- indra/newview/llchiclet.cpp | 41 ++++++++++++++++++++++ indra/newview/llchiclet.h | 11 ++++++ .../skins/default/xui/en/menu_imchiclet_adhoc.xml | 19 ++++++++++ 3 files changed, 71 insertions(+) create mode 100644 indra/newview/skins/default/xui/en/menu_imchiclet_adhoc.xml diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index f41e326dd0..d533743cfc 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -595,8 +595,49 @@ void LLAdHocChiclet::setCounter(S32 counter) setShowNewMessagesIcon(counter); } +void LLAdHocChiclet::createPopupMenu() +{ + if(mPopupMenu) + { + llwarns << "Menu already exists" << llendl; + return; + } + if(getSessionId().isNull()) + { + return; + } + + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + registrar.add("IMChicletMenu.Action", boost::bind(&LLAdHocChiclet::onMenuItemClicked, this, _2)); + + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile + ("menu_imchiclet_adhoc.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +} + +void LLAdHocChiclet::onMenuItemClicked(const LLSD& user_data) +{ + std::string level = user_data.asString(); + LLUUID group_id = getSessionId(); + + if("end" == level) + { + LLGroupActions::endIM(group_id); + } +} + BOOL LLAdHocChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask) { + if(!mPopupMenu) + { + createPopupMenu(); + } + + if (mPopupMenu) + { + mPopupMenu->arrangeAndClear(); + LLMenuGL::showPopup(this, mPopupMenu, x, y); + } + return TRUE; } diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index 1ea141e6c4..ed4bcbc6ac 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -517,6 +517,17 @@ protected: LLAdHocChiclet(const Params& p); friend class LLUICtrlFactory; + /** + * Creates chiclet popup menu. Will create AdHoc Chat menu + * based on other participant's id. + */ + virtual void createPopupMenu(); + + /** + * Processes clicks on chiclet popup menu. + */ + virtual void onMenuItemClicked(const LLSD& user_data); + /** * Displays popup menu. */ diff --git a/indra/newview/skins/default/xui/en/menu_imchiclet_adhoc.xml b/indra/newview/skins/default/xui/en/menu_imchiclet_adhoc.xml new file mode 100644 index 0000000000..eb5e31b57d --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_imchiclet_adhoc.xml @@ -0,0 +1,19 @@ + + + + + + -- cgit v1.2.3 From 573f146b7b69e70cd1e509cf50a6253355aa70be Mon Sep 17 00:00:00 2001 From: Yuri Chebotarev Date: Tue, 1 Dec 2009 17:54:38 +0200 Subject: fix normal EXT-2937 Nearby Chat window has layout issues --HG-- branch : product-engine --- indra/newview/skins/default/xui/en/floater_nearby_chat.xml | 8 +++++--- indra/newview/skins/default/xui/en/panel_chat_header.xml | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml index d8534bfe0b..0856049374 100644 --- a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml +++ b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml @@ -22,13 +22,15 @@ bg_readonly_color="ChatHistoryBgColor" bg_writeable_color="ChatHistoryBgColor" follows="all" - left="1" + left="5" top="20" layout="topleft" - height="280" + height="275" name="chat_history" parse_highlights="true" text_color="ChatHistoryTextColor" text_readonly_color="ChatHistoryTextColor" - width="320" /> + right_widget_pad="5" + left_widget_pad="0" + width="315" /> diff --git a/indra/newview/skins/default/xui/en/panel_chat_header.xml b/indra/newview/skins/default/xui/en/panel_chat_header.xml index c1090a1686..9cb765ae93 100644 --- a/indra/newview/skins/default/xui/en/panel_chat_header.xml +++ b/indra/newview/skins/default/xui/en/panel_chat_header.xml @@ -8,7 +8,7 @@ label="im_header" layout="topleft" name="im_header" - width="300"> + width="310"> Date: Tue, 1 Dec 2009 18:17:38 +0200 Subject: implemented normal task EXT-2471 llLoadURL should be handled also by Chiclet subsystem along with Notificaton subsystem --HG-- branch : product-engine --- indra/newview/llscriptfloater.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp index c58caf9c60..7c4f3d3608 100644 --- a/indra/newview/llscriptfloater.cpp +++ b/indra/newview/llscriptfloater.cpp @@ -41,6 +41,7 @@ #include "llscreenchannel.h" #include "lltoastnotifypanel.h" #include "llviewerwindow.h" +#include "llimfloater.h" ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// @@ -212,6 +213,8 @@ void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id) mNotifications.insert(std::make_pair(object_id, nd)); LLBottomTray::getInstance()->getChicletPanel()->createChiclet(object_id); + + toggleScriptFloater(object_id); } void LLScriptFloaterManager::onRemoveNotification(const LLUUID& notification_id) -- cgit v1.2.3 From dd262a7a3682c80d67908ab4b8f31660699e85e9 Mon Sep 17 00:00:00 2001 From: Igor Borovkov Date: Tue, 1 Dec 2009 19:01:42 +0200 Subject: implemented EXT-2582 (Save IM chat history as plain text file) updated 1.23 chat log format - in multilined messages subsequent lines are prepended with a space multilined messages of an old format are not supported, each line is considered as a separate message the parser depends on current used date and time format --HG-- branch : product-engine --- indra/newview/llimview.cpp | 45 ++++++-- indra/newview/llimview.h | 2 + indra/newview/lllogchat.cpp | 250 ++++++++++++++++++++++++++++++++++++++++++-- indra/newview/lllogchat.h | 55 ++++++++++ 4 files changed, 336 insertions(+), 16 deletions(-) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index c5c412d4ee..5481ca97cd 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -83,19 +83,16 @@ #include "llfirstuse.h" #include "llagentui.h" +const static std::string IM_TIME("time"); +const static std::string IM_TEXT("message"); +const static std::string IM_FROM("from"); +const static std::string IM_FROM_ID("from_id"); + // // Globals // LLIMMgr* gIMMgr = NULL; -// -// Statics -// -// *FIXME: make these all either UIStrings or Strings - -const static std::string IM_SEPARATOR(": "); - - void toast_callback(const LLSD& msg){ // do not show toast in busy mode or it goes from agent if (gAgent.getBusy() || gAgent.getID() == msg["from_id"]) @@ -193,7 +190,13 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& } if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) - LLLogChat::loadHistory(mName, &chatFromLogFile, (void *)this); + { + std::list chat_history; + + //involves parsing of a chat history + LLLogChat::loadAllHistory(mName, chat_history); + addMessagesFromHistory(chat_history); + } } void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state) @@ -303,6 +306,30 @@ void LLIMModel::LLIMSession::addMessage(const std::string& from, const LLUUID& f } } +void LLIMModel::LLIMSession::addMessagesFromHistory(const std::list& history) +{ + std::list::const_iterator it = history.begin(); + while (it != history.end()) + { + const LLSD& msg = *it; + + std::string from = msg[IM_FROM]; + LLUUID from_id = LLUUID::null; + if (msg[IM_FROM_ID].isUndefined()) + { + gCacheName->getUUID(from, from_id); + } + + + std::string timestamp = msg[IM_TIME]; + std::string text = msg[IM_TEXT]; + + addMessage(from, from_id, text, timestamp); + + it++; + } +} + void LLIMModel::LLIMSession::chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata) { if (!userdata) return; diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index b2d3c6b921..66f92c83a5 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -60,6 +60,8 @@ public: virtual ~LLIMSession(); void sessionInitReplyReceived(const LLUUID& new_session_id); + + void addMessagesFromHistory(const std::list& history); void addMessage(const std::string& from, const LLUUID& from_id, const std::string& utf8_text, const std::string& time); void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state); static void chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata); diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 9caa863bd8..33fd3e3bf1 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -32,15 +32,59 @@ #include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "llagentui.h" #include "lllogchat.h" -#include "llappviewer.h" #include "llfloaterchat.h" #include "lltrans.h" #include "llviewercontrol.h" -#include "llsdserialize.h" + +#include +#include +#include +#include const S32 LOG_RECALL_SIZE = 2048; +const static std::string IM_TIME("time"); +const static std::string IM_TEXT("message"); +const static std::string IM_FROM("from"); +const static std::string IM_FROM_ID("from_id"); +const static std::string IM_SEPARATOR(": "); + +const static std::string NEW_LINE("\n"); +const static std::string NEW_LINE_SPACE_PREFIX("\n "); +const static std::string TWO_SPACES(" "); +const static std::string MULTI_LINE_PREFIX(" "); + +//viewer 1.23 may have used "You" for Agent's entries +const static std::string YOU("You"); + +/** + * Chat log lines - timestamp and name are optional but message text is mandatory. + * + * Typical plain text chat log lines: + * + * SuperCar: You aren't the owner + * [2:59] SuperCar: You aren't the owner + * [2009/11/20 3:00] SuperCar: You aren't the owner + * Katar Ivercourt is Offline + * [3:00] Katar Ivercourt is Offline + * [2009/11/20 3:01] Corba ProductEngine is Offline + */ +const static boost::regex TIMESTAMP_AND_STUFF("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}\\]\\s+|\\[\\d{1,2}:\\d{2}\\]\\s+)?(.*)$"); + +/** + * Regular expression suitable to match names like + * "You", "Second Life", "Igor ProductEngine", "Object", "Mega House" + */ +const static boost::regex NAME_AND_TEXT("(You:|Second Life:|[^\\s:]+\\s*[:]{1}|\\S+\\s+[^\\s:]+[:]{1})?(\\s*)(.*)"); + +const static int IDX_TIMESTAMP = 1; +const static int IDX_STUFF = 2; +const static int IDX_NAME = 1; +const static int IDX_TEXT = 3; + //static std::string LLLogChat::makeLogFileName(std::string filename) { @@ -118,7 +162,7 @@ void LLLogChat::saveHistory(const std::string& filename, item["from_id"] = from_id; item["message"] = line; - file << LLSDOStreamer (item) << std::endl; + file << LLChatLogFormatter(item) << std::endl; file.close(); } @@ -154,9 +198,6 @@ void LLLogChat::loadHistory(const std::string& filename, void (*callback)(ELogLi } } - // the parser's destructor is protected so we cannot create in the stack. - LLPointer parser = new LLSDNotationParser(); - while ( fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr) ) { len = strlen(buffer) - 1; /*Flawfinder: ignore*/ @@ -167,7 +208,8 @@ void LLLogChat::loadHistory(const std::string& filename, void (*callback)(ELogLi LLSD item; std::string line(buffer); std::istringstream iss(line); - if (parser->parse(iss, item, line.length()) == LLSDParser::PARSE_FAILURE) + + if (!LLChatLogParser::parse(line, item)) { item["message"] = line; callback(LOG_LINE, item, userdata); @@ -187,3 +229,197 @@ void LLLogChat::loadHistory(const std::string& filename, void (*callback)(ELogLi fclose(fptr); } } + +void append_to_last_message(std::list& messages, const std::string& line) +{ + if (!messages.size()) return; + + std::string im_text = messages.back()[IM_TEXT].asString(); + im_text.append(line); + messages.back()[IM_TEXT] = im_text; +} + +void LLLogChat::loadAllHistory(const std::string& session_name, std::list& messages) +{ + if (session_name.empty()) + { + llwarns << "Session name is Empty!" << llendl; + return ; + } + + LLFILE* fptr = LLFile::fopen(makeLogFileName(session_name), "r"); /*Flawfinder: ignore*/ + if (!fptr) return; //No previous conversation with this name. + + char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/ + char *bptr; + S32 len; + bool firstline = TRUE; + + if (fseek(fptr, (LOG_RECALL_SIZE - 1) * -1 , SEEK_END)) + { //File is smaller than recall size. Get it all. + firstline = FALSE; + if (fseek(fptr, 0, SEEK_SET)) + { + fclose(fptr); + return; + } + } + + while (fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr)) + { + len = strlen(buffer) - 1; /*Flawfinder: ignore*/ + for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0'; + + if (firstline) + { + firstline = FALSE; + continue; + } + + std::string line(buffer); + + //updated 1.23 plaint text log format requires a space added before subsequent lines in a multilined message + if (' ' == line[0]) + { + line.erase(0, MULTI_LINE_PREFIX.length()); + append_to_last_message(messages, '\n' + line); + } + else if (0 == len && ('\n' == line[0] || '\r' == line[0])) + { + //to support old format's multilined messages with new lines used to divide paragraphs + append_to_last_message(messages, line); + } + else + { + LLSD item; + if (!LLChatLogParser::parse(line, item)) + { + item[IM_TEXT] = line; + } + messages.push_back(item); + } + } + fclose(fptr); +} + +//*TODO mark object's names in a special way so that they will be distinguishable form avatar name +//which are more strict by its nature (only firstname and secondname) +//Example, an object's name can be writen like "Object " +void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const +{ + if (!im.isMap()) + { + llwarning("invalid LLSD type of an instant message", 0); + return; + } + + if (im[IM_TIME].isDefined()) + { + std::string timestamp = im[IM_TIME].asString(); + boost::trim(timestamp); + ostr << '[' << timestamp << ']' << TWO_SPACES; + } + + //*TODO mark object's names in a special way so that they will be distinguishable form avatar name + //which are more strict by its nature (only firstname and secondname) + //Example, an object's name can be writen like "Object " + if (im[IM_FROM].isDefined()) + { + std::string from = im[IM_FROM].asString(); + boost::trim(from); + if (from.size()) + { + ostr << from << IM_SEPARATOR; + } + } + + if (im[IM_TEXT].isDefined()) + { + std::string im_text = im[IM_TEXT].asString(); + + //multilined text will be saved with prepended spaces + boost::replace_all(im_text, NEW_LINE, NEW_LINE_SPACE_PREFIX); + ostr << im_text; + } +} + +bool LLChatLogParser::parse(std::string& raw, LLSD& im) +{ + if (!raw.length()) return false; + + im = LLSD::emptyMap(); + + //matching a timestamp + boost::match_results matches; + if (!boost::regex_match(raw, matches, TIMESTAMP_AND_STUFF)) return false; + + bool has_timestamp = matches[IDX_TIMESTAMP].matched; + if (has_timestamp) + { + //timestamp was successfully parsed + std::string timestamp = matches[IDX_TIMESTAMP]; + boost::trim(timestamp); + timestamp.erase(0, 1); + timestamp.erase(timestamp.length()-1, 1); + im[IM_TIME] = timestamp; + } + else + { + //timestamp is optional + im[IM_TIME] = ""; + } + + bool has_stuff = matches[IDX_STUFF].matched; + if (!has_stuff) + { + return false; //*TODO should return false or not? + } + + //matching a name and a text + std::string stuff = matches[IDX_STUFF]; + boost::match_results name_and_text; + if (!boost::regex_match(stuff, name_and_text, NAME_AND_TEXT)) return false; + + bool has_name = name_and_text[IDX_NAME].matched; + std::string name = name_and_text[IDX_NAME]; + + //we don't need a name/text separator + if (has_name && name.length() && name[name.length()-1] == ':') + { + name.erase(name.length()-1, 1); + } + + if (!has_name || name == SYSTEM_FROM) + { + //name is optional too + im[IM_FROM] = SYSTEM_FROM; + im[IM_FROM_ID] = LLUUID::null; + } + + if (!has_name) + { + //text is mandatory + im[IM_TEXT] = stuff; + return true; //parse as a message from Second Life + } + + bool has_text = name_and_text[IDX_TEXT].matched; + if (!has_text) return false; + + //for parsing logs created in very old versions of a viewer + if (name == "You") + { + std::string agent_name; + LLAgentUI::buildFullname(agent_name); + im[IM_FROM] = agent_name; + im[IM_FROM_ID] = gAgentID; + } + else + { + im[IM_FROM] = name; + } + + + im[IM_TEXT] = name_and_text[IDX_TEXT]; + return true; //parsed name and message text, maybe have a timestamp too +} diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index e252cd7d41..3d3f5c4458 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -51,11 +51,66 @@ public: const LLUUID& from_id, const std::string& line); + /** @deprecated @see loadAllHistory() */ static void loadHistory(const std::string& filename, void (*callback)(ELogLineType, const LLSD&, void*), void* userdata); + + static void loadAllHistory(const std::string& session_name, std::list& messages); private: static std::string cleanFileName(std::string filename); }; +/** + * Formatter for the plain text chat log files + */ +class LLChatLogFormatter +{ +public: + LLChatLogFormatter(const LLSD& im) : mIM(im) {} + virtual ~LLChatLogFormatter() {}; + + friend std::ostream& operator<<(std::ostream& str, const LLChatLogFormatter& formatter) + { + formatter.format(formatter.mIM, str); + return str; + } + +protected: + + /** + * Format an instant message to a stream + * Timestamps and sender names are required + * New lines of multilined messages are prepended with a space + */ + void format(const LLSD& im, std::ostream& ostr) const; + + LLSD mIM; +}; + +/** + * Parser for the plain text chat log files + */ +class LLChatLogParser +{ +public: + + /** + * Parse a line from the plain text chat log file + * General plain text log format is like: "[timestamp] [name]: [message]" + * [timestamp] and [name] are optional + * Examples of plain text chat log lines: + * "[2009/11/20 2:53] Igor ProductEngine: howdy" + * "Igor ProductEngine: howdy" + * "Dserduk ProductEngine is Online" + * + * @return false if failed to parse mandatory data - message text + */ + static bool parse(std::string& raw, LLSD& im); + +protected: + LLChatLogParser(); + virtual ~LLChatLogParser() {}; +}; + #endif -- cgit v1.2.3 From 279942b7bf78483fb8b2866e79782cc7e1cf260e Mon Sep 17 00:00:00 2001 From: Mike Antipov Date: Tue, 1 Dec 2009 19:42:42 +0200 Subject: Fixed critical bug EXT-2990 (Viewer crashes after openning "Voice Control" on IM floater) -- added disconnecting from subscribed signals while destroying participant list -- added disconnecting from subscribed signals while destroying Voice controls -- added nullifying of the pointer to speaker manager when channel is changed --HG-- branch : product-engine --- indra/newview/llcallfloater.cpp | 5 ++++- indra/newview/llcallfloater.h | 2 ++ indra/newview/llparticipantlist.cpp | 10 +++++++--- indra/newview/llparticipantlist.h | 5 +++++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index 1b929eca0e..7db709086f 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -54,6 +54,7 @@ LLCallFloater::LLCallFloater(const LLSD& key) LLCallFloater::~LLCallFloater() { + mChannelChangedConnection.disconnect(); delete mPaticipants; mPaticipants = NULL; } @@ -77,7 +78,7 @@ BOOL LLCallFloater::postBuild() updateSession(); // subscribe to to be notified Voice Channel is changed - LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLCallFloater::onCurrentChannelChanged, this, _1)); + mChannelChangedConnection = LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLCallFloater::onCurrentChannelChanged, this, _1)); return TRUE; } @@ -157,6 +158,8 @@ void LLCallFloater::refreshPartisipantList() void LLCallFloater::onCurrentChannelChanged(const LLUUID& /*session_id*/) { + // Forget speaker manager from the previous session to avoid using it after session was destroyed. + mSpeakerManager = NULL; updateSession(); } diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h index 8a440873ff..3112b8e81b 100644 --- a/indra/newview/llcallfloater.h +++ b/indra/newview/llcallfloater.h @@ -90,6 +90,8 @@ private: LLParticipantList* mPaticipants; LLAvatarList* mAvatarList; EVoiceControls mVoiceType; + + boost::signals2::connection mChannelChangedConnection; }; diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index 07a1214b4f..13f195a1be 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -64,10 +64,10 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* av mSpeakerMgr->addListener(mSpeakerModeratorListener, "update_moderator"); mAvatarList->setNoItemsCommentText(LLTrans::getString("LoadingData")); - mAvatarList->setDoubleClickCallback(boost::bind(&LLParticipantList::onAvatarListDoubleClicked, this, mAvatarList)); - mAvatarList->setRefreshCompleteCallback(boost::bind(&LLParticipantList::onAvatarListRefreshed, this, _1, _2)); + mAvatarListDoubleClickConnection = mAvatarList->setDoubleClickCallback(boost::bind(&LLParticipantList::onAvatarListDoubleClicked, this, mAvatarList)); + mAvatarListRefreshConnection = mAvatarList->setRefreshCompleteCallback(boost::bind(&LLParticipantList::onAvatarListRefreshed, this, _1, _2)); // Set onAvatarListDoubleClicked as default on_return action. - mAvatarList->setReturnCallback(boost::bind(&LLParticipantList::onAvatarListDoubleClicked, this, mAvatarList)); + mAvatarListReturnConnection = mAvatarList->setReturnCallback(boost::bind(&LLParticipantList::onAvatarListDoubleClicked, this, mAvatarList)); if (use_context_menu) { @@ -99,6 +99,10 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* av LLParticipantList::~LLParticipantList() { + mAvatarListDoubleClickConnection.disconnect(); + mAvatarListRefreshConnection.disconnect(); + mAvatarListReturnConnection.disconnect(); + delete mParticipantListMenu; mParticipantListMenu = NULL; } diff --git a/indra/newview/llparticipantlist.h b/indra/newview/llparticipantlist.h index 460cf4b9ef..86b38f5f1e 100644 --- a/indra/newview/llparticipantlist.h +++ b/indra/newview/llparticipantlist.h @@ -151,4 +151,9 @@ class LLParticipantList LLParticipantListMenu* mParticipantListMenu; EParticipantSortOrder mSortOrder; + + // boost::connections + boost::signals2::connection mAvatarListDoubleClickConnection; + boost::signals2::connection mAvatarListRefreshConnection; + boost::signals2::connection mAvatarListReturnConnection; }; -- cgit v1.2.3 From 3385ce87f14f71d739a3834fbf3436a962fbdd9d Mon Sep 17 00:00:00 2001 From: Andrew Dyukov Date: Tue, 1 Dec 2009 20:10:18 +0200 Subject: Implemented major task EXT-2986 (Add "Leave Call" button in Voice Control Panel for all voice chats except nearby). --HG-- branch : product-engine --- indra/newview/llcallfloater.cpp | 14 +++++++++++ indra/newview/llcallfloater.h | 6 +++-- .../default/xui/en/floater_voice_controls.xml | 27 ++++++++++++++++++++-- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index 7db709086f..d6ae4603b4 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -64,6 +64,7 @@ BOOL LLCallFloater::postBuild() { LLDockableFloater::postBuild(); mAvatarList = getChild("speakers_list"); + childSetAction("leave_call_btn", boost::bind(&LLCallFloater::leaveCall, this)); LLView *anchor_panel = LLBottomTray::getInstance()->getChild("speak_panel"); @@ -90,6 +91,14 @@ void LLCallFloater::onOpen(const LLSD& /*key*/) ////////////////////////////////////////////////////////////////////////// /// PRIVATE SECTION ////////////////////////////////////////////////////////////////////////// + +void LLCallFloater::leaveCall() +{ + LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel(); + if (voice_channel && voice_channel->isActive()) + voice_channel->deactivate(); +} + void LLCallFloater::updateSession() { LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel(); @@ -139,6 +148,11 @@ void LLCallFloater::updateSession() } updateTitle(); + + //hide "Leave Call" button for nearby chat + bool isLocalChat = mVoiceType == VC_LOCAL_CHAT; + childSetVisible("leave_btn_panel", !isLocalChat); + refreshPartisipantList(); } diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h index 3112b8e81b..d0a2ca5303 100644 --- a/indra/newview/llcallfloater.h +++ b/indra/newview/llcallfloater.h @@ -48,8 +48,8 @@ class LLSpeakerMgr; * the Resident's own microphone input volume, the audible volume of each of the other participants, * the Resident's own Voice Morphing settings (if she has subscribed to enable the feature), and Voice Recording. * - * When the Resident is engaged in Group Voice Chat, the Voice Control Panel also provides an - * 'End Call' button to allow the Resident to leave that voice channel. + * When the Resident is engaged in any chat except Nearby Chat, the Voice Control Panel also provides an + * 'Leave Call' button to allow the Resident to leave that voice channel. */ class LLCallFloater : public LLDockableFloater { @@ -69,6 +69,8 @@ private: VC_PEER_TO_PEER }EVoiceControls; + void leaveCall(); + /** * Updates mSpeakerManager and list according to current Voice Channel * diff --git a/indra/newview/skins/default/xui/en/floater_voice_controls.xml b/indra/newview/skins/default/xui/en/floater_voice_controls.xml index 04696ca2e7..c59d97457e 100644 --- a/indra/newview/skins/default/xui/en/floater_voice_controls.xml +++ b/indra/newview/skins/default/xui/en/floater_voice_controls.xml @@ -74,6 +74,7 @@ width="20" /> @@ -98,9 +101,11 @@ + width="138"> + width="138" /> + + +