summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llchathistory.cpp11
-rw-r--r--indra/newview/llfloaterimcontainer.cpp65
-rw-r--r--indra/newview/llfloaterimcontainer.h1
-rw-r--r--indra/newview/llfloaterimnearbychat.cpp4
-rw-r--r--indra/newview/llfloaterimsession.cpp30
-rw-r--r--indra/newview/llfloaterimsession.h2
-rw-r--r--indra/newview/llgroupactions.cpp125
-rw-r--r--indra/newview/llgroupactions.h8
-rw-r--r--indra/newview/llimview.cpp17
-rw-r--r--indra/newview/lllogchat.cpp28
-rw-r--r--indra/newview/lllogchat.h2
-rw-r--r--indra/newview/llpanelpeople.cpp341
-rw-r--r--indra/newview/llpanelpeople.h24
-rw-r--r--indra/newview/llsociallist.cpp155
-rw-r--r--indra/newview/llsociallist.h102
-rw-r--r--indra/newview/lltoastimpanel.cpp26
-rw-r--r--indra/newview/lltoastimpanel.h2
-rw-r--r--indra/newview/llviewermenu.cpp2
-rwxr-xr-xindra/newview/llviewerwindow.cpp2
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_session.xml66
-rw-r--r--indra/newview/skins/default/xui/en/menu_gear_fbc.xml30
-rw-r--r--indra/newview/skins/default/xui/en/menu_login.xml15
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml18
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml11
-rw-r--r--indra/newview/skins/default/xui/en/panel_people.xml92
26 files changed, 1088 insertions, 93 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index bd0169fb2f..02ab1c9ff1 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -495,6 +495,7 @@ set(viewer_SOURCE_FILES
llsidetraypanelcontainer.cpp
llsky.cpp
llslurl.cpp
+ llsociallist.cpp
llspatialpartition.cpp
llspeakers.cpp
llspeakingindicatormanager.cpp
@@ -1072,6 +1073,7 @@ set(viewer_HEADER_FILES
llsidetraypanelcontainer.h
llsky.h
llslurl.h
+ llsociallist.h
llspatialpartition.h
llspeakers.h
llspeakingindicatormanager.h
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 53926c1fef..0f138873ac 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -408,16 +408,7 @@ public:
S32 user_name_width = user_name_rect.getWidth();
S32 time_box_width = time_box->getRect().getWidth();
- if (time_box->getVisible() && user_name_width <= mMinUserNameWidth)
- {
- time_box->setVisible(FALSE);
-
- user_name_rect.mRight += time_box_width;
- user_name->reshape(user_name_rect.getWidth(), user_name_rect.getHeight());
- user_name->setRect(user_name_rect);
- }
-
- if (!time_box->getVisible() && user_name_width > mMinUserNameWidth + time_box_width)
+ if (!time_box->getVisible() && user_name_width > mMinUserNameWidth)
{
user_name_rect.mRight -= time_box_width;
user_name->reshape(user_name_rect.getWidth(), user_name_rect.getHeight());
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 7296ec3ced..7e281bd99b 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -585,6 +585,28 @@ void LLFloaterIMContainer::returnFloaterToHost()
floater->onTearOffClicked();
}
+void LLFloaterIMContainer::setMinimized(BOOL b)
+{
+ bool was_minimized = isMinimized();
+ LLMultiFloater::setMinimized(b);
+
+ //Switching from minimized to un-minimized
+ if(was_minimized && !b)
+ {
+ LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(mSelectedSession);
+
+ if(session_floater && !session_floater->isTornOff())
+ {
+ //When in DND mode, remove stored IM notifications
+ //Nearby chat (Null) IMs are not stored while in DND mode, so can ignore removal
+ if(gAgent.isDoNotDisturb() && mSelectedSession.notNull())
+ {
+ LLDoNotDisturbNotificationStorage::getInstance()->removeNotification(LLDoNotDisturbNotificationStorage::toastName, mSelectedSession);
+ }
+ }
+ }
+}
+
void LLFloaterIMContainer::setVisible(BOOL visible)
{ LLFloaterIMNearbyChat* nearby_chat;
if (visible)
@@ -597,10 +619,21 @@ void LLFloaterIMContainer::setVisible(BOOL visible)
// *TODO: find a way to move this to XML as a default panel or something like that
LLSD name("nearby_chat");
LLFloaterReg::toggleInstanceOrBringToFront(name);
- setSelectedSession(LLUUID(NULL));
+ selectConversationPair(LLUUID(NULL), false, false);
}
openNearbyChat();
- selectConversationPair(getSelectedSession(), false, false);
+ flashConversationItemWidget(mSelectedSession,false);
+
+ LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(mSelectedSession);
+ if(session_floater && !session_floater->isMinimized())
+ {
+ //When in DND mode, remove stored IM notifications
+ //Nearby chat (Null) IMs are not stored while in DND mode, so can ignore removal
+ if(gAgent.isDoNotDisturb() && mSelectedSession.notNull())
+ {
+ LLDoNotDisturbNotificationStorage::getInstance()->removeNotification(LLDoNotDisturbNotificationStorage::toastName, mSelectedSession);
+ }
+ }
}
nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
@@ -1178,7 +1211,8 @@ bool LLFloaterIMContainer::enableContextMenuItem(const LLSD& userdata)
//Enable Chat history item for ad-hoc and group conversations
if ("can_chat_history" == item && uuids.size() > 0)
{
- return LLLogChat::isTranscriptExist(uuids.front());
+ bool is_group = (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_GROUP);
+ return LLLogChat::isTranscriptExist(uuids.front(),is_group);
}
// If nothing is selected(and selected item is not group chat), everything needs to be disabled
@@ -1389,13 +1423,6 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool
widget->getParentFolder()->setSelection(widget, FALSE, FALSE);
mConversationsRoot->scrollToShowSelection();
}
-
- //When in DND mode, remove stored IM notifications
- //Nearby chat (Null) IMs are not stored while in DND mode, so can ignore removal
- if(gAgent.isDoNotDisturb() && session_id.notNull())
- {
- LLDoNotDisturbNotificationStorage::getInstance()->removeNotification(LLDoNotDisturbNotificationStorage::toastName, session_id);
- }
}
/* floater processing */
@@ -1420,14 +1447,19 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool
{
showStub(true);
}
+
+ //When in DND mode, remove stored IM notifications
+ //Nearby chat (Null) IMs are not stored while in DND mode, so can ignore removal
+ if(gAgent.isDoNotDisturb() && session_id.notNull())
+ {
+ LLDoNotDisturbNotificationStorage::getInstance()->removeNotification(LLDoNotDisturbNotificationStorage::toastName, session_id);
+ }
}
// Set the focus on the selected floater
- if (!session_floater->hasFocus())
+ if (!session_floater->hasFocus() && !session_floater->isMinimized())
{
- BOOL is_minimized = session_floater->isMinimized();
session_floater->setFocus(focus_floater);
- session_floater->setMinimized(is_minimized);
}
}
flashConversationItemWidget(session_id,false);
@@ -1986,8 +2018,11 @@ void LLFloaterIMContainer::closeFloater(bool app_quitting/* = false*/)
{
// Always unminimize before trying to close.
// Most of the time the user will never see this state.
- setMinimized(FALSE);
-
+ if(isMinimized())
+ {
+ LLMultiFloater::setMinimized(FALSE);
+ }
+
LLFloater::closeFloater(app_quitting);
}
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index 52b672241f..e39d20ec35 100644
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -59,6 +59,7 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
/*virtual*/ void draw();
+ /*virtual*/ void setMinimized(BOOL b);
/*virtual*/ void setVisible(BOOL visible);
/*virtual*/ void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());
/*virtual*/ void updateResizeLimits();
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index d86e1b3fd7..49f36a2f32 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -264,7 +264,7 @@ void LLFloaterIMNearbyChat::setVisibleAndFrontmost(BOOL take_focus, const LLSD&
if(!isTornOff() && matchesKey(key))
{
- LLFloaterIMContainer::getInstance()->selectConversationPair(mSessionID, true, false);
+ LLFloaterIMContainer::getInstance()->selectConversationPair(mSessionID, true, take_focus);
}
}
@@ -328,7 +328,7 @@ void LLFloaterIMNearbyChat::onChatFontChange(LLFontGL* fontp)
void LLFloaterIMNearbyChat::show()
{
openFloater(getKey());
- }
+}
bool LLFloaterIMNearbyChat::isChatVisible() const
{
diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp
index 6d5145f205..edc25a7d7e 100644
--- a/indra/newview/llfloaterimsession.cpp
+++ b/indra/newview/llfloaterimsession.cpp
@@ -39,6 +39,7 @@
#include "llchannelmanager.h"
#include "llchiclet.h"
#include "llchicletbar.h"
+#include "lldonotdisturbnotificationstorage.h"
#include "llfloaterreg.h"
#include "llfloateravatarpicker.h"
#include "llfloaterimcontainer.h" // to replace separate IM Floaters with multifloater container
@@ -645,6 +646,23 @@ void LLFloaterIMSession::setDocked(bool docked, bool pop_on_undock)
}
}
+void LLFloaterIMSession::setMinimized(BOOL b)
+{
+ bool wasMinimized = isMinimized();
+ LLFloaterIMSessionTab::setMinimized(b);
+
+ //Switching from minimized state to un-minimized state
+ if(wasMinimized && !b)
+ {
+ //When in DND mode, remove stored IM notifications
+ //Nearby chat (Null) IMs are not stored while in DND mode, so can ignore removal
+ if(gAgent.isDoNotDisturb())
+ {
+ LLDoNotDisturbNotificationStorage::getInstance()->removeNotification(LLDoNotDisturbNotificationStorage::toastName, mSessionID);
+ }
+ }
+}
+
void LLFloaterIMSession::setVisible(BOOL visible)
{
LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*>
@@ -713,6 +731,18 @@ BOOL LLFloaterIMSession::getVisible()
return visible;
}
+void LLFloaterIMSession::setFocus(BOOL focus)
+{
+ LLFloaterIMSessionTab::setFocus(focus);
+
+ //When in DND mode, remove stored IM notifications
+ //Nearby chat (Null) IMs are not stored while in DND mode, so can ignore removal
+ if(focus && gAgent.isDoNotDisturb())
+ {
+ LLDoNotDisturbNotificationStorage::getInstance()->removeNotification(LLDoNotDisturbNotificationStorage::toastName, mSessionID);
+ }
+}
+
//static
bool LLFloaterIMSession::toggle(const LLUUID& session_id)
{
diff --git a/indra/newview/llfloaterimsession.h b/indra/newview/llfloaterimsession.h
index cb330bca0f..a0e0171b34 100644
--- a/indra/newview/llfloaterimsession.h
+++ b/indra/newview/llfloaterimsession.h
@@ -65,8 +65,10 @@ public:
// LLView overrides
/*virtual*/ BOOL postBuild();
+ /*virtual*/ void setMinimized(BOOL b);
/*virtual*/ void setVisible(BOOL visible);
/*virtual*/ BOOL getVisible();
+ /*virtual*/ void setFocus(BOOL focus);
// Check typing timeout timer.
/*virtual*/ void draw();
diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp
index a0f2918bd7..302d21c2e4 100644
--- a/indra/newview/llgroupactions.cpp
+++ b/indra/newview/llgroupactions.cpp
@@ -116,6 +116,80 @@ public:
};
LLGroupHandler gGroupHandler;
+// This object represents a pending request for specified group member information
+// which is needed to check whether avatar can leave group
+class LLFetchGroupMemberData : public LLGroupMgrObserver
+{
+public:
+ LLFetchGroupMemberData(const LLUUID& group_id) :
+ mGroupId(group_id),
+ mRequestProcessed(false),
+ LLGroupMgrObserver(group_id)
+ {
+ llinfos << "Sending new group member request for group_id: "<< group_id << llendl;
+ LLGroupMgr* mgr = LLGroupMgr::getInstance();
+ // register ourselves as an observer
+ mgr->addObserver(this);
+ // send a request
+ mgr->sendGroupPropertiesRequest(group_id);
+ mgr->sendCapGroupMembersRequest(group_id);
+ }
+
+ ~LLFetchGroupMemberData()
+ {
+ if (!mRequestProcessed)
+ {
+ // Request is pending
+ llwarns << "Destroying pending group member request for group_id: "
+ << mGroupId << llendl;
+ }
+ // Remove ourselves as an observer
+ LLGroupMgr::getInstance()->removeObserver(this);
+ }
+
+ void changed(LLGroupChange gc)
+ {
+ if (gc == GC_MEMBER_DATA && !mRequestProcessed)
+ {
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupId);
+ if (!gdatap)
+ {
+ llwarns << "LLGroupMgr::getInstance()->getGroupData() was NULL" << llendl;
+ }
+ else if (!gdatap->isMemberDataComplete())
+ {
+ llwarns << "LLGroupMgr::getInstance()->getGroupData()->isMemberDataComplete() was FALSE" << llendl;
+ }
+ else
+ {
+ processGroupData();
+ mRequestProcessed = true;
+ }
+ }
+ }
+
+ LLUUID getGroupId() { return mGroupId; }
+ virtual void processGroupData() = 0;
+protected:
+ LLUUID mGroupId;
+private:
+ bool mRequestProcessed;
+};
+
+class LLFetchLeaveGroupData: public LLFetchGroupMemberData
+{
+public:
+ LLFetchLeaveGroupData(const LLUUID& group_id)
+ : LLFetchGroupMemberData(group_id)
+ {}
+ void processGroupData()
+ {
+ LLGroupActions::processLeaveGroupDataResponse(mGroupId);
+ }
+};
+
+LLFetchLeaveGroupData* gFetchLeaveGroupData = NULL;
+
// static
void LLGroupActions::search()
{
@@ -208,23 +282,52 @@ bool LLGroupActions::onJoinGroup(const LLSD& notification, const LLSD& response)
void LLGroupActions::leave(const LLUUID& group_id)
{
if (group_id.isNull())
+ {
return;
+ }
- S32 count = gAgent.mGroups.count();
- S32 i;
- for (i = 0; i < count; ++i)
+ LLGroupData group_data;
+ if (gAgent.getGroupData(group_id, group_data))
{
- if(gAgent.mGroups.get(i).mID == group_id)
- break;
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id);
+ if (!gdatap || !gdatap->isMemberDataComplete())
+ {
+ if (gFetchLeaveGroupData != NULL)
+ {
+ delete gFetchLeaveGroupData;
+ gFetchLeaveGroupData = NULL;
+ }
+ gFetchLeaveGroupData = new LLFetchLeaveGroupData(group_id);
+ }
+ else
+ {
+ processLeaveGroupDataResponse(group_id);
+ }
}
- if (i < count)
+}
+
+//static
+void LLGroupActions::processLeaveGroupDataResponse(const LLUUID group_id)
+{
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id);
+ LLUUID agent_id = gAgent.getID();
+ LLGroupMgrGroupData::member_list_t::iterator mit = gdatap->mMembers.find(agent_id);
+ //get the member data for the group
+ if ( mit != gdatap->mMembers.end() )
{
- LLSD args;
- args["GROUP"] = gAgent.mGroups.get(i).mName;
- LLSD payload;
- payload["group_id"] = group_id;
- LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup);
+ LLGroupMemberData* member_data = (*mit).second;
+
+ if ( member_data && member_data->isOwner() && gdatap->mMemberCount == 1)
+ {
+ LLNotificationsUtil::add("OwnerCannotLeaveGroup");
+ return;
+ }
}
+ LLSD args;
+ args["GROUP"] = gdatap->mName;
+ LLSD payload;
+ payload["group_id"] = group_id;
+ LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup);
}
// static
diff --git a/indra/newview/llgroupactions.h b/indra/newview/llgroupactions.h
index 3f9852f194..afc4686dd7 100644
--- a/indra/newview/llgroupactions.h
+++ b/indra/newview/llgroupactions.h
@@ -114,6 +114,14 @@ public:
private:
static bool onJoinGroup(const LLSD& notification, const LLSD& response);
static bool onLeaveGroup(const LLSD& notification, const LLSD& response);
+
+ /**
+ * This function is called by LLFetchLeaveGroupData upon receiving a response to a group
+ * members data request.
+ */
+ static void processLeaveGroupDataResponse(const LLUUID group_id);
+
+ friend class LLFetchLeaveGroupData;
};
#endif // LL_LLGROUPACTIONS_H
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index e237cb7f9e..afac94af07 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -182,18 +182,19 @@ void on_new_message(const LLSD& msg)
{
conversations_floater_status = CLOSED;
}
- else if (!session_floater || !LLFloater::isVisible(session_floater)
- || session_floater->isMinimized() || !session_floater->hasFocus())
+ else if (!im_box->hasFocus() &&
+ !(session_floater && LLFloater::isVisible(session_floater)
+ && !session_floater->isMinimized() && session_floater->hasFocus()))
{
conversations_floater_status = NOT_ON_TOP;
}
- else if ((session_floater->hasFocus()) && (im_box->getSelectedSession() == session_id))
+ else if (im_box->getSelectedSession() != session_id)
{
- conversations_floater_status = ON_TOP_AND_ITEM_IS_SELECTED;
+ conversations_floater_status = ON_TOP;
}
else
{
- conversations_floater_status = ON_TOP;
+ conversations_floater_status = ON_TOP_AND_ITEM_IS_SELECTED;
}
// determine user prefs for this session
@@ -226,7 +227,7 @@ void on_new_message(const LLSD& msg)
// 0. nothing - exit
if (("none" == user_preferences ||
ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status)
- && session_floater->isMessagePaneExpanded())
+ && session_floater->isMessagePaneExpanded())
{
return;
}
@@ -2844,6 +2845,8 @@ LLUUID LLIMMgr::addSession(
//we don't need to show notes about online/offline, mute/unmute users' statuses for existing sessions
if (!new_session) return session_id;
+ llinfos << "LLIMMgr::addSession, new session added, name = " << name << ", session id = " << session_id << llendl;
+
//Per Plan's suggestion commented "explicit offline status warning" out to make Dessie happier (see EXT-3609)
//*TODO After February 2010 remove this commented out line if no one will be missing that warning
//noteOfflineUsers(session_id, floater, ids);
@@ -2879,6 +2882,8 @@ void LLIMMgr::removeSession(const LLUUID& session_id)
LLIMModel::getInstance()->clearSession(session_id);
+ llinfos << "LLIMMgr::removeSession, session removed, session id = " << session_id << llendl;
+
notifyObserverSessionRemoved(session_id);
}
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 2d7454b636..82409da4ba 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -631,7 +631,7 @@ void LLLogChat::deleteTranscripts()
}
// static
-bool LLLogChat::isTranscriptExist(const LLUUID& avatar_id)
+bool LLLogChat::isTranscriptExist(const LLUUID& avatar_id, bool is_group)
{
std::vector<std::string> list_of_transcriptions;
LLLogChat::getListOfTranscriptFiles(list_of_transcriptions);
@@ -641,15 +641,31 @@ bool LLLogChat::isTranscriptExist(const LLUUID& avatar_id)
LLAvatarName avatar_name;
LLAvatarNameCache::get(avatar_id, &avatar_name);
std::string avatar_user_name = avatar_name.getAccountName();
- std::replace(avatar_user_name.begin(), avatar_user_name.end(), '.', '_');
-
- BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)
+ if(!is_group)
{
- if (std::string::npos != transcript_file_name.find(avatar_user_name))
+ std::replace(avatar_user_name.begin(), avatar_user_name.end(), '.', '_');
+ BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)
{
- return true;
+ if (std::string::npos != transcript_file_name.find(avatar_user_name))
+ {
+ return true;
+ }
}
}
+ else
+ {
+ std::string file_name;
+ gCacheName->getGroupName(avatar_id, file_name);
+ file_name = makeLogFileName(file_name);
+ BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)
+ {
+ if (transcript_file_name == file_name)
+ {
+ return true;
+ }
+ }
+ }
+
}
return false;
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index e819f00dd9..77bb2a1570 100644
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -67,7 +67,7 @@ public:
std::vector<std::string>& listOfFilesToMove);
static void deleteTranscripts();
- static bool isTranscriptExist(const LLUUID& avatar_id);
+ static bool isTranscriptExist(const LLUUID& avatar_id, bool is_group=false);
private:
static std::string cleanFileName(std::string filename);
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 4138558bad..2ca22a1382 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -63,19 +63,25 @@
#include "llviewermenu.h" // for gMenuHolder
#include "llvoiceclient.h"
#include "llworld.h"
+#include "llsociallist.h"
#include "llspeakers.h"
+#include "llfloaterwebcontent.h"
#define FRIEND_LIST_UPDATE_TIMEOUT 0.5
#define NEARBY_LIST_UPDATE_INTERVAL 1
+#define FBCTEST_LIST_UPDATE_INTERVAL 0.25
static const std::string NEARBY_TAB_NAME = "nearby_panel";
static const std::string FRIENDS_TAB_NAME = "friends_panel";
static const std::string GROUP_TAB_NAME = "groups_panel";
static const std::string RECENT_TAB_NAME = "recent_panel";
static const std::string BLOCKED_TAB_NAME = "blocked_panel"; // blocked avatars
-
+static const std::string FBCTEST_TAB_NAME = "fbctest_panel";
static const std::string COLLAPSED_BY_USER = "collapsed_by_user";
+static const std::string FBC_SERVICES_URL = "https://pdp15.lindenlab.com";
+static const std::string FBC_SERVICES_REDIRECT_URI = "http://axcho.com/secondlife/";
+
/** Comparator for comparing avatar items by last interaction date */
class LLAvatarItemRecentComparator : public LLAvatarItemComparator
{
@@ -489,10 +495,51 @@ public:
}
};
+/**
+ * Periodically updates the FBC test list after a login is initiated.
+ *
+ * The period is defined by FBCTEST_LIST_UPDATE_INTERVAL constant.
+ */
+class LLFbcTestListUpdater : public LLAvatarListUpdater
+{
+ LOG_CLASS(LLFbcTestListUpdater);
+
+public:
+ LLFbcTestListUpdater(callback_t cb)
+ : LLAvatarListUpdater(cb, FBCTEST_LIST_UPDATE_INTERVAL)
+ {
+ setActive(false);
+ }
+
+ /*virtual*/ void setActive(bool val)
+ {
+ if (val)
+ {
+ // update immediately and start regular updates
+ update();
+ mEventTimer.start();
+ }
+ else
+ {
+ // stop regular updates
+ mEventTimer.stop();
+ }
+ }
+
+ /*virtual*/ BOOL tick()
+ {
+ update();
+ return FALSE;
+ }
+private:
+};
+
//=============================================================================
LLPanelPeople::LLPanelPeople()
: LLPanel(),
+ mConnectedToFbc(false),
+ mTryToConnectToFbc(true),
mTabContainer(NULL),
mOnlineFriendList(NULL),
mAllFriendList(NULL),
@@ -504,8 +551,14 @@ LLPanelPeople::LLPanelPeople()
mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this));
mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this));
mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this));
+ mFbcTestListUpdater = new LLFbcTestListUpdater(boost::bind(&LLPanelPeople::updateFbcTestList, this));
mButtonsUpdater = new LLButtonsUpdater(boost::bind(&LLPanelPeople::updateButtons, this));
+ mCommitCallbackRegistrar.add("People.loginFBC", boost::bind(&LLPanelPeople::onLoginFbcButtonClicked, this));
+ mCommitCallbackRegistrar.add("People.requestFBC", boost::bind(&LLPanelPeople::onFacebookAppRequestClicked, this));
+ mCommitCallbackRegistrar.add("People.sendFBC", boost::bind(&LLPanelPeople::onFacebookAppSendClicked, this));
+
+
mCommitCallbackRegistrar.add("People.AddFriend", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this));
mCommitCallbackRegistrar.add("People.AddFriendWizard", boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this));
mCommitCallbackRegistrar.add("People.DelFriend", boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this));
@@ -532,11 +585,14 @@ LLPanelPeople::~LLPanelPeople()
delete mNearbyListUpdater;
delete mFriendListUpdater;
delete mRecentListUpdater;
+ delete mFbcTestListUpdater;
if(LLVoiceClient::instanceExists())
{
LLVoiceClient::getInstance()->removeObserver(this);
}
+
+ if (mFbcTestBrowserHandle.get()) mFbcTestBrowserHandle.get()->die();
}
void LLPanelPeople::onFriendsAccordionExpandedCollapsed(LLUICtrl* ctrl, const LLSD& param, LLAvatarList* avatar_list)
@@ -616,6 +672,10 @@ BOOL LLPanelPeople::postBuild()
mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
+ LLPanel * social_tab = getChild<LLPanel>(FBCTEST_TAB_NAME);
+ mFacebookFriends = social_tab->getChild<LLSocialList>("facebook_friends");
+ social_tab->setVisibleCallback(boost::bind(&Updater::setActive, mFbcTestListUpdater, _2));
+
setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false);
setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false);
setSortOrder(mNearbyList, (ESortOrder)gSavedSettings.getU32("NearbyPeopleSortOrder"), false);
@@ -664,6 +724,15 @@ BOOL LLPanelPeople::postBuild()
// Must go after setting commit callback and initializing all pointers to children.
mTabContainer->selectTabByName(NEARBY_TAB_NAME);
+ mFBCGearButton = getChild<LLMenuButton>("fbc_options_btn");
+
+ LLToggleableMenu* fbc_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_gear_fbc.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ if(fbc_menu)
+ {
+ mFBCMenuHandle = fbc_menu->getHandle();
+ mFBCGearButton->setMenu(fbc_menu);
+ }
+
LLVoiceClient::getInstance()->addObserver(this);
// call this method in case some list is empty and buttons can be in inconsistent state
@@ -786,6 +855,57 @@ void LLPanelPeople::updateRecentList()
mRecentList->setDirty();
}
+void LLPanelPeople::updateFbcTestList()
+{
+ if (mFbcTestBrowserHandle.get())
+ {
+ // get the current browser url (from the title bar, of course!)
+ std::string url = mFbcTestBrowserHandle.get()->getTitle();
+
+ // if the browser has redirected from facebook
+ if (url.find(FBC_SERVICES_REDIRECT_URI) == 0)
+ {
+ // find the auth code in the url
+ std::string begin_string = "code=";
+ std::string end_string = "#";
+ size_t begin_index = begin_string.length() + url.find(begin_string, FBC_SERVICES_REDIRECT_URI.length());
+ size_t end_index = url.find(end_string, begin_index);
+
+ // extract the auth code from the url
+ std::string auth_code;
+ if (end_index != std::string::npos)
+ {
+ auth_code = url.substr(begin_index, end_index - begin_index);
+ }
+ else
+ {
+ auth_code = url.substr(begin_index);
+ }
+ llinfos << "extracted code " << auth_code << " from url " << url << llendl;
+
+ // finish authenticating on the server
+ connectToFacebook(auth_code);
+
+ // close the browser window
+ mFbcTestBrowserHandle.get()->die();
+
+ // stop updating
+ mFbcTestListUpdater->setActive(false);
+ }
+ }
+ else if (mTryToConnectToFbc)
+ {
+ // try to reconnect to facebook!
+ tryToReconnectToFacebook();
+
+ // don't try again
+ mTryToConnectToFbc = false;
+
+ // stop updating
+ mFbcTestListUpdater->setActive(false);
+ }
+}
+
void LLPanelPeople::updateButtons()
{
std::string cur_tab = getActiveTabName();
@@ -870,6 +990,9 @@ LLUUID LLPanelPeople::getCurrentItemID() const
if (cur_tab == BLOCKED_TAB_NAME)
return LLUUID::null; // FIXME?
+
+ if (cur_tab == FBCTEST_TAB_NAME)
+ return LLUUID::null;
llassert(0 && "unknown tab selected");
return LLUUID::null;
@@ -893,6 +1016,8 @@ void LLPanelPeople::getCurrentItemIDs(uuid_vec_t& selected_uuids) const
mGroupList->getSelectedUUIDs(selected_uuids);
else if (cur_tab == BLOCKED_TAB_NAME)
selected_uuids.clear(); // FIXME?
+ else if (cur_tab == FBCTEST_TAB_NAME)
+ return;
else
llassert(0 && "unknown tab selected");
@@ -1225,7 +1350,7 @@ void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata)
mAllFriendList->showPermissions(show_permissions);
mOnlineFriendList->showPermissions(show_permissions);
}
-}
+ }
void LLPanelPeople::onGroupsViewSortMenuItemClicked(const LLSD& userdata)
{
@@ -1446,4 +1571,216 @@ bool LLPanelPeople::isAccordionCollapsedByUser(const std::string& name)
return isAccordionCollapsedByUser(getChild<LLUICtrl>(name));
}
+void LLPanelPeople::openFacebookWeb(LLFloaterWebContent::Params& p)
+{
+ LLFloater* browser = LLFloaterReg::showInstance("web_content", p);
+
+ if (browser)
+ {
+ // start checking the browser to see if the data is available yet
+ mFbcTestBrowserHandle = browser->getHandle();
+ mFbcTestListUpdater->setActive(true);
+ }
+}
+
+void LLPanelPeople::showFacebookFriends(const LLSD& friends)
+{
+ mFacebookFriends->clear();
+
+ for (LLSD::array_const_iterator i = friends.beginArray(); i != friends.endArray(); ++i)
+ {
+ std::string name = (*i)["name"].asString();
+ LLUUID agent_id = (*i).has("agent_id") ? (*i)["agent_id"].asUUID() : LLUUID(NULL);
+
+ mFacebookFriends->addNewItem(agent_id, name, false);
+ }
+}
+
+void LLPanelPeople::hideFacebookFriends()
+{
+ mFacebookFriends->clear();
+}
+
+class FacebookConnectResponder : public LLHTTPClient::Responder
+{
+public:
+
+ LLPanelPeople * mPanelPeople;
+
+ FacebookConnectResponder(LLPanelPeople * panel_people) : mPanelPeople(panel_people) {}
+
+ /*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (isGoodStatus(status))
+ {
+ llinfos << content << llendl;
+
+ // grab some graph data now that we are connected
+ if (content["success"])
+ {
+ mPanelPeople->mConnectedToFbc = true;
+ mPanelPeople->loadFacebookFriends();
+ }
+ else if (content.has("error"))
+ {
+ llinfos << "failed to connect. reason: " << content["error"]["message"] << llendl;
+ }
+ }
+ else
+ {
+ llinfos << "failed to get response. reason: " << reason << " status: " << status << llendl;
+ }
+ }
+};
+
+class FacebookDisconnectResponder : public LLHTTPClient::Responder
+{
+public:
+
+ LLPanelPeople * mPanelPeople;
+
+ FacebookDisconnectResponder(LLPanelPeople * panel_people) : mPanelPeople(panel_people) {}
+
+ /*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (isGoodStatus(status))
+ {
+ llinfos << content << llendl;
+
+ // hide all the facebook stuff
+ if (content["success"])
+ {
+ mPanelPeople->mConnectedToFbc = false;
+ mPanelPeople->hideFacebookFriends();
+ }
+ else if (content.has("error"))
+ {
+ llinfos << "failed to disconnect. reason: " << content["error"]["message"] << llendl;
+ }
+ }
+ else
+ {
+ llinfos << "failed to get response. reason: " << reason << " status: " << status << llendl;
+ }
+ }
+};
+
+class FacebookConnectedResponder : public LLHTTPClient::Responder
+{
+public:
+
+ LLPanelPeople * mPanelPeople;
+ bool mShowLoginIfNotConnected;
+
+ FacebookConnectedResponder(LLPanelPeople * panel_people, bool show_login_if_not_connected) : mPanelPeople(panel_people), mShowLoginIfNotConnected(show_login_if_not_connected) {}
+
+ /*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (isGoodStatus(status))
+ {
+ llinfos << content << llendl;
+
+ // grab some graph data if already connected
+ if (content["connected"])
+ {
+ mPanelPeople->mConnectedToFbc = true;
+ mPanelPeople->loadFacebookFriends();
+ }
+ // show the facebook login page if not connected yet
+ else if (mShowLoginIfNotConnected)
+ {
+ LLFloaterWebContent::Params p;
+ p.url("https://www.facebook.com/dialog/oauth?client_id=565771023434202&redirect_uri=" + FBC_SERVICES_REDIRECT_URI);
+ mPanelPeople->openFacebookWeb(p);
+ }
+ }
+ else
+ {
+ llinfos << "failed to get response. reason: " << reason << " status: " << status << llendl;
+ }
+ }
+};
+
+class FacebookFriendsResponder : public LLHTTPClient::Responder
+{
+public:
+
+ LLPanelPeople * mPanelPeople;
+
+ FacebookFriendsResponder(LLPanelPeople * panel_people) : mPanelPeople(panel_people) {}
+
+ /*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (isGoodStatus(status))
+ {
+ llinfos << content << llendl;
+
+ // display the list of friends
+ if (content.has("friends"))
+ {
+ mPanelPeople->showFacebookFriends(content["friends"]);
+ }
+ else if (content.has("error"))
+ {
+ llinfos << "failed to get facebook friends. reason: " << content["error"]["message"] << llendl;
+ }
+ }
+ else
+ {
+ llinfos << "failed to get response. reason: " << reason << " status: " << status << llendl;
+ }
+ }
+};
+
+void LLPanelPeople::loadFacebookFriends()
+{
+ LLHTTPClient::get(FBC_SERVICES_URL + "/agent/" + gAgentID.asString() + "/fbc/friends", new FacebookFriendsResponder(this));
+}
+
+void LLPanelPeople::tryToReconnectToFacebook()
+{
+ if (!mConnectedToFbc)
+ {
+ LLHTTPClient::get(FBC_SERVICES_URL + "/agent/" + gAgentID.asString() + "/fbc/connected", new FacebookConnectedResponder(this, false));
+ }
+}
+
+void LLPanelPeople::connectToFacebook(const std::string& auth_code)
+{
+ LLSD body;
+ body["code"] = auth_code;
+ body["redirect_uri"] = FBC_SERVICES_REDIRECT_URI;
+ LLHTTPClient::post(FBC_SERVICES_URL + "/agent/" + gAgentID.asString() + "/fbc/connect", body, new FacebookConnectResponder(this));
+}
+
+void LLPanelPeople::disconnectFromFacebook()
+{
+ LLHTTPClient::post(FBC_SERVICES_URL + "/agent/" + gAgentID.asString() + "/fbc/disconnect", LLSD(), new FacebookDisconnectResponder(this));
+}
+
+void LLPanelPeople::onLoginFbcButtonClicked()
+{
+ if (mConnectedToFbc)
+ {
+ disconnectFromFacebook();
+ }
+ else
+ {
+ LLHTTPClient::get(FBC_SERVICES_URL + "/agent/" + gAgentID.asString() + "/fbc/connected", new FacebookConnectedResponder(this, true));
+ }
+}
+
+void LLPanelPeople::onFacebookAppRequestClicked()
+{
+ LLFloaterWebContent::Params p;
+ p.url("http://www.facebook.com/dialog/apprequests?app_id=565771023434202&message=Test&redirect_uri=" + FBC_SERVICES_URL);
+ openFacebookWeb(p);
+}
+
+void LLPanelPeople::onFacebookAppSendClicked()
+{
+ LLFloaterWebContent::Params p;
+ p.url("https://www.facebook.com/dialog/send?app_id=565771023434202&name=Join Second Life!&link=https://join.secondlife.com&redirect_uri=" + FBC_SERVICES_URL);
+ openFacebookWeb(p);
+}
// EOF
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index 4740964dee..ffb3f74192 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -30,12 +30,15 @@
#include <llpanel.h>
#include "llcallingcard.h" // for avatar tracker
+#include "llfloaterwebcontent.h"
#include "llvoiceclient.h"
class LLAvatarList;
+class LLAvatarListSocial;
class LLAvatarName;
class LLFilterEditor;
class LLGroupList;
+class LLSocialList;
class LLMenuButton;
class LLTabContainer;
@@ -55,6 +58,17 @@ public:
// when voice is available
/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+ void openFacebookWeb(LLFloaterWebContent::Params& p);
+ void showFacebookFriends(const LLSD& friends);
+ void hideFacebookFriends();
+ void loadFacebookFriends();
+ void tryToReconnectToFacebook();
+ void connectToFacebook(const std::string& auth_code);
+ void disconnectFromFacebook();
+
+ bool mConnectedToFbc;
+ bool mTryToConnectToFbc;
+
// internals
class Updater;
@@ -75,6 +89,7 @@ private:
void updateFriendList();
void updateNearbyList();
void updateRecentList();
+ void updateFbcTestList();
bool isItemsFreeOfFriends(const uuid_vec_t& uuids);
@@ -106,6 +121,10 @@ private:
void onGroupsViewSortMenuItemClicked(const LLSD& userdata);
void onRecentViewSortMenuItemClicked(const LLSD& userdata);
+ void onLoginFbcButtonClicked();
+ void onFacebookAppRequestClicked();
+ void onFacebookAppSendClicked();
+
bool onFriendsViewSortMenuItemCheck(const LLSD& userdata);
bool onRecentViewSortMenuItemCheck(const LLSD& userdata);
bool onNearbyViewSortMenuItemCheck(const LLSD& userdata);
@@ -132,15 +151,20 @@ private:
LLAvatarList* mNearbyList;
LLAvatarList* mRecentList;
LLGroupList* mGroupList;
+ LLSocialList* mFacebookFriends;
LLNetMap* mMiniMap;
std::vector<std::string> mSavedOriginalFilters;
std::vector<std::string> mSavedFilters;
+ LLHandle<LLView> mFBCMenuHandle;
+ LLHandle<LLFloater> mFbcTestBrowserHandle;
Updater* mFriendListUpdater;
Updater* mNearbyListUpdater;
Updater* mRecentListUpdater;
+ Updater* mFbcTestListUpdater;
Updater* mButtonsUpdater;
+ LLMenuButton* mFBCGearButton;
LLHandle< LLFloater > mPicker;
};
diff --git a/indra/newview/llsociallist.cpp b/indra/newview/llsociallist.cpp
new file mode 100644
index 0000000000..bcf6d5a63c
--- /dev/null
+++ b/indra/newview/llsociallist.cpp
@@ -0,0 +1,155 @@
+sDestroyImmediate
+/**
+* @file llsociallist.cpp
+* @brief Implementation of llsociallist
+* @author Gilbert@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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 "llsociallist.h"
+
+#include "llavataractions.h"
+#include "llfloaterreg.h"
+#include "llavatariconctrl.h"
+#include "llavatarnamecache.h"
+#include "lloutputmonitorctrl.h"
+#include "lltextutil.h"
+
+static LLDefaultChildRegistry::Register<LLSocialList> r("social_list");
+
+LLSocialList::LLSocialList(const Params&p) : LLFlatListViewEx(p)
+{
+
+}
+
+LLSocialList::~LLSocialList()
+{
+
+}
+
+void LLSocialList::draw()
+{
+ LLFlatListView::draw();
+}
+
+void LLSocialList::refresh()
+{
+
+}
+
+void LLSocialList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_online, EAddPosition pos)
+{
+ LLSocialListItem * item = new LLSocialListItem();
+ LLAvatarName avatar_name;
+ bool has_avatar_name = id.notNull() && LLAvatarNameCache::get(id, &avatar_name);
+
+ item->mAvatarId = id;
+ if(id.notNull())
+ {
+ item->mIcon->setValue(id);
+ }
+
+ item->setName(has_avatar_name ? name + " (" + avatar_name.getDisplayName() + ")" : name, mNameFilter);
+ addItem(item, id, pos);
+}
+
+LLSocialListItem::LLSocialListItem()
+{
+ buildFromFile("panel_avatar_list_item.xml");
+}
+
+LLSocialListItem::~LLSocialListItem()
+{
+
+}
+
+BOOL LLSocialListItem::postBuild()
+{
+ mIcon = getChild<LLAvatarIconCtrl>("avatar_icon");
+ mLabelTextBox = getChild<LLTextBox>("avatar_name");
+
+ mLastInteractionTime = getChild<LLTextBox>("last_interaction");
+ mIconPermissionOnline = getChild<LLIconCtrl>("permission_online_icon");
+ mIconPermissionMap = getChild<LLIconCtrl>("permission_map_icon");
+ mIconPermissionEditMine = getChild<LLIconCtrl>("permission_edit_mine_icon");
+ mIconPermissionEditTheirs = getChild<LLIconCtrl>("permission_edit_theirs_icon");
+ mSpeakingIndicator = getChild<LLOutputMonitorCtrl>("speaking_indicator");
+ mInfoBtn = getChild<LLButton>("info_btn");
+ mProfileBtn = getChild<LLButton>("profile_btn");
+
+ mLastInteractionTime->setVisible(false);
+ mIconPermissionOnline->setVisible(false);
+ mIconPermissionMap->setVisible(false);
+ mIconPermissionEditMine->setVisible(false);
+ mIconPermissionEditTheirs->setVisible(false);
+ mSpeakingIndicator->setVisible(false);
+ mInfoBtn->setVisible(false);
+ mProfileBtn->setVisible(false);
+
+ mInfoBtn->setClickedCallback(boost::bind(&LLSocialListItem::onInfoBtnClick, this));
+ mProfileBtn->setClickedCallback(boost::bind(&LLSocialListItem::onProfileBtnClick, this));
+
+ return TRUE;
+}
+
+void LLSocialListItem::setName(const std::string& name, const std::string& highlight)
+{
+ mLabel = name;
+ LLTextUtil::textboxSetHighlightedVal(mLabelTextBox, mLabelTextBoxStyle, name, highlight);
+}
+
+void LLSocialListItem::setValue(const LLSD& value)
+{
+ getChildView("selected_icon")->setVisible( value["selected"]);
+}
+
+void LLSocialListItem::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ getChildView("hovered_icon")->setVisible( true);
+ mInfoBtn->setVisible(true);
+ mProfileBtn->setVisible(true);
+
+ LLPanel::onMouseEnter(x, y, mask);
+}
+
+void LLSocialListItem::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ getChildView("hovered_icon")->setVisible( false);
+ mInfoBtn->setVisible(false);
+ mProfileBtn->setVisible(false);
+
+ LLPanel::onMouseLeave(x, y, mask);
+}
+
+void LLSocialListItem::onInfoBtnClick()
+{
+ LLFloaterReg::showInstance("inspect_avatar", LLSD().with("avatar_id", mAvatarId));
+}
+
+void LLSocialListItem::onProfileBtnClick()
+{
+ LLAvatarActions::showProfile(mAvatarId);
+}
diff --git a/indra/newview/llsociallist.h b/indra/newview/llsociallist.h
new file mode 100644
index 0000000000..bc667fc400
--- /dev/null
+++ b/indra/newview/llsociallist.h
@@ -0,0 +1,102 @@
+/**
+* @file llsociallist.h
+* @brief Header file for llsociallist
+* @author Gilbert@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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$
+*/
+#ifndef LL_LLSOCIALLIST_H
+#define LL_LLSOCIALLIST_H
+
+#include "llflatlistview.h"
+#include "llstyle.h"
+
+
+/**
+ * Generic list of avatars.
+ *
+ * Updates itself when it's dirty, using optional name filter.
+ * To initiate update, modify the UUID list and call setDirty().
+ *
+ * @see getIDs()
+ * @see setDirty()
+ * @see setNameFilter()
+ */
+
+class LLAvatarIconCtrl;
+class LLIconCtrl;
+class LLOutputMonitorCtrl;
+
+class LLSocialList : public LLFlatListViewEx
+{
+public:
+
+ struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params>
+ {
+ };
+
+ LLSocialList(const Params&p);
+ virtual ~LLSocialList();
+
+ virtual void draw();
+ void refresh();
+ void addNewItem(const LLUUID& id, const std::string& name, BOOL is_online, EAddPosition pos = ADD_BOTTOM);
+
+
+
+ std::string mNameFilter;
+};
+
+class LLSocialListItem : public LLPanel
+{
+ public:
+ LLSocialListItem();
+ ~LLSocialListItem();
+
+ BOOL postBuild();
+ void setName(const std::string& name, const std::string& highlight = LLStringUtil::null);
+ void setValue(const LLSD& value);
+ void onMouseEnter(S32 x, S32 y, MASK mask);
+ void onMouseLeave(S32 x, S32 y, MASK mask);
+ void onInfoBtnClick();
+ void onProfileBtnClick();
+
+ LLUUID mAvatarId;
+
+ LLTextBox * mLabelTextBox;
+ std::string mLabel;
+ LLStyle::Params mLabelTextBoxStyle;
+
+
+ LLAvatarIconCtrl * mIcon;
+ LLTextBox * mLastInteractionTime;
+ LLIconCtrl * mIconPermissionOnline;
+ LLIconCtrl * mIconPermissionMap;
+ LLIconCtrl * mIconPermissionEditMine;
+ LLIconCtrl * mIconPermissionEditTheirs;
+ LLOutputMonitorCtrl * mSpeakingIndicator;
+ LLButton * mInfoBtn;
+ LLButton * mProfileBtn;
+};
+
+
+#endif // LL_LLSOCIALLIST_H
diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp
index 75e6e3d13a..025ef3945d 100644
--- a/indra/newview/lltoastimpanel.cpp
+++ b/indra/newview/lltoastimpanel.cpp
@@ -28,6 +28,7 @@
#include "lltoastimpanel.h"
#include "llagent.h"
+#include "llavatarnamecache.h"
#include "llfloaterreg.h"
#include "llgroupactions.h"
#include "llgroupiconctrl.h"
@@ -61,6 +62,15 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notif
style_params.font.name(font_name);
style_params.font.size(font_size);
+ LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(p.session_id);
+ mIsGroupMsg = (im_session->mSessionType == LLIMModel::LLIMSession::GROUP_SESSION);
+ if(mIsGroupMsg)
+ {
+ mAvatarName->setValue(im_session->mName);
+ LLAvatarName avatar_name;
+ LLAvatarNameCache::get(p.avatar_id, &avatar_name);
+ p.message = "[From " + avatar_name.getDisplayName() + "]\n" + p.message;
+ }
//Handle IRC styled /me messages.
std::string prefix = p.message.substr(0, 4);
@@ -81,12 +91,17 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notif
mMessage->setText(p.message, style_params);
}
- mAvatarName->setValue(p.from);
+ if(!mIsGroupMsg)
+ {
+ mAvatarName->setValue(p.from);
+ }
mTime->setValue(p.time);
mSessionID = p.session_id;
mAvatarID = p.avatar_id;
mNotification = p.notification;
+
+
initIcon();
S32 maxLinesCount;
@@ -147,7 +162,14 @@ void LLToastIMPanel::spawnNameToolTip()
LLToolTip::Params params;
params.background_visible(false);
- params.click_callback(boost::bind(&LLFloaterReg::showInstance, "inspect_avatar", LLSD().with("avatar_id", mAvatarID), FALSE));
+ if(!mIsGroupMsg)
+ {
+ params.click_callback(boost::bind(&LLFloaterReg::showInstance, "inspect_avatar", LLSD().with("avatar_id", mAvatarID), FALSE));
+ }
+ else
+ {
+ params.click_callback(boost::bind(&LLFloaterReg::showInstance, "inspect_group", LLSD().with("group_id", mSessionID), FALSE));
+ }
params.delay_time(0.0f); // spawn instantly on hover
params.image(LLUI::getUIImage("Info_Small"));
params.message("");
diff --git a/indra/newview/lltoastimpanel.h b/indra/newview/lltoastimpanel.h
index 3eb11fb3bc..767617dabc 100644
--- a/indra/newview/lltoastimpanel.h
+++ b/indra/newview/lltoastimpanel.h
@@ -73,6 +73,8 @@ private:
LLTextBox* mAvatarName;
LLTextBox* mTime;
LLTextBox* mMessage;
+
+ bool mIsGroupMsg;
};
#endif // LLTOASTIMPANEL_H_
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 66db0ac8f3..ab1788d1cb 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -8283,8 +8283,6 @@ void initialize_menus()
view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts");
-
- commit.add("Inventory.NewWindow", boost::bind(&LLFloaterInventory::showAgentInventory));
enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed));
// Agent
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 4afd90b44c..be508ad17d 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1798,9 +1798,7 @@ void LLViewerWindow::initBase()
// Constrain floaters to inside the menu and status bar regions.
gFloaterView = main_view->getChild<LLFloaterView>("Floater View");
- gFloaterView->setFloaterSnapView(main_view->getChild<LLView>("floater_snap_region")->getHandle());
gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View");
-
// Console
llassert( !gConsole );
diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml
index 3b56e974d2..08ecc37d21 100644
--- a/indra/newview/skins/default/xui/en/floater_im_session.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_session.xml
@@ -70,23 +70,27 @@
top="0"
left="0"
right="-1"
- bottom="-1">
+ bottom="-3">
<layout_stack
animate="false"
default_tab_group="2"
follows="all"
right="-5"
bottom="-1"
+ top="0"
+ left="3"
+ border_size="0"
layout="topleft"
orientation="vertical"
name="main_stack"
- tab_group="1"
- top="0"
- left="5">
+ tab_group="1">
<layout_panel
auto_resize="false"
+ user_resize="false"
name="toolbar_panel"
- height="35">
+ height="35"
+ right="-1"
+ left="1">
<menu_button
menu_filename="menu_im_session_showmodes.xml"
follows="top|left"
@@ -164,7 +168,7 @@
image_unselected="Toolbar_Middle_Off"
layout="topleft"
top="5"
- right="-70"
+ right="-67"
name="close_btn"
tool_tip="End this conversation"
width="31" />
@@ -196,7 +200,10 @@
</layout_panel>
<layout_panel
name="body_panel"
- height="235">
+ top="1"
+ bottom="-1"
+ auto_resize="true"
+ user_resize="false">
<layout_stack
default_tab_group="2"
follows="all"
@@ -213,12 +220,14 @@
min_dim="0"
width="150"
user_resize="true"
- auto_resize="false" />
+ auto_resize="false"
+ bottom="-1" />
<layout_panel
default_tab_group="3"
tab_group="2"
name="right_part_holder"
- min_width="221">
+ min_width="221"
+ bottom="-1">
<layout_stack
animate="true"
default_tab_group="2"
@@ -262,21 +271,29 @@
</layout_stack>
</layout_panel>
<layout_panel
- height="35"
+ top_delta="0"
+ top="0"
+ height="26"
+ bottom="-1"
auto_resize="false"
+ user_resize="false"
name="chat_layout_panel">
<layout_stack
animate="false"
default_tab_group="2"
follows="all"
- right="-1"
orientation="horizontal"
name="input_panels"
top="0"
- bottom="-1"
- left="0">
+ bottom="-2"
+ left="0"
+ right="-1">
<layout_panel
- name="input_editor_layout_panel">
+ name="input_editor_layout_panel"
+ auto_resize="true"
+ user_resize="false"
+ top="0"
+ bottom="-1">
<chat_editor
layout="topleft"
expand_lines_count="5"
@@ -289,27 +306,32 @@
max_length="1023"
spellcheck="true"
tab_group="3"
- bottom="-8"
- left="5"
- right="-5"
+ top="1"
+ bottom="-2"
+ left="4"
+ right="-4"
wrap="true" />
</layout_panel>
<layout_panel
auto_resize="false"
+ user_resize="false"
name="input_button_layout_panel"
- width="32">
+ width="30"
+ top="0"
+ bottom="-1">
<button
+ layout="topleft"
left="1"
- top="4"
+ right="-1"
+ top="1"
+ height="22"
follows="left|right|top"
- height="25"
image_hover_unselected="Toolbar_Middle_Over"
image_overlay="Conv_expand_one_line"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
name="minz_btn"
- tool_tip="Shows/hides message panel"
- width="28" />
+ tool_tip="Shows/hides message panel" />
</layout_panel>
</layout_stack>
</layout_panel>
diff --git a/indra/newview/skins/default/xui/en/menu_gear_fbc.xml b/indra/newview/skins/default/xui/en/menu_gear_fbc.xml
new file mode 100644
index 0000000000..b05ba46107
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_gear_fbc.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ name="menu_group_plus"
+ left="0" bottom="0" visible="false"
+ mouse_opaque="false">
+ <menu_item_check
+ label="Facebook App Settings"
+ layout="topleft"
+ name="Facebook App Settings">
+ <menu_item_check.on_click
+ function="Advanced.WebContentTest"
+ parameter="http://www.facebook.com/settings?tab=applications" />
+ </menu_item_check>
+ <menu_item_check
+ label="Facebook App Request"
+ layout="topleft"
+ name="Facebook App Request">
+ <menu_item_check.on_click
+ function="People.requestFBC"
+ parameter="http://www.facebook.com/settings?tab=applications" />
+ </menu_item_check>
+ <menu_item_check
+ label="Facebook App Send"
+ layout="topleft"
+ name="Facebook App Send">
+ <menu_item_check.on_click
+ function="People.sendFBC"
+ parameter="http://www.facebook.com/settings?tab=applications" />
+ </menu_item_check>
+</toggleable_menu> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml
index 101e104eab..52c4fb1613 100644
--- a/indra/newview/skins/default/xui/en/menu_login.xml
+++ b/indra/newview/skins/default/xui/en/menu_login.xml
@@ -180,7 +180,8 @@
name="Set Logging Level"
tear_off="true">
<menu_item_check
- label="Debug">
+ name="Debug"
+ label="Debug">
<menu_item_check.on_check
function="Develop.CheckLoggingLevel"
parameter="0" />
@@ -189,7 +190,8 @@
parameter="0" />
</menu_item_check>
<menu_item_check
- label="Info">
+ name="Info"
+ label="Info">
<menu_item_check.on_check
function="Develop.CheckLoggingLevel"
parameter="1" />
@@ -198,7 +200,8 @@
parameter="1" />
</menu_item_check>
<menu_item_check
- label="Warning">
+ name="Warning"
+ label="Warning">
<menu_item_check.on_check
function="Develop.CheckLoggingLevel"
parameter="2" />
@@ -207,7 +210,8 @@
parameter="2" />
</menu_item_check>
<menu_item_check
- label="Error">
+ name="Error"
+ label="Error">
<menu_item_check.on_check
function="Develop.CheckLoggingLevel"
parameter="3" />
@@ -216,7 +220,8 @@
parameter="3" />
</menu_item_check>
<menu_item_check
- label="None">
+ name="None"
+ label="None">
<menu_item_check.on_check
function="Develop.CheckLoggingLevel"
parameter="4" />
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 544f06ac0c..39e777b246 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -131,6 +131,7 @@
name="Status"
tear_off="true">
<menu_item_check
+ name="Away"
label="Away">
<menu_item_check.on_check
function="View.Status.CheckAway" />
@@ -138,6 +139,7 @@
function="World.SetAway" />
</menu_item_check>
<menu_item_check
+ name="Do Not Disturb"
label="Do Not Disturb">
<menu_item_check.on_check
function="View.Status.CheckDoNotDisturb" />
@@ -257,6 +259,7 @@
parameter="speak" />
</menu_item_check>
<menu_item_check
+ name="Conversation Log..."
label="Conversation Log...">
<menu_item_check.on_check
function="Floater.Visible"
@@ -352,6 +355,7 @@
</menu_item_call>
<menu_item_separator/>
<menu_item_check
+ name="Do Not Disturb"
label="Do Not Disturb">
<menu_item_check.on_check
function="View.Status.CheckDoNotDisturb" />
@@ -3014,6 +3018,13 @@
parameter="http://google.com"/>
</menu_item_call>
<menu_item_call
+ label="FB Connect Test"
+ name="FB Connect Test">
+ <menu_item_call.on_click
+ function="Advanced.WebContentTest"
+ parameter="https://cryptic-ridge-1632.herokuapp.com/"/>
+ </menu_item_call>
+ <menu_item_call
label="Dump SelectMgr"
name="Dump SelectMgr">
<menu_item_call.on_click
@@ -3051,13 +3062,6 @@
<menu_item_call.on_click
function="Advanced.PrintAgentInfo" />
</menu_item_call>
- <menu_item_call
- label="Memory Stats"
- name="Memory Stats"
- shortcut="control|alt|shift|M">
- <menu_item_call.on_click
- function="Advanced.PrintTextureMemoryStats" />
- </menu_item_call>
<menu_item_check
label="Region Debug Console"
name="Region Debug Console"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 105bef7321..49e2ddfb14 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -3649,6 +3649,17 @@ Leave Group?
</notification>
<notification
+ icon="alertmodal.tga"
+ name="OwnerCannotLeaveGroup"
+ type="alertmodal">
+ Unable to leave group. You cannot leave the group because you are the last owner of the group. Please assign another member to the owner role first.
+ <tag>group</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
icon="alert.tga"
name="ConfirmKick"
type="alert">
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 7ce2627be9..08c8aef1e9 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -633,5 +633,97 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
top="0"
right="-1" />
</panel>
+ <panel
+ background_opaque="true"
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ bg_opaque_color="DkGray"
+ follows="all"
+ height="383"
+ label="FBC TEST"
+ layout="topleft"
+ left="0"
+ help_topic="people_fbctest_tab"
+ name="fbctest_panel"
+ top="0"
+ width="313">
+ <accordion
+ background_visible="true"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ follows="all"
+ height="356"
+ layout="topleft"
+ left="3"
+ name="friends_accordion"
+ top="0"
+ width="307">
+ <accordion_tab
+ layout="topleft"
+ height="172"
+ min_height="150"
+ name="tab_facebook"
+ title="Facebook Friends">
+ <social_list
+ allow_select="true"
+ follows="all"
+ height="172"
+ layout="topleft"
+ left="0"
+ multi_select="true"
+ name="facebook_friends"
+ show_permissions_granted="true"
+ top="0"
+ width="307" />
+ </accordion_tab>
+ </accordion>
+ <panel
+ background_visible="true"
+ follows="left|right|bottom"
+ height="27"
+ label="bottom_panel"
+ layout="topleft"
+ left="3"
+ name="bottom_panel"
+ top_pad="0"
+ width="313">
+ <menu_button
+ follows="bottom|left"
+ tool_tip="Options"
+ height="25"
+ image_hover_unselected="Toolbar_Left_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Left_Selected"
+ image_unselected="Toolbar_Left_Off"
+ layout="topleft"
+ name="fbc_options_btn"
+ top="1"
+ width="31" />
+ <button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="AddItem_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="1"
+ name="fbc_login_btn"
+ tool_tip="Log in to FBC"
+ width="31">
+ <commit_callback
+ function="People.loginFBC" />
+ </button>
+ <icon
+ follows="bottom|left|right"
+ height="25"
+ image_name="Toolbar_Right_Off"
+ layout="topleft"
+ left_pad="1"
+ name="dummy_icon"
+ width="244"
+ />
+ </panel>
+ </panel>
</tab_container>
</panel>