summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rwxr-xr-xindra/newview/CMakeLists.txt10
-rwxr-xr-xindra/newview/app_settings/settings.xml29
-rwxr-xr-xindra/newview/llagent.cpp13
-rwxr-xr-xindra/newview/llappviewer.cpp28
-rwxr-xr-xindra/newview/llconversationmodel.cpp4
-rwxr-xr-xindra/newview/llconversationmodel.h9
-rwxr-xr-xindra/newview/llconversationview.cpp21
-rwxr-xr-xindra/newview/llconversationview.h3
-rwxr-xr-xindra/newview/lldonotdisturbnotificationstorage.cpp16
-rw-r--r--indra/newview/llfacebookconnect.cpp316
-rw-r--r--indra/newview/llfacebookconnect.h73
-rwxr-xr-xindra/newview/llfloaterimcontainer.cpp135
-rwxr-xr-xindra/newview/llfloaterimcontainer.h8
-rwxr-xr-xindra/newview/llfloaterimnearbychat.cpp5
-rwxr-xr-xindra/newview/llfloaterimsession.cpp18
-rwxr-xr-xindra/newview/llfloaterimsessiontab.cpp44
-rwxr-xr-xindra/newview/llfloaterimsessiontab.h3
-rwxr-xr-xindra/newview/llfolderviewmodelinventory.cpp69
-rwxr-xr-xindra/newview/llfolderviewmodelinventory.h3
-rwxr-xr-xindra/newview/llgroupactions.cpp125
-rwxr-xr-xindra/newview/llgroupactions.h8
-rwxr-xr-xindra/newview/llimview.cpp263
-rwxr-xr-xindra/newview/llinventoryfilter.cpp42
-rwxr-xr-xindra/newview/llinventoryfilter.h17
-rwxr-xr-xindra/newview/llinventorypanel.cpp3
-rwxr-xr-xindra/newview/lllogchat.cpp45
-rwxr-xr-xindra/newview/lllogchat.h3
-rwxr-xr-xindra/newview/llpanelmaininventory.cpp7
-rwxr-xr-xindra/newview/llpanelmaininventory.h1
-rwxr-xr-xindra/newview/llpanelpeople.cpp337
-rwxr-xr-xindra/newview/llpanelpeople.h30
-rwxr-xr-xindra/newview/llparticipantlist.cpp18
-rwxr-xr-xindra/newview/llparticipantlist.h1
-rw-r--r--indra/newview/llpersonfolderview.cpp149
-rw-r--r--indra/newview/llpersonfolderview.h70
-rw-r--r--indra/newview/llpersonmodelcommon.cpp313
-rw-r--r--indra/newview/llpersonmodelcommon.h248
-rw-r--r--indra/newview/llpersontabview.cpp465
-rw-r--r--indra/newview/llpersontabview.h151
-rw-r--r--indra/newview/llsociallist.cpp154
-rw-r--r--indra/newview/llsociallist.h102
-rwxr-xr-xindra/newview/lltoastimpanel.cpp26
-rwxr-xr-xindra/newview/lltoastimpanel.h2
-rwxr-xr-xindra/newview/llviewermenu.cpp19
-rwxr-xr-xindra/newview/llviewermenu.h4
-rwxr-xr-xindra/newview/llviewermessage.cpp3
-rwxr-xr-xindra/newview/llviewerregion.cpp2
-rwxr-xr-xindra/newview/llviewerwindow.cpp1
-rwxr-xr-xindra/newview/skins/default/colors.xml15
-rw-r--r--indra/newview/skins/default/textures/icons/Facebook.pngbin0 -> 365 bytes
-rwxr-xr-xindra/newview/skins/default/textures/textures.xml5
-rw-r--r--indra/newview/skins/default/textures/widgets/horizontal_drag_handle.pngbin0 -> 197 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/vertical_drag_handle.pngbin0 -> 196 bytes
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_im_container.xml102
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_im_session.xml86
-rw-r--r--indra/newview/skins/default/xui/en/menu_gear_fbc.xml51
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_viewer.xml14
-rwxr-xr-xindra/newview/skins/default/xui/en/notifications.xml13
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_people.xml195
-rw-r--r--indra/newview/skins/default/xui/en/widgets/person_tab_view.xml13
-rw-r--r--indra/newview/skins/default/xui/en/widgets/person_view.xml127
-rwxr-xr-xindra/newview/tests/lltranslate_test.cpp4
62 files changed, 3629 insertions, 412 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 6e0bb161af..99b6bdf5d4 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -188,6 +188,7 @@ set(viewer_SOURCE_FILES
llexpandabletextbox.cpp
llexternaleditor.cpp
llface.cpp
+ llfacebookconnect.cpp
llfasttimerview.cpp
llfavoritesbar.cpp
llfeaturemanager.cpp
@@ -461,6 +462,9 @@ set(viewer_SOURCE_FILES
llpathfindingobjectlist.cpp
llpathfindingpathtool.cpp
llpersistentnotificationstorage.cpp
+ llpersonfolderview.cpp
+ llpersonmodelcommon.cpp
+ llpersontabview.cpp
llphysicsmotion.cpp
llphysicsshapebuilderutil.cpp
llpipelinelistener.cpp
@@ -503,6 +507,7 @@ set(viewer_SOURCE_FILES
llsidetraypanelcontainer.cpp
llsky.cpp
llslurl.cpp
+ llsociallist.cpp
llspatialpartition.cpp
llspeakers.cpp
llspeakingindicatormanager.cpp
@@ -769,6 +774,7 @@ set(viewer_HEADER_FILES
llexpandabletextbox.h
llexternaleditor.h
llface.h
+ llfacebookconnect.h
llfasttimerview.h
llfavoritesbar.h
llfeaturemanager.h
@@ -1030,6 +1036,9 @@ set(viewer_HEADER_FILES
llpathfindingobjectlist.h
llpathfindingpathtool.h
llpersistentnotificationstorage.h
+ llpersonfolderview.h
+ llpersonmodelcommon.h
+ llpersontabview.h
llphysicsmotion.h
llphysicsshapebuilderutil.h
llpipelinelistener.h
@@ -1073,6 +1082,7 @@ set(viewer_HEADER_FILES
llsidetraypanelcontainer.h
llsky.h
llslurl.h
+ llsociallist.h
llspatialpartition.h
llspeakers.h
llspeakingindicatormanager.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 31c730e0bc..cf18fa4b46 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3457,16 +3457,27 @@
<key>Value</key>
<real>10.0</real>
</map>
- <key>FilterItemsPerFrame</key>
+ <key>FilterItemsMaxTimePerFrameVisible</key>
<map>
- <key>Comment</key>
- <string>Maximum number of inventory items to match against search filter every frame (lower to increase framerate while searching, higher to improve search speed)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>500</integer>
+ <key>Comment</key>
+ <string>Max time devoted to items filtering per frame for visible inventory listings (in milliseconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>10</integer>
+ </map>
+ <key>FilterItemsMaxTimePerFrameUnvisible</key>
+ <map>
+ <key>Comment</key>
+ <string>Max time devoted to items filtering per frame for non visible inventory listings (in milliseconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1</integer>
</map>
<key>FindLandArea</key>
<map>
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 8c42defa73..d16945070a 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -46,6 +46,7 @@
#include "llenvmanager.h"
#include "llfirstuse.h"
#include "llfloatercamera.h"
+#include "llfloaterimcontainer.h"
#include "llfloaterreg.h"
#include "llfloatertools.h"
#include "llgroupactions.h"
@@ -91,6 +92,7 @@
#include "llworld.h"
#include "llworldmap.h"
#include "stringize.h"
+#include "boost/foreach.hpp"
using namespace LLAvatarAppearanceDefines;
@@ -2037,7 +2039,16 @@ void LLAgent::endAnimationUpdateUI()
{
skip_list.insert(LLFloaterReg::findInstance("mini_map"));
}
-
+
+ LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
+ LLFloaterIMContainer::floater_list_t conversations;
+ im_box->getDetachedConversationFloaters(conversations);
+ BOOST_FOREACH(LLFloater* conversation, conversations)
+ {
+ llinfos << "skip_list.insert(session_floater): " << conversation->getTitle() << llendl;
+ skip_list.insert(conversation);
+ }
+
gFloaterView->popVisibleAll(skip_list);
#endif
mViewsPushed = FALSE;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 45a990f65f..21b022847b 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2632,20 +2632,38 @@ bool LLAppViewer::initConfiguration()
// What can happen is that someone can use IE (or potentially
// other browsers) and do the rough equivalent of command
// injection and steal passwords. Phoenix. SL-55321
+
+ LLSLURL option_slurl;
+
if(clp.hasOption("url"))
{
- LLStartUp::setStartSLURL(LLSLURL(clp.getOption("url")[0]));
+ option_slurl = LLSLURL(clp.getOption("url")[0]);
+ LLStartUp::setStartSLURL(option_slurl);
if(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION)
{
LLGridManager::getInstance()->setGridChoice(LLStartUp::getStartSLURL().getGrid());
-
- }
+ }
}
else if(clp.hasOption("slurl"))
{
- LLSLURL start_slurl(clp.getOption("slurl")[0]);
- LLStartUp::setStartSLURL(start_slurl);
+ option_slurl = LLSLURL(clp.getOption("slurl")[0]);
+ LLStartUp::setStartSLURL(option_slurl);
}
+
+ //RN: if we received a URL, hand it off to the existing instance.
+ // don't call anotherInstanceRunning() when doing URL handoff, as
+ // it relies on checking a marker file which will not work when running
+ // out of different directories
+
+ if (option_slurl.isValid() &&
+ (gSavedSettings.getBOOL("SLURLPassToOtherInstance")))
+ {
+ if (sendURLToOtherInstance(option_slurl.getSLURLString()))
+ {
+ // successfully handed off URL to existing instance, exit
+ return false;
+ }
+ }
const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent");
if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString())
diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index c74ce24872..6e95df8383 100755
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -386,6 +386,10 @@ void LLConversationItemSession::buildContextMenu(LLMenuGL& menu, U32 flags)
addVoiceOptions(items);
items.push_back(std::string("chat_history"));
}
+ else if(this->getType() == CONV_SESSION_NEARBY)
+ {
+ items.push_back(std::string("chat_history"));
+ }
hide_context_entries(menu, items, disabled_items);
}
diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h
index 8766585049..d8cdcdfc97 100755
--- a/indra/newview/llconversationmodel.h
+++ b/indra/newview/llconversationmodel.h
@@ -252,11 +252,10 @@ public:
const std::string& getName() const { return mEmpty; }
const std::string& getFilterText() { return mEmpty; }
void setModified(EFilterModified behavior = FILTER_RESTART) { }
-
- void setFilterCount(S32 count) { }
- S32 getFilterCount() const { return 0; }
- void decrementFilterCount() { }
-
+
+ void resetTime(S32 timeout) { }
+ bool isTimedOut() { return false; }
+
bool isDefault() const { return true; }
bool isNotDefault() const { return false; }
void markDefault() { }
diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp
index b6c53e5e30..42104ea20a 100755
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -118,6 +118,13 @@ void LLConversationViewSession::setFlashState(bool flash_state)
mFlashTimer->stopFlashing();
}
+void LLConversationViewSession::setHighlightState(bool hihglight_state)
+{
+ mFlashStateOn = hihglight_state;
+ mFlashStarted = true;
+ mFlashTimer->stopFlashing();
+}
+
void LLConversationViewSession::startFlashing()
{
if (isInVisibleChain() && mFlashStateOn && !mFlashStarted)
@@ -340,16 +347,20 @@ void LLConversationViewSession::setVisibleIfDetached(BOOL visible)
{
// Do this only if the conversation floater has been torn off (i.e. no multi floater host) and is not minimized
// Note: minimized dockable floaters are brought to front hence unminimized when made visible and we don't want that here
- LLFolderViewModelItem* item = mViewModelItem;
- LLUUID session_uuid = dynamic_cast<LLConversationItem*>(item)->getUUID();
- LLFloater* session_floater = LLFloaterIMSessionTab::getConversation(session_uuid);
-
- if (session_floater && !session_floater->getHost() && !session_floater->isMinimized())
+ LLFloater* session_floater = getSessionFloater();
+ if (session_floater && session_floater->isDetachedAndNotMinimized())
{
session_floater->setVisible(visible);
}
}
+LLFloater* LLConversationViewSession::getSessionFloater()
+{
+ LLFolderViewModelItem* item = mViewModelItem;
+ LLUUID session_uuid = dynamic_cast<LLConversationItem*>(item)->getUUID();
+ return LLFloaterIMSessionTab::getConversation(session_uuid);
+}
+
LLConversationViewParticipant* LLConversationViewSession::findParticipant(const LLUUID& participant_id)
{
// This is *not* a general tree parsing algorithm. We search only in the mItems list
diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h
index 3eb2e63792..879d496dc7 100755
--- a/indra/newview/llconversationview.h
+++ b/indra/newview/llconversationview.h
@@ -86,6 +86,9 @@ public:
virtual void refresh();
/*virtual*/ void setFlashState(bool flash_state);
+ void setHighlightState(bool hihglight_state);
+
+ LLFloater* getSessionFloater();
private:
diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp
index 82affcf068..71bc4f15d2 100755
--- a/indra/newview/lldonotdisturbnotificationstorage.cpp
+++ b/indra/newview/lldonotdisturbnotificationstorage.cpp
@@ -115,7 +115,8 @@ void LLDoNotDisturbNotificationStorage::saveNotifications()
{
LLNotificationPtr notificationPtr = historyIter->second;
- if (!notificationPtr->isRespondedTo() && !notificationPtr->isCancelled() && !notificationPtr->isExpired())
+ if (!notificationPtr->isRespondedTo() && !notificationPtr->isCancelled() &&
+ !notificationPtr->isExpired() && !notificationPtr->isPersistent())
{
data.append(notificationPtr->asLLSD(true));
}
@@ -210,12 +211,8 @@ void LLDoNotDisturbNotificationStorage::loadNotifications()
}
- if(imToastExists)
- {
- LLFloaterReg::showInstance("im_container");
- }
-
- if(group_ad_hoc_toast_exists)
+ bool isConversationLoggingAllowed = gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 0;
+ if(group_ad_hoc_toast_exists && isConversationLoggingAllowed)
{
LLFloaterReg::showInstance("conversation");
}
@@ -266,11 +263,6 @@ void LLDoNotDisturbNotificationStorage::updateNotifications()
}
}
- if(imToastExists)
- {
- LLFloaterReg::showInstance("im_container");
- }
-
if(imToastExists || offerExists)
{
make_ui_sound("UISndNewIncomingIMSession");
diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp
new file mode 100644
index 0000000000..eb70cf4d10
--- /dev/null
+++ b/indra/newview/llfacebookconnect.cpp
@@ -0,0 +1,316 @@
+/**
+ * @file llfacebookconnect.h
+ * @author Merov, Cho, Gil
+ * @brief Connection to Facebook Service
+ *
+ * $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 "llfacebookconnect.h"
+
+#include "llagent.h"
+#include "llcallingcard.h" // for LLAvatarTracker
+#include "llcommandhandler.h"
+#include "llhttpclient.h"
+#include "llurlaction.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//
+
+class LLFacebookConnectHandler : public LLCommandHandler
+{
+public:
+ LLFacebookConnectHandler() : LLCommandHandler("fbc", UNTRUSTED_THROTTLE) { }
+
+ bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ if (tokens.size() > 0)
+ {
+ if (tokens[0].asString() == "connect")
+ {
+ if (query_map.has("code"))
+ {
+ LLFacebookConnect::instance().connectToFacebook(query_map["code"]);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+};
+LLFacebookConnectHandler gFacebookConnectHandler;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFacebookConnectResponder : public LLHTTPClient::Responder
+{
+ LOG_CLASS(LLFacebookConnectResponder);
+public:
+
+ virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (isGoodStatus(status))
+ {
+ LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL;
+
+ // Grab some graph data now that we are connected
+ LLFacebookConnect::instance().setConnected(true);
+ LLFacebookConnect::instance().loadFacebookFriends();
+ }
+ else
+ {
+ LL_WARNS("FacebookConnect") << "Failed to get a response. reason: " << reason << " status: " << status << LL_ENDL;
+ }
+ }
+
+ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (status == 302)
+ {
+ LLFacebookConnect::instance().openFacebookWeb(content["location"]);
+ }
+ }
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFacebookPostResponder : public LLHTTPClient::Responder
+{
+ LOG_CLASS(LLFacebookPostResponder);
+public:
+
+ virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (isGoodStatus(status))
+ {
+ LL_DEBUGS("FacebookConnect") << "Post successful. content: " << content << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS("FacebookConnect") << "Failed to get a post response. reason: " << reason << " status: " << status << LL_ENDL;
+ }
+ }
+
+ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (status == 302)
+ {
+ LLFacebookConnect::instance().openFacebookWeb(content["location"]);
+ }
+ }
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFacebookDisconnectResponder : public LLHTTPClient::Responder
+{
+ LOG_CLASS(LLFacebookDisconnectResponder);
+public:
+
+ virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (isGoodStatus(status))
+ {
+ LL_DEBUGS("FacebookConnect") << "Disconnect successful. content: " << content << LL_ENDL;
+
+ // Clear all facebook stuff
+ LLFacebookConnect::instance().setConnected(false);
+ LLFacebookConnect::instance().clearContent();
+ }
+ else
+ {
+ LL_WARNS("FacebookConnect") << "Failed to get a response. reason: " << reason << " status: " << status << LL_ENDL;
+ }
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFacebookConnectedResponder : public LLHTTPClient::Responder
+{
+ LOG_CLASS(LLFacebookConnectedResponder);
+public:
+
+ LLFacebookConnectedResponder(bool show_login_if_not_connected) : mShowLoginIfNotConnected(show_login_if_not_connected) {}
+
+ virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (isGoodStatus(status))
+ {
+ LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL;
+
+ // Grab some graph data if already connected
+ LLFacebookConnect::instance().setConnected(true);
+ LLFacebookConnect::instance().loadFacebookFriends();
+ }
+ else
+ {
+ LL_WARNS("FacebookConnect") << "Failed to get a response. reason: " << reason << " status: " << status << LL_ENDL;
+
+ // show the facebook login page if not connected yet
+ if ((status == 404) && mShowLoginIfNotConnected)
+ {
+ LLFacebookConnect::instance().connectToFacebook();
+ }
+ }
+ }
+
+private:
+ bool mShowLoginIfNotConnected;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class LLFacebookFriendsResponder : public LLHTTPClient::Responder
+{
+ LOG_CLASS(LLFacebookFriendsResponder);
+public:
+
+ virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (isGoodStatus(status))
+ {
+ LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. content: " << content << LL_ENDL;
+ LLFacebookConnect::instance().storeContent(content);
+ }
+ else
+ {
+ LL_WARNS("FacebookConnect") << "Failed to get a response. reason: " << reason << " status: " << status << LL_ENDL;
+ }
+ }
+
+ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (status == 302)
+ {
+ LLFacebookConnect::instance().openFacebookWeb(content["location"]);
+ }
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+LLFacebookConnect::LLFacebookConnect()
+: mConnectedToFbc(false),
+ mContent(),
+ mGeneration(0)
+{
+}
+
+void LLFacebookConnect::openFacebookWeb(std::string url)
+{
+ LLUrlAction::openURLExternal(url);
+}
+
+std::string LLFacebookConnect::getFacebookConnectURL(const std::string& route)
+{
+ //static std::string sFacebookConnectUrl = gAgent.getRegion()->getCapability("FacebookConnect");
+ static std::string sFacebookConnectUrl = "https://pdp15.lindenlab.com/fbc/agent/" + gAgentID.asString(); // TEMPORARY HACK FOR FB DEMO - Cho
+ std::string url = sFacebookConnectUrl + route;
+ llinfos << url << llendl;
+ return url;
+}
+
+void LLFacebookConnect::connectToFacebook(const std::string& auth_code)
+{
+ LLSD body;
+ if (!auth_code.empty())
+ body["code"] = auth_code;
+
+ LLHTTPClient::put(getFacebookConnectURL("/connection"), body, new LLFacebookConnectResponder());
+}
+
+void LLFacebookConnect::disconnectFromFacebook()
+{
+ LLHTTPClient::del(getFacebookConnectURL("/connection"), new LLFacebookDisconnectResponder());
+}
+
+void LLFacebookConnect::tryToReconnectToFacebook()
+{
+ if (!mConnectedToFbc)
+ {
+ const bool follow_redirects=false;
+ const F32 timeout=HTTP_REQUEST_EXPIRY_SECS;
+ LLHTTPClient::get(getFacebookConnectURL("/connection"), new LLFacebookConnectedResponder(false),
+ LLSD(), timeout, follow_redirects);
+ }
+}
+
+void LLFacebookConnect::getConnectionToFacebook()
+{
+ const bool follow_redirects=false;
+ const F32 timeout=HTTP_REQUEST_EXPIRY_SECS;
+ LLHTTPClient::get(getFacebookConnectURL("/connection"), new LLFacebookConnectedResponder(true),
+ LLSD(), timeout, follow_redirects);
+}
+
+void LLFacebookConnect::loadFacebookFriends()
+{
+ const bool follow_redirects=false;
+ const F32 timeout=HTTP_REQUEST_EXPIRY_SECS;
+ LLHTTPClient::get(getFacebookConnectURL("/friend"), new LLFacebookFriendsResponder(),
+ LLSD(), timeout, follow_redirects);
+}
+
+void LLFacebookConnect::postCheckinMessage(const std::string& message, const std::string& url)
+{
+ // Note: We need to improve the API support to provide all the relevant data if possible
+ // Full set described : http://facebook-python-library.docs-library.appspot.com/facebook-python/library-manual.html
+ LLSD body;
+ if (!message.empty())
+ body["message"] = message;
+ if (!url.empty())
+ body["link"] = url;
+
+ // Note: we can use that route for different publish action. We should be able to use the same responder.
+ LLHTTPClient::post(getFacebookConnectURL("/share"), body, new LLFacebookPostResponder());
+}
+
+void LLFacebookConnect::storeContent(const LLSD& content)
+{
+ mGeneration++;
+ mContent = content;
+}
+
+const LLSD& LLFacebookConnect::getContent() const
+{
+ return mContent;
+}
+
+void LLFacebookConnect::clearContent()
+{
+ mGeneration++;
+ mContent = LLSD();
+}
+
+
+
+
+
+
+
+
diff --git a/indra/newview/llfacebookconnect.h b/indra/newview/llfacebookconnect.h
new file mode 100644
index 0000000000..f151dd95c1
--- /dev/null
+++ b/indra/newview/llfacebookconnect.h
@@ -0,0 +1,73 @@
+/**
+ * @file llfacebookconnect.h
+ * @author Merov, Cho, Gil
+ * @brief Connection to Facebook Service
+ *
+ * $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_LLFACEBOOKCONNECT_H
+#define LL_LLFACEBOOKCONNECT_H
+
+#include "llsingleton.h"
+
+/**
+ * @class LLFacebookConnect
+ *
+ * Manages authentication to, and interaction with, a web service allowing the
+ * the viewer to get Facebook OpenGraph data.
+ */
+class LLFacebookConnect : public LLSingleton<LLFacebookConnect>
+{
+ LOG_CLASS(LLFacebookConnect);
+public:
+ void connectToFacebook(const std::string& auth_code = "");
+ void disconnectFromFacebook();
+ void tryToReconnectToFacebook();
+ void getConnectionToFacebook();
+
+ void loadFacebookFriends();
+ void postCheckinMessage(const std::string& message, const std::string& url);
+
+ void clearContent();
+ void storeContent(const LLSD& content);
+ const LLSD& getContent() const;
+
+ void setConnected(bool connected) { mConnectedToFbc = connected; }
+ bool getConnected() { return mConnectedToFbc; }
+ S32 generation() { return mGeneration; }
+
+ void openFacebookWeb(std::string url);
+private:
+
+ friend class LLSingleton<LLFacebookConnect>;
+
+ LLFacebookConnect();
+ ~LLFacebookConnect() {};
+ std::string getFacebookConnectURL(const std::string& route = "");
+
+ bool mConnectedToFbc;
+ LLSD mContent;
+ S32 mGeneration;
+};
+
+#endif // LL_LLFACEBOOKCONNECT_H
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 58817485fb..21ba3a444b 100755
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -54,6 +54,7 @@
#include "llworld.h"
#include "llsdserialize.h"
#include "llviewerobjectlist.h"
+#include "boost/foreach.hpp"
//
// LLFloaterIMContainer
@@ -63,7 +64,8 @@ LLFloaterIMContainer::LLFloaterIMContainer(const LLSD& seed, const Params& param
mExpandCollapseBtn(NULL),
mConversationsRoot(NULL),
mConversationsEventStream("ConversationsEvents"),
- mInitialized(false)
+ mInitialized(false),
+ mIsFirstLaunch(true)
{
mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLFloaterIMContainer::isActionChecked, this, _2));
mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLFloaterIMContainer::onCustomAction, this, _2));
@@ -204,6 +206,7 @@ BOOL LLFloaterIMContainer::postBuild()
// a scroller for folder view
LLRect scroller_view_rect = mConversationsListPanel->getRect();
scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
+ scroller_view_rect.mBottom += getChild<LLLayoutStack>("conversations_pane_buttons_stack")->getRect().getHeight();
LLScrollContainer::Params scroller_params(LLUICtrlFactory::getDefaultParams<LLFolderViewScrollContainer>());
scroller_params.rect(scroller_view_rect);
@@ -221,7 +224,8 @@ BOOL LLFloaterIMContainer::postBuild()
mExpandCollapseBtn->setClickedCallback(boost::bind(&LLFloaterIMContainer::onExpandCollapseButtonClicked, this));
mStubCollapseBtn = getChild<LLButton>("stub_collapse_btn");
mStubCollapseBtn->setClickedCallback(boost::bind(&LLFloaterIMContainer::onStubCollapseButtonClicked, this));
- getChild<LLButton>("speak_btn")->setClickedCallback(boost::bind(&LLFloaterIMContainer::onSpeakButtonClicked, this));
+ mSpeakBtn = getChild<LLButton>("speak_btn");
+ mSpeakBtn->setClickedCallback(boost::bind(&LLFloaterIMContainer::onSpeakButtonClicked, this));
childSetAction("add_btn", boost::bind(&LLFloaterIMContainer::onAddButtonClicked, this));
@@ -342,8 +346,11 @@ void LLFloaterIMContainer::onStubCollapseButtonClicked()
void LLFloaterIMContainer::onSpeakButtonClicked()
{
- LLAgent::toggleMicrophone("speak");
- updateSpeakBtnState();
+ //LLAgent::toggleMicrophone("speak");
+ //updateSpeakBtnState();
+
+ LLParticipantList* session_model = dynamic_cast<LLParticipantList*>(mConversationsItems[LLUUID(NULL)]);
+ session_model->addTestAvatarAgents();
}
void LLFloaterIMContainer::onExpandCollapseButtonClicked()
{
@@ -659,10 +666,32 @@ void LLFloaterIMContainer::setVisible(BOOL visible)
LLMultiFloater::setVisible(visible);
}
+void LLFloaterIMContainer::getDetachedConversationFloaters(floater_list_t& floaters)
+{
+ typedef conversations_widgets_map::value_type conv_pair;
+ BOOST_FOREACH(conv_pair item, mConversationsWidgets)
+ {
+ LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(item.second);
+ if (widget)
+ {
+ LLFloater* session_floater = widget->getSessionFloater();
+ if (session_floater && session_floater->isDetachedAndNotMinimized())
+ {
+ floaters.push_back(session_floater);
+ }
+ }
+ }
+}
+
void LLFloaterIMContainer::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key)
{
LLMultiFloater::setVisibleAndFrontmost(take_focus, key);
selectConversationPair(getSelectedSession(), false, take_focus);
+ if (mInitialized && mIsFirstLaunch)
+ {
+ collapseMessagesPane(gSavedPerAccountSettings.getBOOL("ConversationsMessagePaneCollapsed"));
+ mIsFirstLaunch = false;
+ }
}
void LLFloaterIMContainer::updateResizeLimits()
@@ -779,13 +808,6 @@ void LLFloaterIMContainer::reshapeFloaterAndSetResizeLimits(bool collapse, S32 d
setCanMinimize(at_least_one_panel_is_expanded);
assignResizeLimits();
-
- // force set correct size for the title after show/hide minimize button
- LLRect cur_rect = getRect();
- LLRect force_rect = cur_rect;
- force_rect.mRight = cur_rect.mRight + 1;
- setRect(force_rect);
- setRect(cur_rect);
}
void LLFloaterIMContainer::assignResizeLimits()
@@ -793,15 +815,12 @@ void LLFloaterIMContainer::assignResizeLimits()
bool is_conv_pane_expanded = !mConversationsPane->isCollapsed();
bool is_msg_pane_expanded = !mMessagesPane->isCollapsed();
- // With two panels visible number of borders is three, because the borders
- // between the panels are merged into one
- S32 number_of_visible_borders = llmin((is_conv_pane_expanded? 2 : 0) + (is_msg_pane_expanded? 2 : 0), 3);
- S32 summary_width_of_visible_borders = number_of_visible_borders * LLPANEL_BORDER_WIDTH;
- S32 conv_pane_target_width = is_conv_pane_expanded?
- (is_msg_pane_expanded?
- mConversationsPane->getRect().getWidth()
- : mConversationsPane->getExpandedMinDim())
- : mConversationsPane->getMinDim();
+ S32 summary_width_of_visible_borders = (is_msg_pane_expanded ? mConversationsStack->getPanelSpacing() : 0) + 1;
+
+ S32 conv_pane_target_width = is_conv_pane_expanded
+ ? ( is_msg_pane_expanded?mConversationsPane->getRect().getWidth():mConversationsPane->getExpandedMinDim() )
+ : mConversationsPane->getMinDim();
+
S32 msg_pane_min_width = is_msg_pane_expanded ? mMessagesPane->getExpandedMinDim() : 0;
S32 new_min_width = conv_pane_target_width + msg_pane_min_width + summary_width_of_visible_borders;
@@ -1143,7 +1162,7 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,
}
else if("chat_history" == command)
{
- if (selectedIDS.size() > 0)
+ if (selectedIDS.size() > 0)
{
LLAvatarActions::viewChatHistory(selectedIDS.front());
}
@@ -1156,6 +1175,17 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,
}
}
}
+ //if there is no LLFloaterIMSession* instance for selected conversation it might be Nearby chat
+ else
+ {
+ if(conversationItem->getType() == LLConversationItem::CONV_SESSION_NEARBY)
+ {
+ if("chat_history" == command)
+ {
+ LLFloaterReg::showInstance("preview_conversation", LLSD(LLUUID::null), true);
+ }
+ }
+ }
}
void LLFloaterIMContainer::doToSelected(const LLSD& userdata)
@@ -1211,7 +1241,19 @@ 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());
+ //Disable menu item if selected participant is user agent
+ if(uuids.front() != gAgentID)
+ {
+ if (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_NEARBY)
+ {
+ return LLLogChat::isNearbyTranscriptExist();
+ }
+ else
+ {
+ 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
@@ -1904,7 +1946,6 @@ void LLFloaterIMContainer::reSelectConversation()
void LLFloaterIMContainer::updateSpeakBtnState()
{
- LLButton* mSpeakBtn = getChild<LLButton>("speak_btn");
mSpeakBtn->setToggleState(LLVoiceClient::getInstance()->getUserPTTState());
mSpeakBtn->setEnabled(LLAgent::isActionAllowed("speak"));
}
@@ -1925,6 +1966,17 @@ void LLFloaterIMContainer::flashConversationItemWidget(const LLUUID& session_id,
}
}
+void LLFloaterIMContainer::highlightConversationItemWidget(const LLUUID& session_id, bool is_highlighted)
+{
+ //Finds the conversation line item to highlight using the session_id
+ LLConversationViewSession * widget = dynamic_cast<LLConversationViewSession *>(get_ptr_in_map(mConversationsWidgets,session_id));
+
+ if (widget)
+ {
+ widget->setHighlightState(is_highlighted);
+ }
+}
+
bool LLFloaterIMContainer::isScrolledOutOfSight(LLConversationViewSession* conversation_item_widget)
{
llassert(conversation_item_widget != NULL);
@@ -1940,23 +1992,28 @@ bool LLFloaterIMContainer::isScrolledOutOfSight(LLConversationViewSession* conve
BOOL LLFloaterIMContainer::handleKeyHere(KEY key, MASK mask )
{
+ BOOL handled = FALSE;
+
if(mask == MASK_ALT)
{
if (KEY_RETURN == key )
{
expandConversation();
+ handled = TRUE;
}
if ((KEY_DOWN == key ) || (KEY_RIGHT == key))
{
selectNextorPreviousConversation(true);
+ handled = TRUE;
}
if ((KEY_UP == key) || (KEY_LEFT == key))
{
selectNextorPreviousConversation(false);
+ handled = TRUE;
}
}
- return TRUE;
+ return handled;
}
bool LLFloaterIMContainer::selectAdjacentConversation(bool focus_selected)
@@ -2013,7 +2070,9 @@ void LLFloaterIMContainer::expandConversation()
}
}
-void LLFloaterIMContainer::closeFloater(bool app_quitting/* = false*/)
+// For conversations, closeFloater() (linked to Ctrl-W) does not actually close the floater but the active conversation.
+// This is intentional so it doesn't confuse the user. onClickCloseBtn() closes the whole floater.
+void LLFloaterIMContainer::onClickCloseBtn()
{
// Always unminimize before trying to close.
// Most of the time the user will never see this state.
@@ -2022,7 +2081,31 @@ void LLFloaterIMContainer::closeFloater(bool app_quitting/* = false*/)
LLMultiFloater::setMinimized(FALSE);
}
- LLFloater::closeFloater(app_quitting);
+ LLFloater::closeFloater();
+}
+
+void LLFloaterIMContainer::closeFloater(bool app_quitting/* = false*/)
+{
+ // Check for currently active session
+ LLUUID session_id = getSelectedSession();
+ // If current session is Nearby Chat or there is only one session remaining, close the floater
+ if (mConversationsItems.size() == 1 || session_id == LLUUID() || app_quitting)
+ {
+ onClickCloseBtn();
+ }
+
+ // Otherwise, close current conversation
+ LLFloaterIMSessionTab* active_conversation = LLFloaterIMSessionTab::getConversation(session_id);
+ if (active_conversation)
+ {
+ active_conversation->closeFloater();
+ }
+}
+
+void LLFloaterIMContainer::handleReshape(const LLRect& rect, bool by_user)
+{
+ LLMultiFloater::handleReshape(rect, by_user);
+ storeRectControl();
}
// EOF
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index e39d20ec35..74c3640bad 100755
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -63,6 +63,8 @@ public:
/*virtual*/ void setVisible(BOOL visible);
/*virtual*/ void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());
/*virtual*/ void updateResizeLimits();
+ /*virtual*/ void handleReshape(const LLRect& rect, bool by_user);
+
void onCloseFloater(LLUUID& id);
/*virtual*/ void addFloater(LLFloater* floaterp,
@@ -130,6 +132,7 @@ private:
void onStubCollapseButtonClicked();
void processParticipantsStyleUpdate();
void onSpeakButtonClicked();
+ /*virtual*/ void onClickCloseBtn();
void collapseConversationsPane(bool collapse, bool save_is_allowed=true);
@@ -169,6 +172,7 @@ private:
LLButton* mExpandCollapseBtn;
LLButton* mStubCollapseBtn;
+ LLButton* mSpeakBtn;
LLPanel* mStubPanel;
LLTextBox* mStubTextBox;
LLLayoutPanel* mMessagesPane;
@@ -176,6 +180,7 @@ private:
LLLayoutStack* mConversationsStack;
bool mInitialized;
+ bool mIsFirstLaunch;
LLUUID mSelectedSession;
std::string mGeneralTitle;
@@ -190,9 +195,12 @@ public:
void updateSpeakBtnState();
static bool isConversationLoggingAllowed();
void flashConversationItemWidget(const LLUUID& session_id, bool is_flashes);
+ void highlightConversationItemWidget(const LLUUID& session_id, bool is_highlighted);
bool isScrolledOutOfSight(LLConversationViewSession* conversation_item_widget);
boost::signals2::connection mMicroChangedSignal;
S32 getConversationListItemSize() { return mConversationsWidgets.size(); }
+ typedef std::list<LLFloater*> floater_list_t;
+ void getDetachedConversationFloaters(floater_list_t& floaters);
private:
LLConversationViewSession* createConversationItemWidget(LLConversationItem* item);
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index 49f36a2f32..7e472466ed 100755
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -568,7 +568,10 @@ void LLFloaterIMNearbyChat::sendChat( EChatType type )
if (0 == channel)
{
// discard returned "found" boolean
- LLGestureMgr::instance().triggerAndReviseString(utf8text, &utf8_revised_text);
+ if(!LLGestureMgr::instance().triggerAndReviseString(utf8text, &utf8_revised_text))
+ {
+ utf8_revised_text = utf8text;
+ }
}
else
{
diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp
index 8ec85e1160..848d5c34d2 100755
--- a/indra/newview/llfloaterimsession.cpp
+++ b/indra/newview/llfloaterimsession.cpp
@@ -442,8 +442,11 @@ void LLFloaterIMSession::addSessionParticipants(const uuid_vec_t& uuids)
}
else
{
- // remember whom we have invited, to notify others later, when the invited ones actually join
- mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end());
+ if(findInstance(mSessionID))
+ {
+ // remember whom we have invited, to notify others later, when the invited ones actually join
+ mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end());
+ }
inviteToSession(uuids);
}
@@ -469,13 +472,18 @@ void LLFloaterIMSession::addP2PSessionParticipants(const LLSD& notification, con
temp_ids.insert(temp_ids.end(), uuids.begin(), uuids.end());
// then we can close the current session
- onClose(false);
+ if(findInstance(mSessionID))
+ {
+ onClose(false);
+
+ // remember whom we have invited, to notify others later, when the invited ones actually join
+ mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end());
+ }
// we start a new session so reset the initialization flag
mSessionInitialized = false;
- // remember whom we have invited, to notify others later, when the invited ones actually join
- mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end());
+
// Start a new ad hoc voice call if we invite new participants to a P2P call,
// or start a text chat otherwise.
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index ce6e639305..cc2859c099 100755
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -212,7 +212,7 @@ void LLFloaterIMSessionTab::assignResizeLimits()
mRightPartPanel->setIgnoreReshape(is_participants_pane_collapsed);
S32 participants_pane_target_width = is_participants_pane_collapsed?
- 0 : (mParticipantListPanel->getRect().getWidth() + LLPANEL_BORDER_WIDTH);
+ 0 : (mParticipantListPanel->getRect().getWidth() + mParticipantListAndHistoryStack->getPanelSpacing());
S32 new_min_width = participants_pane_target_width + mRightPartPanel->getExpandedMinDim() + mFloaterExtraWidth;
@@ -241,7 +241,10 @@ BOOL LLFloaterIMSessionTab::postBuild()
mTearOffBtn->setCommitCallback(boost::bind(&LLFloaterIMSessionTab::onTearOffClicked, this));
mGearBtn = getChild<LLButton>("gear_btn");
-
+ mAddBtn = getChild<LLButton>("add_btn");
+ mVoiceButton = getChild<LLButton>("voice_call_btn");
+ mTranslationCheckBox = getChild<LLUICtrl>("translate_chat_checkbox_lp");
+
mParticipantListPanel = getChild<LLLayoutPanel>("speakers_list_panel");
mRightPartPanel = getChild<LLLayoutPanel>("right_part_holder");
@@ -372,7 +375,7 @@ void LLFloaterIMSessionTab::draw()
void LLFloaterIMSessionTab::enableDisableCallBtn()
{
- getChildView("voice_call_btn")->setEnabled(
+ mVoiceButton->setEnabled(
mSessionID.notNull()
&& mSession
&& mSession->mSessionInitialized
@@ -758,7 +761,7 @@ void LLFloaterIMSessionTab::reshapeChatLayoutPanel()
void LLFloaterIMSessionTab::showTranslationCheckbox(BOOL show)
{
- getChild<LLUICtrl>("translate_chat_checkbox_lp")->setVisible(mIsNearbyChat? show : FALSE);
+ mTranslationCheckBox->setVisible(mIsNearbyChat && show);
}
// static
@@ -805,15 +808,10 @@ void LLFloaterIMSessionTab::reloadEmptyFloaters()
void LLFloaterIMSessionTab::updateCallBtnState(bool callIsActive)
{
- LLButton* voiceButton = getChild<LLButton>("voice_call_btn");
- voiceButton->setImageOverlay(
- callIsActive? getString("call_btn_stop") : getString("call_btn_start"));
-
- voiceButton->setToolTip(
- callIsActive? getString("end_call_button_tooltip") : getString("start_call_button_tooltip"));
+ mVoiceButton->setImageOverlay(callIsActive? getString("call_btn_stop") : getString("call_btn_start"));
+ mVoiceButton->setToolTip(callIsActive? getString("end_call_button_tooltip") : getString("start_call_button_tooltip"));
enableDisableCallBtn();
-
}
void LLFloaterIMSessionTab::onSlide(LLFloaterIMSessionTab* self)
@@ -898,6 +896,7 @@ void LLFloaterIMSessionTab::restoreFloater()
mExpandCollapseLineBtn->setImageOverlay(getString("expandline_icon"));
setMessagePaneExpanded(true);
saveCollapsedState();
+ mInputEditor->enableSingleLineMode(false);
enableResizeCtrls(true, true, true);
}
}
@@ -953,8 +952,8 @@ void LLFloaterIMSessionTab::updateGearBtn()
if(prevVisibility != mGearBtn->getVisible())
{
LLRect gear_btn_rect = mGearBtn->getRect();
- LLRect add_btn_rect = getChild<LLButton>("add_btn")->getRect();
- LLRect call_btn_rect = getChild<LLButton>("voice_call_btn")->getRect();
+ LLRect add_btn_rect = mAddBtn->getRect();
+ LLRect call_btn_rect = mVoiceButton->getRect();
S32 gap_width = call_btn_rect.mLeft - add_btn_rect.mRight;
S32 right_shift = gear_btn_rect.getWidth() + gap_width;
if(mGearBtn->getVisible())
@@ -968,24 +967,24 @@ void LLFloaterIMSessionTab::updateGearBtn()
add_btn_rect.translate(-right_shift,0);
call_btn_rect.translate(-right_shift,0);
}
- getChild<LLButton>("add_btn")->setRect(add_btn_rect);
- getChild<LLButton>("voice_call_btn")->setRect(call_btn_rect);
+ mAddBtn->setRect(add_btn_rect);
+ mVoiceButton->setRect(call_btn_rect);
}
}
void LLFloaterIMSessionTab::initBtns()
{
LLRect gear_btn_rect = mGearBtn->getRect();
- LLRect add_btn_rect = getChild<LLButton>("add_btn")->getRect();
- LLRect call_btn_rect = getChild<LLButton>("voice_call_btn")->getRect();
+ LLRect add_btn_rect = mAddBtn->getRect();
+ LLRect call_btn_rect = mVoiceButton->getRect();
S32 gap_width = call_btn_rect.mLeft - add_btn_rect.mRight;
S32 right_shift = gear_btn_rect.getWidth() + gap_width;
add_btn_rect.translate(-right_shift,0);
call_btn_rect.translate(-right_shift,0);
- getChild<LLButton>("add_btn")->setRect(add_btn_rect);
- getChild<LLButton>("voice_call_btn")->setRect(call_btn_rect);
+ mAddBtn->setRect(add_btn_rect);
+ mVoiceButton->setRect(call_btn_rect);
}
// static
@@ -1083,21 +1082,26 @@ void LLFloaterIMSessionTab::saveCollapsedState()
}
BOOL LLFloaterIMSessionTab::handleKeyHere(KEY key, MASK mask )
{
+ BOOL handled = FALSE;
+
if(mask == MASK_ALT)
{
LLFloaterIMContainer* floater_container = LLFloaterIMContainer::getInstance();
if (KEY_RETURN == key && !isTornOff())
{
floater_container->expandConversation();
+ handled = TRUE;
}
if ((KEY_UP == key) || (KEY_LEFT == key))
{
floater_container->selectNextorPreviousConversation(false);
+ handled = TRUE;
}
if ((KEY_DOWN == key ) || (KEY_RIGHT == key))
{
floater_container->selectNextorPreviousConversation(true);
+ handled = TRUE;
}
}
- return TRUE;
+ return handled;
}
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index 302d5a8066..ba80d2369a 100755
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -182,6 +182,9 @@ protected:
LLButton* mTearOffBtn;
LLButton* mCloseBtn;
LLButton* mGearBtn;
+ LLButton* mAddBtn;
+ LLButton* mVoiceButton;
+ LLUICtrl* mTranslationCheckBox;
private:
// Handling selection and contextual menu
diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp
index 586965e5a0..c28657dbcd 100755
--- a/indra/newview/llfolderviewmodelinventory.cpp
+++ b/indra/newview/llfolderviewmodelinventory.cpp
@@ -74,6 +74,7 @@ void LLFolderViewModelInventory::sort( LLFolderViewFolder* folder )
it != end_it;
++it)
{
+ // Recursive call to sort() on child (CHUI-849)
LLFolderViewFolder* child_folderp = *it;
sort(child_folderp);
@@ -129,12 +130,12 @@ void LLFolderViewModelItemInventory::requestSort()
void LLFolderViewModelItemInventory::setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset, std::string::size_type string_size)
{
LLFolderViewModelItemCommon::setPassedFilter(passed, filter_generation, string_offset, string_size);
-
- bool passed_filter_before = mPrevPassedAllFilters;
+ bool before = mPrevPassedAllFilters;
mPrevPassedAllFilters = passedFilter(filter_generation);
- if (passed_filter_before != mPrevPassedAllFilters)
+ if (before != mPrevPassedAllFilters)
{
+ // Need to rearrange the folder if the filtered state of the item changed
LLFolderViewFolder* parent_folder = mFolderViewItem->getParentFolder();
if (parent_folder)
{
@@ -150,11 +151,11 @@ bool LLFolderViewModelItemInventory::filterChildItem( LLFolderViewModelItem* ite
bool continue_filtering = true;
if (item->getLastFilterGeneration() < filter_generation)
{
- // recursive application of the filter for child items
+ // Recursive application of the filter for child items (CHUI-849)
continue_filtering = item->filter( filter );
}
- // track latest generation to pass any child items, for each folder up to root
+ // Update latest generation to pass filter in parent and propagate up to root
if (item->passedFilter())
{
LLFolderViewModelItemInventory* view_model = this;
@@ -174,53 +175,61 @@ bool LLFolderViewModelItemInventory::filter( LLFolderViewFilter& filter)
const S32 filter_generation = filter.getCurrentGeneration();
const S32 must_pass_generation = filter.getFirstRequiredGeneration();
- if (getLastFilterGeneration() >= must_pass_generation
+ if (getLastFilterGeneration() >= must_pass_generation
&& getLastFolderFilterGeneration() >= must_pass_generation
&& !passedFilter(must_pass_generation))
{
// failed to pass an earlier filter that was a subset of the current one
- // go ahead and flag this item as done
+ // go ahead and flag this item as not pass
setPassedFilter(false, filter_generation);
setPassedFolderFilter(false, filter_generation);
return true;
}
- const bool passed_filter_folder = (getInventoryType() == LLInventoryType::IT_CATEGORY)
- ? filter.checkFolder(this)
- : true;
+ // *TODO : Revise the logic for fast pass on less restrictive filter case
+ /*
+ const S32 sufficient_pass_generation = filter.getFirstSuccessGeneration();
+ if (getLastFilterGeneration() >= sufficient_pass_generation
+ && getLastFolderFilterGeneration() >= sufficient_pass_generation
+ && passedFilter(sufficient_pass_generation))
+ {
+ // passed an earlier filter that was a superset of the current one
+ // go ahead and flag this item as pass
+ setPassedFilter(true, filter_generation);
+ setPassedFolderFilter(true, filter_generation);
+ return true;
+ }
+ */
+
+ const bool passed_filter_folder = (getInventoryType() == LLInventoryType::IT_CATEGORY) ? filter.checkFolder(this) : true;
setPassedFolderFilter(passed_filter_folder, filter_generation);
- if(!mChildren.empty()
+ bool continue_filtering = true;
+
+ if (!mChildren.empty()
&& (getLastFilterGeneration() < must_pass_generation // haven't checked descendants against minimum required generation to pass
- || descendantsPassedFilter(must_pass_generation))) // or at least one descendant has passed the minimum requirement
+ || descendantsPassedFilter(must_pass_generation))) // or at least one descendant has passed the minimum requirement
{
// now query children
- for (child_list_t::iterator iter = mChildren.begin(), end_iter = mChildren.end();
- iter != end_iter && filter.getFilterCount() > 0;
- ++iter)
+ for (child_list_t::iterator iter = mChildren.begin(), end_iter = mChildren.end(); iter != end_iter; ++iter)
{
- if (!filterChildItem((*iter), filter))
+ continue_filtering = filterChildItem((*iter), filter);
+ if (!continue_filtering)
{
break;
}
}
}
- // if we didn't use all filter iterations
- // that means we filtered all of our descendants
- // so filter ourselves now
- if (filter.getFilterCount() > 0)
+ // If we didn't use all the filter time that means we filtered all of our descendants so we can filter ourselves now
+ if (continue_filtering)
{
- filter.decrementFilterCount();
-
+ // This is where filter check on the item done (CHUI-849)
const bool passed_filter = filter.check(this);
setPassedFilter(passed_filter, filter_generation, filter.getStringMatchOffset(this), filter.getFilterStringSize());
- return true;
- }
- else
- {
- return false;
+ continue_filtering = !filter.isTimedOut();
}
+ return continue_filtering;
}
LLFolderViewModelInventory* LLInventoryPanel::getFolderViewModel()
@@ -307,8 +316,8 @@ bool LLInventorySort::operator()(const LLFolderViewModelItemInventory* const& a,
}
}
-LLFolderViewModelItemInventory::LLFolderViewModelItemInventory( class LLFolderViewModelInventory& root_view_model )
- : LLFolderViewModelItemCommon(root_view_model),
- mPrevPassedAllFilters(false)
+LLFolderViewModelItemInventory::LLFolderViewModelItemInventory( class LLFolderViewModelInventory& root_view_model ) :
+ LLFolderViewModelItemCommon(root_view_model),
+ mPrevPassedAllFilters(false)
{
}
diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h
index 890d03d1c9..9dcfdfa185 100755
--- a/indra/newview/llfolderviewmodelinventory.h
+++ b/indra/newview/llfolderviewmodelinventory.h
@@ -59,9 +59,8 @@ public:
virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const = 0;
virtual LLToolDragAndDrop::ESource getDragSource() const = 0;
-
protected:
- bool mPrevPassedAllFilters;
+ bool mPrevPassedAllFilters;
};
class LLInventorySort
diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp
index a0f2918bd7..302d21c2e4 100755
--- 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 100755
--- 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 2c20409381..214b177a1b 100755
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -103,6 +103,7 @@ BOOL LLSessionTimeoutTimer::tick()
}
+void notify_of_message(const LLSD& msg, bool is_dnd_msg);
void process_dnd_im(const LLSD& notification)
{
@@ -129,15 +130,9 @@ void process_dnd_im(const LLSD& notification)
fromID,
false,
false); //will need slight refactor to retrieve whether offline message or not (assume online for now)
+ }
- LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
-
- if (im_box)
- {
- im_box->flashConversationItemWidget(sessionID, true);
- }
-
- }
+ notify_of_message(data, true);
}
@@ -158,88 +153,89 @@ static void on_avatar_name_cache_toast(const LLUUID& agent_id,
LLNotificationsUtil::add("IMToast", args, args, boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID()));
}
-void on_new_message(const LLSD& msg)
+void notify_of_message(const LLSD& msg, bool is_dnd_msg)
{
- std::string user_preferences;
- LLUUID participant_id = msg["from_id"].asUUID();
- LLUUID session_id = msg["session_id"].asUUID();
- LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);
+ std::string user_preferences;
+ LLUUID participant_id = msg[is_dnd_msg ? "FROM_ID" : "from_id"].asUUID();
+ LLUUID session_id = msg[is_dnd_msg ? "SESSION_ID" : "session_id"].asUUID();
+ LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);
- // do not show notification which goes from agent
- if (gAgent.getID() == participant_id)
- {
- return;
- }
-
- // determine state of conversations floater
- enum {CLOSED, NOT_ON_TOP, ON_TOP, ON_TOP_AND_ITEM_IS_SELECTED} conversations_floater_status;
+ // do not show notification which goes from agent
+ if (gAgent.getID() == participant_id)
+ {
+ return;
+ }
+ // determine state of conversations floater
+ enum {CLOSED, NOT_ON_TOP, ON_TOP, ON_TOP_AND_ITEM_IS_SELECTED} conversations_floater_status;
- LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
+ LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id);
+ bool store_dnd_message = false; // flag storage of a dnd message
if (!LLFloater::isVisible(im_box) || im_box->isMinimized())
{
conversations_floater_status = CLOSED;
}
else if (!im_box->hasFocus() &&
- !(session_floater && LLFloater::isVisible(session_floater)
- && !session_floater->isMinimized() && session_floater->hasFocus()))
+ !(session_floater && LLFloater::isVisible(session_floater)
+ && !session_floater->isMinimized() && session_floater->hasFocus()))
{
conversations_floater_status = NOT_ON_TOP;
}
else if (im_box->getSelectedSession() != session_id)
{
conversations_floater_status = ON_TOP;
- }
+ }
else
{
conversations_floater_status = ON_TOP_AND_ITEM_IS_SELECTED;
}
- // determine user prefs for this session
- if (session_id.isNull())
- {
- user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions");
- }
- else if(session->isP2PSessionType())
- {
- if (LLAvatarTracker::instance().isBuddy(participant_id))
- {
- user_preferences = gSavedSettings.getString("NotificationFriendIMOptions");
- }
- else
- {
- user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions");
- }
- }
- else if(session->isAdHocSessionType())
- {
- user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions");
- }
- else if(session->isGroupSessionType())
- {
- user_preferences = gSavedSettings.getString("NotificationGroupChatOptions");
- }
-
- // actions:
+ // determine user prefs for this session
+ if (session_id.isNull())
+ {
+ user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions");
+ }
+ else if(session->isP2PSessionType())
+ {
+ if (LLAvatarTracker::instance().isBuddy(participant_id))
+ {
+ user_preferences = gSavedSettings.getString("NotificationFriendIMOptions");
+ }
+ else
+ {
+ user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions");
+ }
+ }
+ else if(session->isAdHocSessionType())
+ {
+ user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions");
+ }
+ else if(session->isGroupSessionType())
+ {
+ user_preferences = gSavedSettings.getString("NotificationGroupChatOptions");
+ }
- // 0. nothing - exit
- if (("none" == user_preferences ||
- ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status)
- && session_floater->isMessagePaneExpanded())
- {
- return;
- }
+ // actions:
- // 1. open floater and [optional] surface it
- if ("openconversations" == user_preferences &&
- (CLOSED == conversations_floater_status
- || NOT_ON_TOP == conversations_floater_status))
- {
- if(!gAgent.isDoNotDisturb())
- {
+ // 0. nothing - exit
+ if (("none" == user_preferences ||
+ ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status)
+ && session_floater->isMessagePaneExpanded())
+ {
+ return;
+ }
+
+ // 1. open floater and [optional] surface it
+ if (("openconversations" == user_preferences &&
+ (CLOSED == conversations_floater_status
+ || NOT_ON_TOP == conversations_floater_status))
+ || is_dnd_msg )
+ {
+ if(!gAgent.isDoNotDisturb())
+ {
// Open conversations floater
LLFloaterReg::showInstance("im_container");
im_box->collapseMessagesPane(false);
@@ -261,57 +257,100 @@ void on_new_message(const LLSD& msg)
}
}
}
- else
- {
- //If in DND mode, allow notification to be stored so upon DND exit
- //useMostItrusiveIMNotification will be called to notify user a message exists
- if(session_id.notNull()
- && participant_id.notNull()
- && !session_floater->isShown())
- {
- LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
- }
- }
- }
+ else
+ {
+ store_dnd_message = true;
+ }
- // 2. Flash line item
- if ("openconversations" == user_preferences
- || ON_TOP == conversations_floater_status
- || ("toast" == user_preferences && ON_TOP != conversations_floater_status)
- || ("flash" == user_preferences && CLOSED == conversations_floater_status))
- {
- if(!LLMuteList::getInstance()->isMuted(participant_id))
- {
- im_box->flashConversationItemWidget(session_id, true);
- }
- }
+ }
- // 3. Flash FUI button
- if (("toast" == user_preferences || "flash" == user_preferences) &&
- (CLOSED == conversations_floater_status
- || NOT_ON_TOP == conversations_floater_status))
- {
- if(!LLMuteList::getInstance()->isMuted(participant_id)
- && !gAgent.isDoNotDisturb())
- {
- gToolBarView->flashCommand(LLCommandId("chat"), true);
- }
- }
+ // 2. Flash line item
+ if ("openconversations" == user_preferences
+ || ON_TOP == conversations_floater_status
+ || ("toast" == user_preferences && ON_TOP != conversations_floater_status)
+ || ("flash" == user_preferences && CLOSED == conversations_floater_status)
+ || is_dnd_msg)
+ {
+ if(!LLMuteList::getInstance()->isMuted(participant_id))
+ {
+ if(gAgent.isDoNotDisturb())
+ {
+ store_dnd_message = true;
+ }
+ else
+ {
+ if (is_dnd_msg && (ON_TOP == conversations_floater_status ||
+ NOT_ON_TOP == conversations_floater_status ||
+ CLOSED == conversations_floater_status))
+ {
+ im_box->highlightConversationItemWidget(session_id, true);
+ }
+ else
+ {
+ im_box->flashConversationItemWidget(session_id, true);
+ }
+ }
+ }
+ }
- // 4. Toast
- if ((("toast" == user_preferences) &&
- (CLOSED == conversations_floater_status
- || NOT_ON_TOP == conversations_floater_status))
- || !session_floater->isMessagePaneExpanded())
+ // 3. Flash FUI button
+ if (("toast" == user_preferences || "flash" == user_preferences) &&
+ (CLOSED == conversations_floater_status
+ || NOT_ON_TOP == conversations_floater_status)
+ && !is_dnd_msg) //prevent flashing FUI button because the conversation floater will have already opened
+ {
+ if(!LLMuteList::getInstance()->isMuted(participant_id))
+ {
+ if(!gAgent.isDoNotDisturb())
+ {
+ gToolBarView->flashCommand(LLCommandId("chat"), true);
+ }
+ else
+ {
+ store_dnd_message = true;
+ }
+ }
+ }
- {
- //Show IM toasts (upper right toasts)
- // Skip toasting for system messages and for nearby chat
- if(session_id.notNull() && participant_id.notNull())
- {
- LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
- }
- }
+ // 4. Toast
+ if ((("toast" == user_preferences) &&
+ (ON_TOP_AND_ITEM_IS_SELECTED != conversations_floater_status))
+ || !session_floater->isMessagePaneExpanded())
+
+ {
+ //Show IM toasts (upper right toasts)
+ // Skip toasting for system messages and for nearby chat
+ if(session_id.notNull() && participant_id.notNull())
+ {
+ if(!is_dnd_msg)
+ {
+ if(gAgent.isDoNotDisturb())
+ {
+ store_dnd_message = true;
+ }
+ else
+ {
+ LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
+ }
+ }
+ }
+ }
+ if (store_dnd_message)
+ {
+ // If in DND mode, allow notification to be stored so upon DND exit
+ // the user will be notified with some limitations (see 'is_dnd_msg' flag checks)
+ if(session_id.notNull()
+ && participant_id.notNull()
+ && !session_floater->isShown())
+ {
+ LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
+ }
+ }
+}
+
+void on_new_message(const LLSD& msg)
+{
+ notify_of_message(msg, false);
}
LLIMModel::LLIMModel()
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index 92f2d33073..3c6974cf6d 100755
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -70,11 +70,8 @@ LLInventoryFilter::LLInventoryFilter(const Params& p)
mFilterSubString(p.substring),
mCurrentGeneration(0),
mFirstRequiredGeneration(0),
- mFirstSuccessGeneration(0),
- mFilterCount(0)
+ mFirstSuccessGeneration(0)
{
- mNextFilterGeneration = mCurrentGeneration + 1;
-
// copy mFilterOps into mDefaultFilterOps
markDefault();
}
@@ -92,9 +89,7 @@ bool LLInventoryFilter::check(const LLFolderViewModelItem* item)
return passed_clipboard;
}
- std::string::size_type string_offset = mFilterSubString.size() ? listener->getSearchableName().find(mFilterSubString) : std::string::npos;
-
- BOOL passed = (mFilterSubString.size() == 0 || string_offset != std::string::npos);
+ bool passed = (mFilterSubString.size() ? listener->getSearchableName().find(mFilterSubString) != std::string::npos : true);
passed = passed && checkAgainstFilterType(listener);
passed = passed && checkAgainstPermissions(listener);
passed = passed && checkAgainstFilterLinks(listener);
@@ -105,17 +100,12 @@ bool LLInventoryFilter::check(const LLFolderViewModelItem* item)
bool LLInventoryFilter::check(const LLInventoryItem* item)
{
- std::string::size_type string_offset = mFilterSubString.size() ? item->getName().find(mFilterSubString) : std::string::npos;
-
+ const bool passed_string = (mFilterSubString.size() ? item->getName().find(mFilterSubString) != std::string::npos : true);
const bool passed_filtertype = checkAgainstFilterType(item);
const bool passed_permissions = checkAgainstPermissions(item);
- const BOOL passed_clipboard = checkAgainstClipboard(item->getUUID());
- const bool passed = (passed_filtertype
- && passed_permissions
- && passed_clipboard
- && (mFilterSubString.size() == 0 || string_offset != std::string::npos));
+ const bool passed_clipboard = checkAgainstClipboard(item->getUUID());
- return passed;
+ return passed_filtertype && passed_permissions && passed_clipboard && passed_string;
}
bool LLInventoryFilter::checkFolder(const LLFolderViewModelItem* item) const
@@ -439,7 +429,7 @@ void LLInventoryFilter::updateFilterTypes(U64 types, U64& current_types)
current_types = types;
if (more_bits_set && fewer_bits_set)
{
- // neither less or more restrive, both simultaneously
+ // neither less or more restrictive, both simultaneously
// so we need to filter from scratch
setModified(FILTER_RESTART);
}
@@ -714,7 +704,7 @@ void LLInventoryFilter::resetDefault()
void LLInventoryFilter::setModified(EFilterModified behavior)
{
mFilterText.clear();
- mCurrentGeneration = mNextFilterGeneration++;
+ mCurrentGeneration++;
if (mFilterModified == FILTER_NONE)
{
@@ -1021,21 +1011,19 @@ LLInventoryFilter::EFolderShow LLInventoryFilter::getShowFolderState() const
return mFilterOps.mShowFolderState;
}
-void LLInventoryFilter::setFilterCount(S32 count)
-{
- mFilterCount = count;
-}
-S32 LLInventoryFilter::getFilterCount() const
+bool LLInventoryFilter::isTimedOut()
{
- return mFilterCount;
+ return mFilterTime.hasExpired();
}
-void LLInventoryFilter::decrementFilterCount()
-{
- mFilterCount--;
+void LLInventoryFilter::resetTime(S32 timeout)
+{
+ mFilterTime.reset();
+ F32 time_in_sec = (F32)(timeout)/1000.0;
+ mFilterTime.setTimerExpirySec(time_in_sec);
}
-S32 LLInventoryFilter::getCurrentGeneration() const
+S32 LLInventoryFilter::getCurrentGeneration() const
{
return mCurrentGeneration;
}
diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h
index 4912b5ca91..ce516af0b9 100755
--- a/indra/newview/llinventoryfilter.h
+++ b/indra/newview/llinventoryfilter.h
@@ -215,12 +215,11 @@ public:
void setModified(EFilterModified behavior = FILTER_RESTART);
// +-------------------------------------------------------------------+
- // + Count
+ // + Time
// +-------------------------------------------------------------------+
- void setFilterCount(S32 count);
- S32 getFilterCount() const;
- void decrementFilterCount();
-
+ void resetTime(S32 timeout);
+ bool isTimedOut();
+
// +-------------------------------------------------------------------+
// + Default
// +-------------------------------------------------------------------+
@@ -262,13 +261,15 @@ private:
const std::string mName;
S32 mCurrentGeneration;
+ // The following makes checking for pass/no pass possible even if the item is not checked against the current generation
+ // Any item that *did not pass* the "required generation" will *not pass* the current one
+ // Any item that *passes* the "success generation" will *pass* the current one
S32 mFirstRequiredGeneration;
S32 mFirstSuccessGeneration;
- S32 mNextFilterGeneration;
- S32 mFilterCount;
EFilterModified mFilterModified;
-
+ LLTimer mFilterTime;
+
std::string mFilterText;
std::string mEmptyLookupMessage;
};
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index cf1fd4c0d0..e5b9e11d48 100755
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -192,7 +192,7 @@ LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )
p.show_item_link_overlays = mShowItemLinkOverlays;
p.root = NULL;
p.options_menu = "menu_inventory.xml";
-
+
return LLUICtrlFactory::create<LLFolderView>(p);
}
@@ -396,6 +396,7 @@ LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState()
return getFilter().getShowFolderState();
}
+// Called when something changed in the global model (new item, item coming through the wire, rename, move, etc...) (CHUI-849)
void LLInventoryPanel::modelChanged(U32 mask)
{
static LLFastTimer::DeclareTimer FTM_REFRESH("Inventory Refresh");
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 2d7454b636..379bbc5f8d 100755
--- 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,20 +641,53 @@ 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;
}
+bool LLLogChat::isNearbyTranscriptExist()
+{
+ std::vector<std::string> list_of_transcriptions;
+ LLLogChat::getListOfTranscriptFiles(list_of_transcriptions);
+
+ std::string file_name;
+ file_name = makeLogFileName("chat");
+ BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)
+ {
+ if (transcript_file_name == file_name)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
//*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 written like "Object <actual_object's_name>"
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index e819f00dd9..bd70dbaac9 100755
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -67,7 +67,8 @@ 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);
+ static bool isNearbyTranscriptExist();
private:
static std::string cleanFileName(std::string filename);
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index d6535c88e9..53deded2f2 100755
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -130,6 +130,8 @@ BOOL LLPanelMainInventory::postBuild()
mFilterTabs = getChild<LLTabContainer>("inventory filter tabs");
mFilterTabs->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterSelected, this));
+ mCounterCtrl = getChild<LLUICtrl>("ItemcountText");
+
//panel->getFilter().markDefault();
// Set up the default inv. panel/filter settings.
@@ -566,7 +568,7 @@ void LLPanelMainInventory::draw()
void LLPanelMainInventory::updateItemcountText()
{
// *TODO: Calling setlocale() on each frame may be inefficient.
- LLLocale locale(LLStringUtil::getLocale());
+ //LLLocale locale(LLStringUtil::getLocale());
std::string item_count_string;
LLResMgr::getInstance()->getIntegerString(item_count_string, gInventory.getItemCount());
@@ -589,8 +591,7 @@ void LLPanelMainInventory::updateItemcountText()
text = getString("ItemcountUnknown");
}
- // *TODO: Cache the LLUICtrl* for the ItemcountText control
- getChild<LLUICtrl>("ItemcountText")->setValue(text);
+ mCounterCtrl->setValue(text);
}
void LLPanelMainInventory::onFocusReceived()
diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h
index 899931aa89..394b004e20 100755
--- a/indra/newview/llpanelmaininventory.h
+++ b/indra/newview/llpanelmaininventory.h
@@ -121,6 +121,7 @@ private:
LLFilterEditor* mFilterEditor;
LLTabContainer* mFilterTabs;
+ LLUICtrl* mCounterCtrl;
LLHandle<LLFloater> mFinderHandle;
LLInventoryPanel* mActivePanel;
bool mResortActivePanel;
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 4138558bad..e0b1c3abba 100755
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -28,6 +28,8 @@
// libs
#include "llavatarname.h"
+#include "llconversationview.h"
+#include "llfloaterimcontainer.h"
#include "llfloaterreg.h"
#include "llfloatersidepanelcontainer.h"
#include "llmenubutton.h"
@@ -48,34 +50,49 @@
#include "llavataractions.h"
#include "llavatarlist.h"
#include "llavatarlistitem.h"
+#include "llavatarnamecache.h"
#include "llcallingcard.h" // for LLAvatarTracker
+#include "llcallbacklist.h"
+#include "llerror.h"
+#include "llfacebookconnect.h"
#include "llfloateravatarpicker.h"
-//#include "llfloaterminiinspector.h"
#include "llfriendcard.h"
#include "llgroupactions.h"
#include "llgrouplist.h"
#include "llinventoryobserver.h"
#include "llnetmap.h"
#include "llpanelpeoplemenus.h"
+#include "llparticipantlist.h"
+#include "llpersonfolderview.h"
+#include "llpersonmodelcommon.h"
+#include "llpersontabview.h"
#include "llsidetraypanelcontainer.h"
#include "llrecentpeople.h"
#include "llviewercontrol.h" // for gSavedSettings
#include "llviewermenu.h" // for gMenuHolder
#include "llvoiceclient.h"
#include "llworld.h"
+#include "llsociallist.h"
#include "llspeakers.h"
+#include "llfloaterwebcontent.h"
+
+#include "llagentui.h"
+#include "llslurl.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 FBCTESTTWO_TAB_NAME = "fbctesttwo_panel";
static const std::string COLLAPSED_BY_USER = "collapsed_by_user";
+
/** Comparator for comparing avatar items by last interaction date */
class LLAvatarItemRecentComparator : public LLAvatarItemComparator
{
@@ -489,23 +506,73 @@ 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(),
+ mPersonFolderView(NULL),
+ mTryToConnectToFbc(true),
mTabContainer(NULL),
mOnlineFriendList(NULL),
mAllFriendList(NULL),
mNearbyList(NULL),
mRecentList(NULL),
mGroupList(NULL),
- mMiniMap(NULL)
+ mMiniMap(NULL),
+ mFacebookListGeneration(0)
{
mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this));
mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this));
mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this));
+ mFacebookListUpdater = new LLFbcTestListUpdater(boost::bind(&LLPanelPeople::updateFacebookList, 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.testaddFBC", boost::bind(&LLPanelPeople::onFacebookTestAddClicked, this));
+ mCommitCallbackRegistrar.add("People.testaddFBCFolderView", boost::bind(&LLPanelPeople::addTestParticipant, this));
+ mCommitCallbackRegistrar.add("People.testFBCCheckin", boost::bind(&LLPanelPeople::onFacebookCheckinClicked, 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 +599,14 @@ LLPanelPeople::~LLPanelPeople()
delete mNearbyListUpdater;
delete mFriendListUpdater;
delete mRecentListUpdater;
+ delete mFacebookListUpdater;
if(LLVoiceClient::instanceExists())
{
LLVoiceClient::getInstance()->removeObserver(this);
}
+
+ if (mFbcTestBrowserHandle.get()) mFbcTestBrowserHandle.get()->die();
}
void LLPanelPeople::onFriendsAccordionExpandedCollapsed(LLUICtrl* ctrl, const LLSD& param, LLAvatarList* avatar_list)
@@ -571,6 +641,7 @@ BOOL LLPanelPeople::postBuild()
getChild<LLFilterEditor>("friends_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
getChild<LLFilterEditor>("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
getChild<LLFilterEditor>("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
+ getChild<LLFilterEditor>("fbc_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
mTabContainer = getChild<LLTabContainer>("tabs");
mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2));
@@ -616,6 +687,54 @@ BOOL LLPanelPeople::postBuild()
mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
+ //===Temporary ========================================================================
+
+ LLPanel * social_tab = getChild<LLPanel>(FBCTEST_TAB_NAME);
+ mFacebookFriends = social_tab->getChild<LLSocialList>("facebook_friends");
+ // Note: we use the same updater for both test lists (brute force but OK since it's temporary)
+ social_tab->setVisibleCallback(boost::bind(&Updater::setActive, mFacebookListUpdater, _2));
+
+ //===Test START========================================================================
+
+ LLPanel * socialtwo_tab = getChild<LLPanel>(FBCTESTTWO_TAB_NAME);
+ socialtwo_tab->setVisibleCallback(boost::bind(&Updater::setActive, mFacebookListUpdater, _2));
+
+ //Create folder view
+ LLPersonModelCommon* base_item = new LLPersonModelCommon(mPersonFolderViewModel);
+
+ LLPersonFolderView::Params folder_view_params(LLUICtrlFactory::getDefaultParams<LLPersonFolderView>());
+
+ folder_view_params.parent_panel = socialtwo_tab;
+ folder_view_params.listener = base_item;
+ folder_view_params.view_model = &mPersonFolderViewModel;
+ folder_view_params.root = NULL;
+ folder_view_params.use_ellipses = true;
+ folder_view_params.use_label_suffix = true;
+ folder_view_params.options_menu = "menu_conversation.xml";
+ folder_view_params.name = "fbcfolderview";
+ mPersonFolderView = LLUICtrlFactory::create<LLPersonFolderView>(folder_view_params);
+
+ //Create scroller
+ LLRect scroller_view_rect = socialtwo_tab->getRect();
+ scroller_view_rect.mTop -= 2+27; // 27 is the height of the top toolbar
+ scroller_view_rect.mRight -= 4;
+ scroller_view_rect.mLeft += 2;
+ LLScrollContainer::Params scroller_params(LLUICtrlFactory::getDefaultParams<LLFolderViewScrollContainer>());
+ scroller_params.rect(scroller_view_rect);
+
+ LLScrollContainer* scroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
+ socialtwo_tab->addChildInBack(scroller);
+ scroller->addChild(mPersonFolderView);
+ scroller->setFollowsAll();
+ mPersonFolderView->setScrollContainer(scroller);
+ mPersonFolderView->setFollowsAll();
+
+ gIdleCallbacks.addFunction(idle, this);
+
+ //===Test END========================================================================
+
+
+
setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false);
setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false);
setSortOrder(mNearbyList, (ESortOrder)gSavedSettings.getU32("NearbyPeopleSortOrder"), false);
@@ -664,6 +783,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
@@ -686,6 +814,12 @@ void LLPanelPeople::onChange(EStatusType status, const std::string &channelURI,
updateButtons();
}
+void LLPanelPeople::idle(void * user_data)
+{
+ LLPanelPeople * self = static_cast<LLPanelPeople *>(user_data);
+ self->mPersonFolderView->update();
+}
+
void LLPanelPeople::updateFriendListHelpText()
{
// show special help text for just created account to help finding friends. EXT-4836
@@ -786,6 +920,62 @@ void LLPanelPeople::updateRecentList()
mRecentList->setDirty();
}
+void LLPanelPeople::updateFacebookList()
+{
+ if (mTryToConnectToFbc)
+ {
+ // try to reconnect to facebook!
+ LLFacebookConnect::instance().tryToReconnectToFacebook();
+
+ // don't try again
+ mTryToConnectToFbc = false;
+
+ // stop updating
+ mFacebookListUpdater->setActive(false);
+ }
+
+ if (LLFacebookConnect::instance().generation() != mFacebookListGeneration)
+ {
+ mFacebookListGeneration = LLFacebookConnect::instance().generation();
+ LLSD friends = LLFacebookConnect::instance().getContent();
+
+ mFacebookFriends->clear();
+ LLPersonTabModel::tab_type tab_type;
+ LLAvatarTracker& avatar_tracker = LLAvatarTracker::instance();
+
+ for (LLSD::map_const_iterator i = friends.beginMap(); i != friends.endMap(); ++i)
+ {
+ std::string name = i->second["name"].asString();
+ LLUUID agent_id = i->second.has("agent_id") ? i->second["agent_id"].asUUID() : LLUUID(NULL);
+ bool second_life_buddy = agent_id.notNull() ? avatar_tracker.isBuddy(agent_id) : false;
+
+ //add to avatar list
+ mFacebookFriends->addNewItem(agent_id, name, false);
+
+ if(!second_life_buddy)
+ {
+ //FB+SL but not SL friend
+ if (agent_id.notNull())
+ {
+ tab_type = LLPersonTabModel::FB_SL_NON_SL_FRIEND;
+ }
+ //FB only friend
+ else
+ {
+ tab_type = LLPersonTabModel::FB_ONLY_FRIEND;
+ }
+
+ //Add to person tab model
+ LLPersonTabModel * person_tab_model = dynamic_cast<LLPersonTabModel *>(mPersonFolderView->getPersonTabModelByIndex(tab_type));
+ if (person_tab_model)
+ {
+ addParticipantToModel(person_tab_model, agent_id, name);
+ }
+ }
+ }
+ }
+}
+
void LLPanelPeople::updateButtons()
{
std::string cur_tab = getActiveTabName();
@@ -870,6 +1060,13 @@ LLUUID LLPanelPeople::getCurrentItemID() const
if (cur_tab == BLOCKED_TAB_NAME)
return LLUUID::null; // FIXME?
+
+ if (cur_tab == FBCTEST_TAB_NAME)
+ return LLUUID::null;
+
+ if (cur_tab == FBCTESTTWO_TAB_NAME)
+ return LLUUID::null;
+
llassert(0 && "unknown tab selected");
return LLUUID::null;
@@ -893,6 +1090,10 @@ 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 if (cur_tab == FBCTESTTWO_TAB_NAME)
+ return;
else
llassert(0 && "unknown tab selected");
@@ -989,23 +1190,23 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string)
{
// store accordion tabs opened/closed state before any manipulation with accordion tabs
if (!saved_filter.empty())
- {
- notifyChildren(LLSD().with("action","store_state"));
- }
+ {
+ notifyChildren(LLSD().with("action","store_state"));
+ }
mOnlineFriendList->setNameFilter(filter);
mAllFriendList->setNameFilter(filter);
- setAccordionCollapsedByUser("tab_online", false);
- setAccordionCollapsedByUser("tab_all", false);
- showFriendsAccordionsIfNeeded();
+ setAccordionCollapsedByUser("tab_online", false);
+ setAccordionCollapsedByUser("tab_all", false);
+ showFriendsAccordionsIfNeeded();
// restore accordion tabs state _after_ all manipulations
if(saved_filter.empty())
- {
- notifyChildren(LLSD().with("action","restore_state"));
- }
-}
+ {
+ notifyChildren(LLSD().with("action","restore_state"));
+ }
+ }
else if (cur_tab == GROUP_TAB_NAME)
{
mGroupList->setNameFilter(filter);
@@ -1014,6 +1215,11 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string)
{
mRecentList->setNameFilter(filter);
}
+ else if (cur_tab == FBCTESTTWO_TAB_NAME)
+ {
+ mPersonFolderViewModel.getFilter().setFilterSubString(filter);
+ mPersonFolderView->requestArrange();
+ }
}
void LLPanelPeople::onTabSelected(const LLSD& param)
@@ -1225,7 +1431,7 @@ void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata)
mAllFriendList->showPermissions(show_permissions);
mOnlineFriendList->showPermissions(show_permissions);
}
-}
+ }
void LLPanelPeople::onGroupsViewSortMenuItemClicked(const LLSD& userdata)
{
@@ -1446,4 +1652,107 @@ bool LLPanelPeople::isAccordionCollapsedByUser(const std::string& name)
return isAccordionCollapsedByUser(getChild<LLUICtrl>(name));
}
+void LLPanelPeople::addTestParticipant()
+{
+ std::string suffix("Aa");
+ std::string prefix("FB Name");
+ LLPersonTabModel * person_tab_model;
+ LLUUID agentID;
+ std::string name;
+ LLPersonTabModel::tab_type tab_type;
+
+ for(int i = 0; i < 300; ++i)
+ {
+ //Adds FB+SL people that aren't yet SL friends
+ if(i < 10)
+ {
+ tab_type = LLPersonTabModel::FB_SL_NON_SL_FRIEND;
+ agentID = gAgent.getID();
+ }
+ //Adds FB only friends
+ else
+ {
+ tab_type = LLPersonTabModel::FB_ONLY_FRIEND;
+ agentID = LLUUID(NULL);
+ }
+
+ person_tab_model = dynamic_cast<LLPersonTabModel *>(mPersonFolderView->getPersonTabModelByIndex(tab_type));
+ name = prefix + " " + suffix;
+ addParticipantToModel(person_tab_model, agentID, name);
+ // Next suffix : Aa, Ab, Ac ... Az, Ba, Bb, Bc ... Bz, Ca, Cb ...
+ suffix[1]+=1;
+ if (suffix[1]=='{')
+ {
+ suffix[1]='a';
+ suffix[0]+=1;
+ if (suffix[0]=='[')
+ suffix[0]='A';
+ }
+ }
+}
+
+void LLPanelPeople::addParticipantToModel(LLPersonTabModel * person_folder_model, const LLUUID& agent_id, const std::string& name)
+{
+ LLPersonModel* person_model = NULL;
+
+ LLAvatarName avatar_name;
+ bool has_name = agent_id.notNull() ? LLAvatarNameCache::get(agent_id, &avatar_name) : false;
+ std::string avatar_name_string;
+
+ if(has_name)
+ {
+ avatar_name_string = avatar_name.getDisplayName();
+ }
+
+ person_model = new LLPersonModel(agent_id, avatar_name_string, name, mPersonFolderViewModel);
+ person_folder_model->addParticipant(person_model);
+}
+
+void LLPanelPeople::onLoginFbcButtonClicked()
+{
+ if (LLFacebookConnect::instance().getConnected())
+ {
+ LLFacebookConnect::instance().disconnectFromFacebook();
+ }
+ else
+ {
+ LLFacebookConnect::instance().getConnectionToFacebook();
+ }
+}
+
+void LLPanelPeople::onFacebookCheckinClicked()
+{
+ // Get the local SLURL
+ LLSLURL slurl;
+ LLAgentUI::buildSLURL(slurl);
+
+ LLFacebookConnect::instance().postCheckinMessage("Here I am in SL!", slurl.getSLURLString());
+}
+
+void LLPanelPeople::onFacebookAppRequestClicked()
+{
+}
+
+void LLPanelPeople::onFacebookAppSendClicked()
+{
+}
+
+static LLFastTimer::DeclareTimer FTM_AVATAR_LIST_TEST("avatar list test");
+
+void LLPanelPeople::onFacebookTestAddClicked()
+{
+ LLFastTimer _(FTM_AVATAR_LIST_TEST);
+
+ mFacebookFriends->clear();
+
+ LL_INFOS("LLPanelPeople") << "start adding 300 users" << LL_ENDL;
+
+ for(int i = 0; i < 300; ++i)
+ {
+ mFacebookFriends->addNewItem(LLUUID(), "Test", false);
+ }
+
+ LL_INFOS("LLPanelPeople") << "finished adding 300 users" << LL_ENDL;
+}
+
// EOF
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index 4740964dee..f617517392 100755
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -22,7 +22,7 @@
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
- */
+ */
#ifndef LL_LLPANELPEOPLE_H
#define LL_LLPANELPEOPLE_H
@@ -30,12 +30,17 @@
#include <llpanel.h>
#include "llcallingcard.h" // for avatar tracker
+#include "llpersonmodelcommon.h"
+#include "llfloaterwebcontent.h"
#include "llvoiceclient.h"
class LLAvatarList;
+class LLAvatarListSocial;
class LLAvatarName;
class LLFilterEditor;
class LLGroupList;
+class LLPersonFolderView;
+class LLSocialList;
class LLMenuButton;
class LLTabContainer;
@@ -55,6 +60,13 @@ public:
// when voice is available
/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+ static void idle(void * user_data);
+
+ void addTestParticipant();
+ void addParticipantToModel(LLPersonTabModel * session_model, const LLUUID& agent_id, const std::string& name);
+
+ bool mTryToConnectToFbc;
+
// internals
class Updater;
@@ -75,6 +87,7 @@ private:
void updateFriendList();
void updateNearbyList();
void updateRecentList();
+ void updateFacebookList();
bool isItemsFreeOfFriends(const uuid_vec_t& uuids);
@@ -106,6 +119,12 @@ private:
void onGroupsViewSortMenuItemClicked(const LLSD& userdata);
void onRecentViewSortMenuItemClicked(const LLSD& userdata);
+ void onLoginFbcButtonClicked();
+ void onFacebookAppRequestClicked();
+ void onFacebookAppSendClicked();
+ void onFacebookTestAddClicked();
+ void onFacebookCheckinClicked();
+
bool onFriendsViewSortMenuItemCheck(const LLSD& userdata);
bool onRecentViewSortMenuItemCheck(const LLSD& userdata);
bool onNearbyViewSortMenuItemCheck(const LLSD& userdata);
@@ -132,16 +151,25 @@ private:
LLAvatarList* mNearbyList;
LLAvatarList* mRecentList;
LLGroupList* mGroupList;
+ LLSocialList* mFacebookFriends;
+ S32 mFacebookListGeneration;
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* mFacebookListUpdater;
Updater* mButtonsUpdater;
+ LLMenuButton* mFBCGearButton;
LLHandle< LLFloater > mPicker;
+
+ LLPersonFolderViewModel mPersonFolderViewModel;
+ LLPersonFolderView* mPersonFolderView;
};
#endif //LL_LLPANELPEOPLE_H
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index c53760bca1..b5c9f4a310 100755
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -27,6 +27,7 @@
#include "llviewerprecompiledheaders.h"
#include "llavatarnamecache.h"
+#include "llerror.h"
#include "llimview.h"
#include "llfloaterimcontainer.h"
#include "llparticipantlist.h"
@@ -401,6 +402,23 @@ void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id)
adjustParticipant(avatar_id);
}
+static LLFastTimer::DeclareTimer FTM_FOLDERVIEW_TEST("add test avatar agents");
+
+
+void LLParticipantList::addTestAvatarAgents()
+{
+ LLFastTimer _(FTM_FOLDERVIEW_TEST);
+
+ LL_INFOS("LLParticipantList") << "start adding 300 users" << LL_ENDL;
+
+ for(int i = 0; i < 300; ++i)
+ {
+ addAvatarIDExceptAgent(LLUUID().generateNewID());
+ }
+
+ LL_INFOS("LLParticipantList") << "finished adding 300 users" << LL_ENDL;
+}
+
void LLParticipantList::adjustParticipant(const LLUUID& speaker_id)
{
LLPointer<LLSpeaker> speakerp = mSpeakerMgr->findSpeaker(speaker_id);
diff --git a/indra/newview/llparticipantlist.h b/indra/newview/llparticipantlist.h
index 3a3ae76604..936e289c08 100755
--- a/indra/newview/llparticipantlist.h
+++ b/indra/newview/llparticipantlist.h
@@ -50,6 +50,7 @@ public:
* @param[in] avatar_id - Avatar UUID to be added into the list
*/
void addAvatarIDExceptAgent(const LLUUID& avatar_id);
+ void addTestAvatarAgents();
/**
* Refreshes the participant list.
diff --git a/indra/newview/llpersonfolderview.cpp b/indra/newview/llpersonfolderview.cpp
new file mode 100644
index 0000000000..7e969fc96c
--- /dev/null
+++ b/indra/newview/llpersonfolderview.cpp
@@ -0,0 +1,149 @@
+/**
+* @file llpersonfolderview.cpp
+* @brief Implementation of llpersonfolderview
+* @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 "llpersonfolderview.h"
+
+#include "llpersontabview.h"
+
+
+LLPersonFolderView::LLPersonFolderView(const Params &p) :
+LLFolderView(p),
+ mConversationsEventStream("ConversationsEventsTwo")
+{
+ rename("Persons"); // For tracking!
+ mConversationsEventStream.listen("ConversationsRefresh", boost::bind(&LLPersonFolderView::onConversationModelEvent, this, _1));
+
+ createPersonTabs();
+}
+
+LLPersonFolderView::~LLPersonFolderView()
+{
+ mConversationsEventStream.stopListening("ConversationsRefresh");
+}
+
+BOOL LLPersonFolderView::handleMouseDown( S32 x, S32 y, MASK mask )
+{
+ LLFolderViewItem * item = getCurSelectedItem();
+
+ //Will disable highlight on tab
+ if(item)
+ {
+ LLPersonTabView * person_tab= dynamic_cast<LLPersonTabView *>(item);
+ if(person_tab)
+ {
+ person_tab->highlight = false;
+ }
+ else
+ {
+ person_tab = dynamic_cast<LLPersonTabView *>(item->getParent());
+ person_tab->highlight = false;
+ }
+ }
+
+ mKeyboardSelection = FALSE;
+ mSearchString.clear();
+
+ LLEditMenuHandler::gEditMenuHandler = this;
+
+ return LLView::handleMouseDown( x, y, mask );
+}
+
+void LLPersonFolderView::createPersonTabs()
+{
+ createPersonTab(LLPersonTabModel::FB_SL_NON_SL_FRIEND, "SL residents you may want to friend");
+ createPersonTab(LLPersonTabModel::FB_ONLY_FRIEND, "Invite people you know to SL");
+}
+
+void LLPersonFolderView::createPersonTab(LLPersonTabModel::tab_type tab_type, const std::string& tab_name)
+{
+ //Create a person tab
+ LLPersonTabModel* item = new LLPersonTabModel(tab_type, tab_name, *mViewModel);
+ LLPersonTabView::Params params;
+ params.name = item->getDisplayName();
+ params.root = this;
+ params.listener = item;
+ params.tool_tip = params.name;
+ LLPersonTabView * widget = LLUICtrlFactory::create<LLPersonTabView>(params);
+ widget->addToFolder(this);
+
+ mIndexToFolderMap[tab_type] = item->getID();
+ mPersonFolderModelMap[item->getID()] = item;
+ mPersonFolderViewMap[item->getID()] = widget;
+}
+
+bool LLPersonFolderView::onConversationModelEvent(const LLSD &event)
+{
+ std::string type = event.get("type").asString();
+ LLUUID folder_id = event.get("folder_id").asUUID();
+ LLUUID person_id = event.get("person_id").asUUID();
+
+ if(type == "add_participant")
+ {
+ LLPersonTabModel * person_tab_model = dynamic_cast<LLPersonTabModel *>(mPersonFolderModelMap[folder_id]);
+ LLPersonTabView * person_tab_view = dynamic_cast<LLPersonTabView *>(mPersonFolderViewMap[folder_id]);
+
+ if(person_tab_model)
+ {
+ LLPersonModel * person_model = person_tab_model->findParticipant(person_id);
+
+ if(person_model)
+ {
+ LLPersonView * person_view = createConversationViewParticipant(person_model);
+ person_view->addToFolder(person_tab_view);
+ }
+ }
+ }
+
+ return false;
+}
+
+LLPersonView * LLPersonFolderView::createConversationViewParticipant(LLPersonModel * item)
+{
+ LLPersonView::Params params;
+
+ params.name = item->getDisplayName();
+ params.root = this;
+ params.listener = item;
+
+ //24 should be loaded from .xml somehow
+ params.rect = LLRect (0, 24, getRect().getWidth(), 0);
+ params.tool_tip = params.name;
+
+ return LLUICtrlFactory::create<LLPersonView>(params);
+}
+
+LLPersonTabModel * LLPersonFolderView::getPersonTabModelByIndex(LLPersonTabModel::tab_type tab_type)
+{
+ return mPersonFolderModelMap[mIndexToFolderMap[tab_type]];
+}
+
+LLPersonTabView * LLPersonFolderView::getPersonTabViewByIndex(LLPersonTabModel::tab_type tab_type)
+{
+ return mPersonFolderViewMap[mIndexToFolderMap[tab_type]];
+}
diff --git a/indra/newview/llpersonfolderview.h b/indra/newview/llpersonfolderview.h
new file mode 100644
index 0000000000..85dec6515d
--- /dev/null
+++ b/indra/newview/llpersonfolderview.h
@@ -0,0 +1,70 @@
+/**
+* @file llpersonfolderview.h
+* @brief Header file for llpersonfolderview
+* @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_LLPERSONFOLDERVIEW_H
+#define LL_LLPERSONFOLDERVIEW_H
+
+#include "llevents.h"
+#include "llfolderview.h"
+#include "llpersonmodelcommon.h"
+
+class LLPersonTabView;
+class LLPersonView;
+class LLPersonModel;
+
+typedef std::map<LLUUID, LLPersonTabModel *> person_folder_model_map;
+typedef std::map<LLUUID, LLPersonTabView *> person_folder_view_map;
+
+class LLPersonFolderView : public LLFolderView
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLFolderView::Params>
+ {
+ Params()
+ {}
+ };
+
+ LLPersonFolderView(const Params &p);
+ ~LLPersonFolderView();
+
+ BOOL handleMouseDown( S32 x, S32 y, MASK mask );
+
+ void createPersonTabs();
+ void createPersonTab(LLPersonTabModel::tab_type tab_type, const std::string& tab_name);
+ bool onConversationModelEvent(const LLSD &event);
+ LLPersonView * createConversationViewParticipant(LLPersonModel * item);
+
+ LLPersonTabModel * getPersonTabModelByIndex(LLPersonTabModel::tab_type tab_type);
+ LLPersonTabView * getPersonTabViewByIndex(LLPersonTabModel::tab_type tab_type);
+
+ person_folder_model_map mPersonFolderModelMap;
+ person_folder_view_map mPersonFolderViewMap;
+ std::map<LLPersonTabModel::tab_type, LLUUID> mIndexToFolderMap;
+ LLEventStream mConversationsEventStream;
+};
+
+#endif // LL_LLPERSONFOLDERVIEW_H
+
diff --git a/indra/newview/llpersonmodelcommon.cpp b/indra/newview/llpersonmodelcommon.cpp
new file mode 100644
index 0000000000..73239dcb8d
--- /dev/null
+++ b/indra/newview/llpersonmodelcommon.cpp
@@ -0,0 +1,313 @@
+/**
+* @file llavatarfolder.cpp
+* @brief Implementation of llavatarfolder
+* @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 "llpersonmodelcommon.h"
+
+#include "llevents.h"
+#include "llsdutil.h"
+#include "llstring.h"
+
+//
+// LLPersonModelCommon
+//
+
+LLPersonModelCommon::LLPersonModelCommon(std::string display_name, LLFolderViewModelInterface& root_view_model) :
+ LLFolderViewModelItemCommon(root_view_model),
+ mLabelSuffix(""),
+ mID(LLUUID().generateNewID())
+{
+ renameItem(display_name);
+}
+
+LLPersonModelCommon::LLPersonModelCommon(std::string display_name, std::string suffix, LLFolderViewModelInterface& root_view_model) :
+LLFolderViewModelItemCommon(root_view_model),
+ mID(LLUUID().generateNewID())
+{
+ mLabelSuffix = suffix;
+ renameItem(display_name);
+}
+
+LLPersonModelCommon::LLPersonModelCommon(LLFolderViewModelInterface& root_view_model) :
+ LLFolderViewModelItemCommon(root_view_model),
+ mName(""),
+ mLabelSuffix(""),
+ mSearchableName(""),
+ mPrevPassedAllFilters(false),
+ mID(LLUUID().generateNewID())
+{
+}
+
+LLPersonModelCommon::~LLPersonModelCommon()
+{
+
+}
+
+BOOL LLPersonModelCommon::renameItem(const std::string& new_name)
+{
+ mName = new_name;
+ mSearchableName = new_name + " " + mLabelSuffix;
+ LLStringUtil::toUpper(mSearchableName);
+ return TRUE;
+}
+
+void LLPersonModelCommon::postEvent(const std::string& event_type, LLPersonTabModel* folder, LLPersonModel* person)
+{
+ LLUUID folder_id = folder->getID();
+ LLUUID person_id = person->getID();
+ LLSD event(LLSDMap("type", event_type)("folder_id", folder_id)("person_id", person_id));
+ LLEventPumps::instance().obtain("ConversationsEventsTwo").post(event);
+}
+
+// Virtual action callbacks
+void LLPersonModelCommon::performAction(LLInventoryModel* model, std::string action)
+{
+}
+
+void LLPersonModelCommon::openItem( void )
+{
+}
+
+void LLPersonModelCommon::closeItem( void )
+{
+}
+
+void LLPersonModelCommon::previewItem( void )
+{
+}
+
+void LLPersonModelCommon::showProperties(void)
+{
+}
+
+bool LLPersonModelCommon::filter( LLFolderViewFilter& filter)
+{
+/*
+ Hack: for the moment, we always apply the filter if we're called
+ if (!filter.isModified())
+ {
+ llinfos << "Merov : LLPersonModelCommon::filter, exit, no modif" << llendl;
+ return true;
+ }
+ */
+ if (!mChildren.empty())
+ {
+ // If the current instance has children, it's a "person folder" and always passes filters (we do not filter out empty folders)
+ setPassedFilter(1, filter.getCurrentGeneration());
+ // Call filter recursively on all children
+ for (child_list_t::iterator iter = mChildren.begin(), end_iter = mChildren.end();
+ iter != end_iter;
+ ++iter)
+ {
+ LLPersonModelCommon* item = dynamic_cast<LLPersonModelCommon*>(*iter);
+ item->filter(filter);
+ }
+ }
+ else
+ {
+ // If there's no children, the current instance is a person and we check and set the passed filter flag on it
+ const bool passed_filter = filter.check(this);
+ setPassedFilter(passed_filter, filter.getCurrentGeneration(), filter.getStringMatchOffset(this), filter.getFilterStringSize());
+ }
+
+ filter.clearModified();
+ return true;
+}
+
+void LLPersonModelCommon::setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset, std::string::size_type string_size)
+{
+ LLFolderViewModelItemCommon::setPassedFilter(passed, filter_generation, string_offset, string_size);
+ bool before = mPrevPassedAllFilters;
+ mPrevPassedAllFilters = passedFilter(filter_generation);
+
+ if (before != mPrevPassedAllFilters)
+ {
+ // Need to rearrange the folder if the filtered state of the item changed
+ LLFolderViewFolder* parent_folder = mFolderViewItem->getParentFolder();
+ if (parent_folder)
+ {
+ parent_folder->requestArrange();
+ }
+ }
+}
+
+
+//
+// LLPersonTabModel
+//
+
+LLPersonTabModel::LLPersonTabModel(tab_type tab_type, std::string display_name, LLFolderViewModelInterface& root_view_model) :
+LLPersonModelCommon(display_name,root_view_model),
+mTabType(tab_type)
+{
+
+}
+
+LLPersonTabModel::LLPersonTabModel(LLFolderViewModelInterface& root_view_model) :
+LLPersonModelCommon(root_view_model)
+{
+
+}
+
+void LLPersonTabModel::addParticipant(LLPersonModel* participant)
+{
+ addChild(participant);
+ postEvent("add_participant", this, participant);
+}
+
+void LLPersonTabModel::removeParticipant(LLPersonModel* participant)
+{
+ removeChild(participant);
+ postEvent("remove_participant", this, participant);
+}
+
+void LLPersonTabModel::removeParticipant(const LLUUID& participant_id)
+{
+ LLPersonModel* participant = findParticipant(participant_id);
+ if (participant)
+ {
+ removeParticipant(participant);
+ }
+}
+
+void LLPersonTabModel::clearParticipants()
+{
+ clearChildren();
+}
+
+LLPersonModel* LLPersonTabModel::findParticipant(const LLUUID& person_id)
+{
+ LLPersonModel * person_model = NULL;
+ child_list_t::iterator iter;
+
+ for(iter = mChildren.begin(); iter != mChildren.end(); ++iter)
+ {
+ person_model = static_cast<LLPersonModel *>(*iter);
+
+ if(person_model->getID() == person_id)
+ {
+ break;
+ }
+ }
+
+ return iter == mChildren.end() ? NULL : person_model;
+}
+
+//
+// LLPersonModel
+//
+
+LLPersonModel::LLPersonModel(const LLUUID& agent_id, const std::string display_name, const std::string suffix, LLFolderViewModelInterface& root_view_model) :
+LLPersonModelCommon(display_name, suffix, root_view_model),
+mAgentID(agent_id)
+{
+}
+
+LLPersonModel::LLPersonModel(LLFolderViewModelInterface& root_view_model) :
+LLPersonModelCommon(root_view_model),
+mAgentID(LLUUID(NULL))
+{
+}
+
+LLUUID LLPersonModel::getAgentID()
+{
+ return mAgentID;
+}
+
+//
+// LLPersonViewFilter
+//
+
+LLPersonViewFilter::LLPersonViewFilter() :
+ mEmptyLookupMessage(""),
+ mFilterSubString(""),
+ mName(""),
+ mFilterModified(FILTER_NONE),
+ mCurrentGeneration(0)
+{
+}
+
+void LLPersonViewFilter::setFilterSubString(const std::string& string)
+{
+ std::string filter_sub_string_new = string;
+ LLStringUtil::trimHead(filter_sub_string_new);
+ LLStringUtil::toUpper(filter_sub_string_new);
+
+ if (mFilterSubString != filter_sub_string_new)
+ {
+ // *TODO : Add logic to support more and less restrictive filtering
+ setModified(FILTER_RESTART);
+ mFilterSubString = filter_sub_string_new;
+ }
+}
+
+bool LLPersonViewFilter::showAllResults() const
+{
+ return mFilterSubString.size() > 0;
+}
+
+bool LLPersonViewFilter::check(const LLFolderViewModelItem* item)
+{
+ return (mFilterSubString.size() ? (item->getSearchableName().find(mFilterSubString) != std::string::npos) : true);
+}
+
+std::string::size_type LLPersonViewFilter::getStringMatchOffset(LLFolderViewModelItem* item) const
+{
+ return mFilterSubString.size() ? item->getSearchableName().find(mFilterSubString) : std::string::npos;
+}
+
+std::string::size_type LLPersonViewFilter::getFilterStringSize() const
+{
+ return mFilterSubString.size();
+}
+
+bool LLPersonViewFilter::isActive() const
+{
+ return mFilterSubString.size();
+}
+
+bool LLPersonViewFilter::isModified() const
+{
+ return mFilterModified != FILTER_NONE;
+}
+
+void LLPersonViewFilter::clearModified()
+{
+ mFilterModified = FILTER_NONE;
+}
+
+void LLPersonViewFilter::setEmptyLookupMessage(const std::string& message)
+{
+ mEmptyLookupMessage = message;
+}
+
+std::string LLPersonViewFilter::getEmptyLookupMessage() const
+{
+ return mEmptyLookupMessage;
+}
+
diff --git a/indra/newview/llpersonmodelcommon.h b/indra/newview/llpersonmodelcommon.h
new file mode 100644
index 0000000000..74598eaee0
--- /dev/null
+++ b/indra/newview/llpersonmodelcommon.h
@@ -0,0 +1,248 @@
+/**
+* @file llavatarfolder.h
+* @brief Header file for llavatarfolder
+* @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_LLPERSONMODELCOMMON_H
+#define LL_LLPERSONMODELCOMMON_H
+
+#include "../llui/llfolderviewitem.h"
+#include "../llui/llfolderviewmodel.h"
+
+class LLPersonTabModel;
+class LLPersonModel;
+
+// Conversation items: we hold a list of those and create an LLFolderViewItem widget for each
+// that we tuck into the mConversationsListPanel.
+class LLPersonModelCommon : public LLFolderViewModelItemCommon
+{
+public:
+
+ LLPersonModelCommon(std::string name, LLFolderViewModelInterface& root_view_model);
+ LLPersonModelCommon(std::string display_name, std::string suffix, LLFolderViewModelInterface& root_view_model);
+ LLPersonModelCommon(LLFolderViewModelInterface& root_view_model);
+ virtual ~LLPersonModelCommon();
+
+ // Stub those things we won't really be using in this conversation context
+ virtual const std::string& getName() const { return mName; }
+ virtual const std::string& getDisplayName() const { return mName; }
+ virtual const std::string& getSearchableName() const { return mSearchableName; }
+
+ virtual LLPointer<LLUIImage> getIcon() const { return NULL; }
+ virtual LLPointer<LLUIImage> getOpenIcon() const { return getIcon(); }
+ virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; }
+ virtual std::string getLabelSuffix() const { return mLabelSuffix; }
+ virtual BOOL isItemRenameable() const { return TRUE; }
+ virtual BOOL renameItem(const std::string& new_name);
+ virtual BOOL isItemMovable( void ) const { return FALSE; }
+ virtual BOOL isItemRemovable( void ) const { return FALSE; }
+ virtual BOOL isItemInTrash( void) const { return FALSE; }
+ virtual BOOL removeItem() { return FALSE; }
+ virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) { }
+ virtual void move( LLFolderViewModelItem* parent_listener ) { }
+ virtual BOOL isItemCopyable() const { return FALSE; }
+ virtual BOOL copyToClipboard() const { return FALSE; }
+ virtual BOOL cutToClipboard() const { return FALSE; }
+ virtual BOOL isClipboardPasteable() const { return FALSE; }
+ virtual void pasteFromClipboard() { }
+ virtual void pasteLinkFromClipboard() { }
+ virtual void buildContextMenu(LLMenuGL& menu, U32 flags) { }
+ virtual BOOL isUpToDate() const { return TRUE; }
+ virtual bool hasChildren() const { return FALSE; }
+
+ virtual bool potentiallyVisible() { return true; }
+
+ virtual bool filter( LLFolderViewFilter& filter);
+
+ virtual bool descendantsPassedFilter(S32 filter_generation = -1) { return true; }
+ virtual void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0);
+ virtual bool passedFilter(S32 filter_generation = -1) { return mPassedFilter; }
+
+ // The action callbacks
+ virtual void performAction(LLInventoryModel* model, std::string action);
+ virtual void openItem( void );
+ virtual void closeItem( void );
+ virtual void previewItem( void );
+ virtual void selectItem(void) { }
+ virtual void showProperties(void);
+
+ // This method will be called to determine if a drop can be
+ // performed, and will set drop to TRUE if a drop is
+ // requested.
+ // Returns TRUE if a drop is possible/happened, FALSE otherwise.
+ virtual BOOL dragOrDrop(MASK mask, BOOL drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ std::string& tooltip_msg) { return FALSE; }
+
+ const LLUUID& getID() {return mID;}
+ void postEvent(const std::string& event_type, LLPersonTabModel* session, LLPersonModel* participant);
+
+protected:
+
+ std::string mName; // Name of the person
+ std::string mLabelSuffix;
+ std::string mSearchableName; // Name used in string matching for this person
+ bool mPrevPassedAllFilters;
+ LLUUID mID;
+};
+
+class LLPersonTabModel : public LLPersonModelCommon
+{
+public:
+ enum tab_type
+ {
+ FB_SL_NON_SL_FRIEND,
+ FB_ONLY_FRIEND,
+ };
+
+ LLPersonTabModel(tab_type tab_type, std::string display_name, LLFolderViewModelInterface& root_view_model);
+ LLPersonTabModel(LLFolderViewModelInterface& root_view_model);
+
+ LLPointer<LLUIImage> getIcon() const { return NULL; }
+ void addParticipant(LLPersonModel* participant);
+ void removeParticipant(LLPersonModel* participant);
+ void removeParticipant(const LLUUID& participant_id);
+ void clearParticipants();
+ LLPersonModel* findParticipant(const LLUUID& person_id);
+
+ tab_type mTabType;
+
+private:
+};
+
+class LLPersonModel : public LLPersonModelCommon
+{
+public:
+ LLPersonModel(const LLUUID& agent_id, const std::string display_name, const std::string suffix, LLFolderViewModelInterface& root_view_model);
+ LLPersonModel(LLFolderViewModelInterface& root_view_model);
+
+ LLUUID getAgentID();
+
+private:
+ LLUUID mAgentID;
+};
+
+// Filtering functional object
+
+class LLPersonViewFilter : public LLFolderViewFilter
+{
+public:
+
+ enum ESortOrderType
+ {
+ SO_NAME = 0, // Sort by name
+ SO_ONLINE_STATUS = 0x1 // Sort by online status (i.e. online or not)
+ };
+ // Default sort order is by name
+ static const U32 SO_DEFAULT = SO_NAME;
+
+ LLPersonViewFilter();
+ ~LLPersonViewFilter() {}
+
+ // +-------------------------------------------------------------------+
+ // + Execution And Results
+ // +-------------------------------------------------------------------+
+ bool check(const LLFolderViewModelItem* item);
+ bool checkFolder(const LLFolderViewModelItem* folder) const { return true; }
+
+ void setEmptyLookupMessage(const std::string& message);
+ std::string getEmptyLookupMessage() const;
+
+ bool showAllResults() const;
+
+ std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const;
+ std::string::size_type getFilterStringSize() const;
+
+ // +-------------------------------------------------------------------+
+ // + Status
+ // +-------------------------------------------------------------------+
+ bool isActive() const;
+ bool isModified() const;
+ void clearModified();
+ const std::string& getName() const { return mName; }
+ const std::string& getFilterText() { return mName; }
+ void setModified(EFilterModified behavior = FILTER_RESTART) { mFilterModified = behavior; mCurrentGeneration++; }
+
+ // +-------------------------------------------------------------------+
+ // + Time
+ // +-------------------------------------------------------------------+
+ // Note : we currently filter the whole person list at once, no need to timeout then.
+ void resetTime(S32 timeout) { }
+ bool isTimedOut() { return false; }
+
+ // +-------------------------------------------------------------------+
+ // + Default
+ // +-------------------------------------------------------------------+
+ // Note : we don't support runtime default setting for person filter
+ bool isDefault() const { return !isActive(); }
+ bool isNotDefault() const { return isActive(); }
+ void markDefault() { }
+ void resetDefault() { setModified(); }
+
+ // +-------------------------------------------------------------------+
+ // + Generation
+ // +-------------------------------------------------------------------+
+ // Note : For the moment, we do not support restrictive filtering so all generation indexes are pointing to the current generation
+ S32 getCurrentGeneration() const { return mCurrentGeneration; }
+ S32 getFirstSuccessGeneration() const { return mCurrentGeneration; }
+ S32 getFirstRequiredGeneration() const { return mCurrentGeneration; }
+
+ // Non Virtual Methods (i.e. specific to this class)
+ void setFilterSubString(const std::string& string);
+
+private:
+ std::string mName;
+ std::string mEmptyLookupMessage;
+ std::string mFilterSubString;
+ EFilterModified mFilterModified;
+ S32 mCurrentGeneration;
+};
+
+class LLPersonViewSort
+{
+public:
+ LLPersonViewSort(U32 order = LLPersonViewFilter::SO_DEFAULT) : mSortOrder(order) { }
+
+ bool operator()(const LLPersonModelCommon* const& a, const LLPersonModelCommon* const& b) const {return false;}
+ operator U32() const { return mSortOrder; }
+private:
+ // Note: we're treating this value as a sort order bitmask as done in other places in the code (e.g. inventory)
+ U32 mSortOrder;
+};
+
+
+class LLPersonFolderViewModel
+ : public LLFolderViewModel<LLPersonViewSort, LLPersonModelCommon, LLPersonModelCommon, LLPersonViewFilter>
+{
+public:
+ typedef LLFolderViewModel<LLPersonViewSort, LLPersonModelCommon, LLPersonModelCommon, LLPersonViewFilter> base_t;
+
+ void sort(LLFolderViewFolder* folder) { base_t::sort(folder);}
+ bool startDrag(std::vector<LLFolderViewModelItem*>& items) { return false; } // We do not allow drag of conversation items
+};
+
+
+#endif // LL_LLPERSONMODELCOMMON_H
+
diff --git a/indra/newview/llpersontabview.cpp b/indra/newview/llpersontabview.cpp
new file mode 100644
index 0000000000..34ffc6ffce
--- /dev/null
+++ b/indra/newview/llpersontabview.cpp
@@ -0,0 +1,465 @@
+/**
+* @file llpersontabview.cpp
+* @brief Implementation of llpersontabview
+* @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 "llpersontabview.h"
+
+#include "llavataractions.h"
+#include "llfloaterreg.h"
+#include "llpersonmodelcommon.h"
+
+static LLDefaultChildRegistry::Register<LLPersonTabView> r_person_tab_view("person_tab_view");
+
+const LLColor4U DEFAULT_WHITE(255, 255, 255);
+
+LLPersonTabView::Params::Params()
+{}
+
+LLPersonTabView::LLPersonTabView(const LLPersonTabView::Params& p) :
+LLFolderViewFolder(p),
+highlight(false),
+mImageHeader(LLUI::getUIImage("Accordion_Off")),
+mImageHeaderOver(LLUI::getUIImage("Accordion_Over")),
+mImageHeaderFocused(LLUI::getUIImage("Accordion_Selected"))
+{
+}
+
+S32 LLPersonTabView::getLabelXPos()
+{
+ return getIndentation() + mArrowSize + 15;//Should be a .xml variable but causes crash;
+}
+
+LLPersonTabView::~LLPersonTabView()
+{
+
+}
+
+BOOL LLPersonTabView::handleMouseDown( S32 x, S32 y, MASK mask )
+{
+ bool selected_item = LLFolderViewFolder::handleMouseDown(x, y, mask);
+
+ if(selected_item)
+ {
+ gFocusMgr.setKeyboardFocus( this );
+ highlight = true;
+ }
+
+ return selected_item;
+}
+
+void LLPersonTabView::draw()
+{
+ static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
+ static const LLFolderViewItem::Params& default_params = LLUICtrlFactory::getDefaultParams<LLPersonTabView>();
+
+ const LLFontGL * font = LLFontGL::getFontSansSerif();
+ F32 text_left = (F32)getLabelXPos();
+ F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad;
+ LLColor4 color = sFgColor;
+ F32 right_x = 0;
+
+ drawHighlight();
+ updateLabelRotation();
+ drawOpenFolderArrow(default_params, sFgColor);
+
+ drawLabel(font, text_left, y, color, right_x);
+
+ LLView::draw();
+}
+
+void LLPersonTabView::drawHighlight()
+{
+ S32 width = getRect().getWidth();
+ S32 height = mItemHeight;
+ S32 x = 1;
+ S32 y = getRect().getHeight() - mItemHeight;
+
+ if(highlight)
+ {
+ mImageHeaderFocused->draw(x,y,width,height);
+ }
+ else
+ {
+ mImageHeader->draw(x,y,width,height);
+ }
+
+ if(mIsMouseOverTitle)
+ {
+ mImageHeaderOver->draw(x,y,width,height);
+ }
+
+}
+
+//
+// LLPersonView
+//
+
+static LLDefaultChildRegistry::Register<LLPersonView> r_person_view("person_view");
+
+bool LLPersonView::sChildrenWidthsInitialized = false;
+ChildWidthVec LLPersonView::mChildWidthVec;
+
+LLPersonView::Params::Params() :
+facebook_icon("facebook_icon"),
+avatar_icon("avatar_icon"),
+last_interaction_time_textbox("last_interaction_time_textbox"),
+permission_edit_theirs_icon("permission_edit_theirs_icon"),
+permission_edit_mine_icon("permission_edit_mine_icon"),
+permission_map_icon("permission_map_icon"),
+permission_online_icon("permission_online_icon"),
+info_btn("info_btn"),
+profile_btn("profile_btn"),
+output_monitor("output_monitor")
+{}
+
+LLPersonView::LLPersonView(const LLPersonView::Params& p) :
+LLFolderViewItem(p),
+mImageOver(LLUI::getUIImage("ListItem_Over")),
+mImageSelected(LLUI::getUIImage("ListItem_Select")),
+mFacebookIcon(NULL),
+mAvatarIcon(NULL),
+mLastInteractionTimeTextbox(NULL),
+mPermissionEditTheirsIcon(NULL),
+mPermissionEditMineIcon(NULL),
+mPermissionMapIcon(NULL),
+mPermissionOnlineIcon(NULL),
+mInfoBtn(NULL),
+mProfileBtn(NULL),
+mOutputMonitorCtrl(NULL)
+{
+}
+
+S32 LLPersonView::getLabelXPos()
+{
+ S32 label_x_pos;
+
+ if(mAvatarIcon->getVisible())
+ {
+ label_x_pos = getIndentation() + mAvatarIcon->getRect().getWidth() + mIconPad;
+ }
+ else
+ {
+ label_x_pos = getIndentation() + mFacebookIcon->getRect().getWidth() + mIconPad;
+ }
+
+
+ return label_x_pos;
+}
+
+void LLPersonView::addToFolder(LLFolderViewFolder * person_folder_view)
+{
+ const LLFontGL * font = LLFontGL::getFontSansSerifSmall();
+
+ LLFolderViewItem::addToFolder(person_folder_view);
+ //Added item to folder could change folder's mHasVisibleChildren flag so call arrange
+ person_folder_view->requestArrange();
+
+ mPersonTabModel = static_cast<LLPersonTabModel *>(getParentFolder()->getViewModelItem());
+
+ if(mPersonTabModel->mTabType == LLPersonTabModel::FB_SL_NON_SL_FRIEND)
+ {
+ mAvatarIcon->setVisible(TRUE);
+ mFacebookIcon->setVisible(TRUE);
+
+ S32 label_width = font->getWidth(mLabel);
+ F32 text_left = (F32)getLabelXPos();
+
+ LLRect mFacebookIconRect = mFacebookIcon->getRect();
+ S32 new_left = text_left + label_width + 7;
+ mFacebookIconRect.set(new_left,
+ mFacebookIconRect.mTop,
+ new_left + mFacebookIconRect.getWidth(),
+ mFacebookIconRect.mBottom);
+ mFacebookIcon->setRect(mFacebookIconRect);
+ }
+ else if(mPersonTabModel->mTabType == LLPersonTabModel::FB_ONLY_FRIEND)
+ {
+ mFacebookIcon->setVisible(TRUE);
+ }
+
+}
+
+LLPersonView::~LLPersonView()
+{
+
+}
+
+BOOL LLPersonView::postBuild()
+{
+ if(!sChildrenWidthsInitialized)
+ {
+ initChildrenWidthVec(this);
+ sChildrenWidthsInitialized = true;
+ }
+
+ initChildVec();
+ updateChildren();
+
+ LLPersonModel * person_model = static_cast<LLPersonModel *>(getViewModelItem());
+
+ mAvatarIcon->setValue(person_model->getAgentID());
+ mInfoBtn->setClickedCallback(boost::bind(&LLFloaterReg::showInstance, "inspect_avatar", LLSD().with("avatar_id", person_model->getAgentID()), FALSE));
+ mProfileBtn->setClickedCallback(boost::bind(&LLAvatarActions::showProfile, person_model->getAgentID()));
+
+ return LLFolderViewItem::postBuild();
+}
+
+void LLPersonView::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ if(mPersonTabModel->mTabType == LLPersonTabModel::FB_SL_NON_SL_FRIEND)
+ {
+ mInfoBtn->setVisible(TRUE);
+ mProfileBtn->setVisible(TRUE);
+ }
+
+ updateChildren();
+ LLFolderViewItem::onMouseEnter(x, y, mask);
+}
+
+void LLPersonView::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ if(mPersonTabModel->mTabType == LLPersonTabModel::FB_SL_NON_SL_FRIEND)
+ {
+ mInfoBtn->setVisible(FALSE);
+ mProfileBtn->setVisible(FALSE);
+ }
+
+ updateChildren();
+ LLFolderViewItem::onMouseLeave(x, y, mask);
+}
+
+BOOL LLPersonView::handleMouseDown( S32 x, S32 y, MASK mask)
+{
+ if(!LLView::childrenHandleMouseDown(x, y, mask))
+ {
+ gFocusMgr.setMouseCapture( this );
+ }
+
+ if (!mIsSelected)
+ {
+ if(mask & MASK_CONTROL)
+ {
+ getRoot()->changeSelection(this, !mIsSelected);
+ }
+ else if (mask & MASK_SHIFT)
+ {
+ getParentFolder()->extendSelectionTo(this);
+ }
+ else
+ {
+ getRoot()->setSelection(this, FALSE);
+ }
+ make_ui_sound("UISndClick");
+ }
+ else
+ {
+ // If selected, we reserve the decision of deselecting/reselecting to the mouse up moment.
+ // This is necessary so we maintain selection consistent when starting a drag.
+ mSelectPending = TRUE;
+ }
+
+ mDragStartX = x;
+ mDragStartY = y;
+ return TRUE;
+}
+
+void LLPersonView::draw()
+{
+ static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
+ static LLUIColor sHighlightFgColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
+
+ const LLFontGL * font = LLFontGL::getFontSansSerifSmall();
+ F32 text_left = (F32)getLabelXPos();
+ F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad;
+ LLColor4 color = mIsSelected ? sHighlightFgColor : sFgColor;
+ F32 right_x = 0;
+
+ drawHighlight();
+ if(mLabel.length())
+ {
+ drawLabel(mLabel, font, text_left, y, color, right_x);
+ }
+ if(mLabelSuffix.length())
+ {
+ drawLabel(mLabelSuffix, font, mFacebookIcon->getRect().mRight + 7, y, color, right_x);
+ }
+
+ LLView::draw();
+}
+
+void LLPersonView::drawHighlight()
+{
+ static LLUIColor outline_color = LLUIColorTable::instance().getColor("EmphasisColor", DEFAULT_WHITE);
+
+ S32 width = getRect().getWidth();
+ S32 height = mItemHeight;
+ S32 x = 1;
+ S32 y = 0;
+
+ if(mIsSelected)
+ {
+ mImageSelected->draw(x, y, width, height);
+ //Draw outline
+ gl_rect_2d(x,
+ height,
+ width,
+ y,
+ outline_color, FALSE);
+ }
+
+ if(mIsMouseOverTitle)
+ {
+ mImageOver->draw(x, y, width, height);
+ }
+}
+
+void LLPersonView::drawLabel(const std::string text, const LLFontGL * font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x)
+{
+ font->renderUTF8(text, 0, x, y, color,
+ LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
+ S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, TRUE);
+}
+
+void LLPersonView::initFromParams(const LLPersonView::Params & params)
+{
+ LLIconCtrl::Params facebook_icon_params(params.facebook_icon());
+ applyXUILayout(facebook_icon_params, this);
+ mFacebookIcon = LLUICtrlFactory::create<LLIconCtrl>(facebook_icon_params);
+ addChild(mFacebookIcon);
+
+ LLAvatarIconCtrl::Params avatar_icon_params(params.avatar_icon());
+ applyXUILayout(avatar_icon_params, this);
+ mAvatarIcon = LLUICtrlFactory::create<LLAvatarIconCtrl>(avatar_icon_params);
+ addChild(mAvatarIcon);
+
+ LLTextBox::Params last_interaction_time_textbox(params.last_interaction_time_textbox());
+ applyXUILayout(last_interaction_time_textbox, this);
+ mLastInteractionTimeTextbox = LLUICtrlFactory::create<LLTextBox>(last_interaction_time_textbox);
+ addChild(mLastInteractionTimeTextbox);
+
+ LLIconCtrl::Params permission_edit_theirs_icon(params.permission_edit_theirs_icon());
+ applyXUILayout(permission_edit_theirs_icon, this);
+ mPermissionEditTheirsIcon = LLUICtrlFactory::create<LLIconCtrl>(permission_edit_theirs_icon);
+ addChild(mPermissionEditTheirsIcon);
+
+ LLIconCtrl::Params permission_edit_mine_icon(params.permission_edit_mine_icon());
+ applyXUILayout(permission_edit_mine_icon, this);
+ mPermissionEditMineIcon = LLUICtrlFactory::create<LLIconCtrl>(permission_edit_mine_icon);
+ addChild(mPermissionEditMineIcon);
+
+ LLIconCtrl::Params permission_map_icon(params.permission_map_icon());
+ applyXUILayout(permission_map_icon, this);
+ mPermissionMapIcon = LLUICtrlFactory::create<LLIconCtrl>(permission_map_icon);
+ addChild(mPermissionMapIcon);
+
+ LLIconCtrl::Params permission_online_icon(params.permission_online_icon());
+ applyXUILayout(permission_online_icon, this);
+ mPermissionOnlineIcon = LLUICtrlFactory::create<LLIconCtrl>(permission_online_icon);
+ addChild(mPermissionOnlineIcon);
+
+ LLButton::Params info_btn(params.info_btn());
+ applyXUILayout(info_btn, this);
+ mInfoBtn = LLUICtrlFactory::create<LLButton>(info_btn);
+ addChild(mInfoBtn);
+
+ LLButton::Params profile_btn(params.profile_btn());
+ applyXUILayout(profile_btn, this);
+ mProfileBtn = LLUICtrlFactory::create<LLButton>(profile_btn);
+ addChild(mProfileBtn);
+
+ LLOutputMonitorCtrl::Params output_monitor(params.output_monitor());
+ applyXUILayout(output_monitor, this);
+ mOutputMonitorCtrl = LLUICtrlFactory::create<LLOutputMonitorCtrl>(output_monitor);
+ addChild(mOutputMonitorCtrl);
+}
+
+void LLPersonView::initChildrenWidthVec(LLPersonView* self)
+{
+ S32 output_monitor_width = self->getRect().getWidth() - self->mOutputMonitorCtrl->getRect().mLeft;
+ S32 profile_btn_width = self->mOutputMonitorCtrl->getRect().mLeft - self->mProfileBtn->getRect().mLeft;
+ S32 info_btn_width = self->mProfileBtn->getRect().mLeft - self->mInfoBtn->getRect().mLeft;
+ S32 permission_online_icon_width = self->mInfoBtn->getRect().mLeft - self->mPermissionOnlineIcon->getRect().mLeft;
+ S32 permissions_map_icon_width = self->mPermissionOnlineIcon->getRect().mLeft - self->mPermissionMapIcon->getRect().mLeft;
+ S32 permission_edit_mine_icon_width = self->mPermissionMapIcon->getRect().mLeft - self->mPermissionEditMineIcon->getRect().mLeft;
+ S32 permission_edit_theirs_icon_width = self->mPermissionEditMineIcon->getRect().mLeft - self->mPermissionEditTheirsIcon->getRect().mLeft;
+ S32 last_interaction_time_textbox_width = self->mPermissionEditTheirsIcon->getRect().mLeft - self->mLastInteractionTimeTextbox->getRect().mLeft;
+
+ self->mChildWidthVec.push_back(output_monitor_width);
+ self->mChildWidthVec.push_back(profile_btn_width);
+ self->mChildWidthVec.push_back(info_btn_width);
+ self->mChildWidthVec.push_back(permission_online_icon_width);
+ self->mChildWidthVec.push_back(permissions_map_icon_width);
+ self->mChildWidthVec.push_back(permission_edit_mine_icon_width);
+ self->mChildWidthVec.push_back(permission_edit_theirs_icon_width);
+ self->mChildWidthVec.push_back(last_interaction_time_textbox_width);
+}
+
+void LLPersonView::initChildVec()
+{
+ mChildVec.push_back(mOutputMonitorCtrl);
+ mChildVec.push_back(mProfileBtn);
+ mChildVec.push_back(mInfoBtn);
+ mChildVec.push_back(mPermissionOnlineIcon);
+ mChildVec.push_back(mPermissionMapIcon);
+ mChildVec.push_back(mPermissionEditMineIcon);
+ mChildVec.push_back(mPermissionEditTheirsIcon);
+ mChildVec.push_back(mLastInteractionTimeTextbox);
+}
+
+void LLPersonView::updateChildren()
+{
+ mLabelPaddingRight = 0;
+ LLView * control;
+ S32 control_width;
+ LLRect control_rect;
+
+ llassert(mChildWidthVec.size() == mChildVec.size());
+
+ for(S32 i = 0; i < mChildWidthVec.size(); ++i)
+ {
+ control = mChildVec[i];
+
+ if(!control->getVisible())
+ {
+ continue;
+ }
+
+ control_width = mChildWidthVec[i];
+ mLabelPaddingRight += control_width;
+
+ control_rect = control->getRect();
+ control_rect.setLeftTopAndSize(
+ getLocalRect().getWidth() - mLabelPaddingRight,
+ control_rect.mTop,
+ control_rect.getWidth(),
+ control_rect.getHeight());
+
+ control->setShape(control_rect);
+
+ }
+}
diff --git a/indra/newview/llpersontabview.h b/indra/newview/llpersontabview.h
new file mode 100644
index 0000000000..6f244c2794
--- /dev/null
+++ b/indra/newview/llpersontabview.h
@@ -0,0 +1,151 @@
+/**
+* @file llpersontabview.h
+* @brief Header file for llpersontabview
+* @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_LLPERSONTABVIEW_H
+#define LL_LLPERSONTABVIEW_H
+
+#include "llavatariconctrl.h"
+#include "llbutton.h"
+#include "llfolderviewitem.h"
+#include "lloutputmonitorctrl.h"
+#include "lltextbox.h"
+
+class LLPersonTabModel;
+
+class LLPersonTabView : public LLFolderViewFolder
+{
+
+public:
+
+ struct Params : public LLInitParam::Block<Params, LLFolderViewFolder::Params>
+ {
+ Params();
+ };
+
+ LLPersonTabView(const LLPersonTabView::Params& p);
+ virtual ~LLPersonTabView();
+
+ S32 getLabelXPos();
+ bool highlight;
+
+ BOOL handleMouseDown( S32 x, S32 y, MASK mask );
+
+protected:
+ void draw();
+ void drawHighlight();
+
+private:
+
+ // Background images
+ LLPointer<LLUIImage> mImageHeader;
+ LLPointer<LLUIImage> mImageHeaderOver;
+ LLPointer<LLUIImage> mImageHeaderFocused;
+
+};
+
+typedef std::vector<S32> ChildWidthVec;
+typedef std::vector<LLView *> ChildVec;
+
+class LLPersonView : public LLFolderViewItem
+{
+
+public:
+
+ struct Params : public LLInitParam::Block<Params, LLFolderViewItem::Params>
+ {
+ Params();
+ Optional<LLIconCtrl::Params> facebook_icon;
+ Optional<LLAvatarIconCtrl::Params> avatar_icon;
+ Optional<LLTextBox::Params> last_interaction_time_textbox;
+ Optional<LLIconCtrl::Params> permission_edit_theirs_icon;
+ Optional<LLIconCtrl::Params> permission_edit_mine_icon;
+ Optional<LLIconCtrl::Params> permission_map_icon;
+ Optional<LLIconCtrl::Params> permission_online_icon;
+ Optional<LLButton::Params> info_btn;
+ Optional<LLButton::Params> profile_btn;
+ Optional<LLOutputMonitorCtrl::Params> output_monitor;
+ };
+
+ LLPersonView(const LLPersonView::Params& p);
+ virtual ~LLPersonView();
+
+ S32 getLabelXPos();
+ void addToFolder(LLFolderViewFolder * person_folder_view);
+ void initFromParams(const LLPersonView::Params & params);
+ BOOL postBuild();
+ void onMouseEnter(S32 x, S32 y, MASK mask);
+ void onMouseLeave(S32 x, S32 y, MASK mask);
+ BOOL handleMouseDown( S32 x, S32 y, MASK mask);
+
+protected:
+
+ void draw();
+ void drawHighlight();
+ void drawLabel(const std::string text, const LLFontGL * font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x);
+
+private:
+
+ //Short-cut to tab model
+ LLPersonTabModel * mPersonTabModel;
+
+ LLPointer<LLUIImage> mImageOver;
+ LLPointer<LLUIImage> mImageSelected;
+ LLIconCtrl * mFacebookIcon;
+ LLAvatarIconCtrl* mAvatarIcon;
+ LLTextBox * mLastInteractionTimeTextbox;
+ LLIconCtrl * mPermissionEditTheirsIcon;
+ LLIconCtrl * mPermissionEditMineIcon;
+ LLIconCtrl * mPermissionMapIcon;
+ LLIconCtrl * mPermissionOnlineIcon;
+ LLButton * mInfoBtn;
+ LLButton * mProfileBtn;
+ LLOutputMonitorCtrl * mOutputMonitorCtrl;
+
+ typedef enum e_avatar_item_child {
+ ALIC_SPEAKER_INDICATOR,
+ ALIC_PROFILE_BUTTON,
+ ALIC_INFO_BUTTON,
+ ALIC_PERMISSION_ONLINE,
+ ALIC_PERMISSION_MAP,
+ ALIC_PERMISSION_EDIT_MINE,
+ ALIC_PERMISSION_EDIT_THEIRS,
+ ALIC_INTERACTION_TIME,
+ ALIC_COUNT,
+ } EAvatarListItemChildIndex;
+
+ //Widths of controls are same for every instance so can be static
+ static ChildWidthVec mChildWidthVec;
+ //Control pointers are different for each instance so non-static
+ ChildVec mChildVec;
+
+ static bool sChildrenWidthsInitialized;
+ static void initChildrenWidthVec(LLPersonView* self);
+ void initChildVec();
+ void updateChildren();
+};
+
+#endif // LL_LLPERSONTABVIEW_H
+
diff --git a/indra/newview/llsociallist.cpp b/indra/newview/llsociallist.cpp
new file mode 100644
index 0000000000..9f827cf04f
--- /dev/null
+++ b/indra/newview/llsociallist.cpp
@@ -0,0 +1,154 @@
+/**
+* @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 100755
--- 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 100755
--- 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 beca08203f..bb9ad8c606 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -52,6 +52,7 @@
#include "lldaycyclemanager.h"
#include "lldebugview.h"
#include "llenvmanager.h"
+#include "llfacebookconnect.h"
#include "llfilepicker.h"
#include "llfirstuse.h"
#include "llfloaterbuy.h"
@@ -5970,6 +5971,21 @@ void handle_report_abuse()
LLFloaterReporter::showFromMenu(COMPLAINT_REPORT);
}
+void handle_facebook_connect()
+{
+ if (LLFacebookConnect::instance().getConnected())
+ {
+ LLFacebookConnect::instance().disconnectFromFacebook();
+ }
+ else
+ {
+ LLFacebookConnect::instance().getConnectionToFacebook();
+ }
+}
+
+//bool is_facebook_connected();
+
+
void handle_buy_currency()
{
LLBuyCurrencyHTML::openCurrencyFloater();
@@ -8719,4 +8735,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected");
view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono");
view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints");
+
+ // Facebook Connect
+ commit.add("Facebook.Connect", boost::bind(&handle_facebook_connect));
}
diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h
index 143420e227..b916d95b7a 100755
--- a/indra/newview/llviewermenu.h
+++ b/indra/newview/llviewermenu.h
@@ -135,6 +135,10 @@ bool enable_pay_object();
bool enable_buy_object();
bool handle_go_to();
+// Facebook Connect
+void handle_facebook_connect();
+//bool is_facebook_connected();
+
// Export to XML or Collada
void handle_export_selected( void * );
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index ace16396db..a8b5177c31 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2649,7 +2649,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
{
send_do_not_disturb_message(msg, from_id);
}
- else
+
+ if (!is_muted)
{
LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL;
// Read the binary bucket for more information.
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index b8b53aa6e4..fba835f642 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1585,6 +1585,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("EnvironmentSettings");
capabilityNames.append("EstateChangeInfo");
capabilityNames.append("EventQueueGet");
+ capabilityNames.append("FacebookConnect");
+ //capabilityNames.append("FacebookRedirect");
if (gSavedSettings.getBOOL("UseHTTPInventory"))
{
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index fe4d5b3e4d..04e5447abf 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1811,7 +1811,6 @@ void LLViewerWindow::initBase()
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/colors.xml b/indra/newview/skins/default/colors.xml
index 42568775d9..fc6458c67e 100755
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -875,4 +875,19 @@
<color
name="blue"
value="0 0 1 1"/>
+
+ <!--Resize bar colors -->
+
+ <color
+ name="ResizebarBorderLight"
+ value="0.231 0.231 0.231 1"/>
+
+ <color
+ name="ResizebarBorderDark"
+ value="0.133 0.133 0.133 1"/>
+
+ <color
+ name="ResizebarBody"
+ value="0.208 0.208 0.208 1"/>
+
</colors>
diff --git a/indra/newview/skins/default/textures/icons/Facebook.png b/indra/newview/skins/default/textures/icons/Facebook.png
new file mode 100644
index 0000000000..8287d56f88
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Facebook.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index fcab966dee..18146943a5 100755
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -199,6 +199,8 @@ with the same filename but different name
<texture name="ExternalBrowser_Off" file_name="icons/ExternalBrowser_Off.png" preload="false" />
<texture name="Edit_Wrench" file_name="icons/Edit_Wrench.png" preload="false" />
+ <texture name="Facebook_Icon" file_name="icons/Facebook.png" preload="false" />
+
<texture name="Favorite_Star_Active" file_name="navbar/Favorite_Star_Active.png" preload="false" />
<texture name="Favorite_Star_Off" file_name="navbar/Favorite_Star_Off.png" preload="false" />
<texture name="Favorite_Star_Press" file_name="navbar/Favorite_Star_Press.png" preload="false" />
@@ -773,4 +775,7 @@ with the same filename but different name
<texture name="Popup_Caution" file_name="icons/pop_up_caution.png"/>
<texture name="Camera_Drag_Dot" file_name="world/CameraDragDot.png"/>
<texture name="NavBar Separator" file_name="navbar/separator.png"/>
+
+ <texture name="Horizontal Drag Handle" file_name="widgets/horizontal_drag_handle.png"/>
+ <texture name="Vertical Drag Handle" file_name="widgets/vertical_drag_handle.png"/>
</textures>
diff --git a/indra/newview/skins/default/textures/widgets/horizontal_drag_handle.png b/indra/newview/skins/default/textures/widgets/horizontal_drag_handle.png
new file mode 100644
index 0000000000..642eac4065
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/horizontal_drag_handle.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/vertical_drag_handle.png b/indra/newview/skins/default/textures/widgets/vertical_drag_handle.png
new file mode 100644
index 0000000000..b06b70cf36
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/vertical_drag_handle.png
Binary files differ
diff --git a/indra/newview/skins/default/xui/en/floater_im_container.xml b/indra/newview/skins/default/xui/en/floater_im_container.xml
index 65f623a47e..da016462db 100755
--- a/indra/newview/skins/default/xui/en/floater_im_container.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_container.xml
@@ -24,24 +24,28 @@
value="Conv_toolbar_expand"/>
<layout_stack
animate="true"
- bottom="-1"
+ bottom="-5"
+ drag_handle_gap="6"
+ drag_handle_first_indent="27"
+ drag_handle_second_indent="10"
follows="all"
layout="topleft"
left="0"
name="conversations_stack"
orientation="horizontal"
right="-1"
+ show_drag_handle="true"
top="0">
<layout_panel
auto_resize="false"
user_resize="true"
name="conversations_layout_panel"
min_dim="38"
- expanded_min_dim="156">
+ expanded_min_dim="136">
<layout_stack
animate="false"
follows="left|top|right"
- height="35"
+ height="27"
layout="topleft"
left="0"
name="conversations_pane_buttons_stack"
@@ -50,7 +54,6 @@
top="0">
<layout_panel
auto_resize="true"
- height="35"
name="conversations_pane_buttons_expanded">
<menu_button
follows="top|left"
@@ -64,7 +67,7 @@
left="5"
name="sort_btn"
tool_tip="View/sort options"
- top="5"
+ top="1"
width="31" />
<button
follows="top|left"
@@ -74,7 +77,7 @@
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
- top="5"
+ top="1"
left_pad="2"
name="add_btn"
tool_tip="Start a new conversation"
@@ -87,7 +90,7 @@
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
- top="5"
+ top="1"
left_pad="2"
name="speak_btn"
tool_tip="Speak with people using your microphone"
@@ -95,9 +98,8 @@
</layout_panel>
<layout_panel
auto_resize="false"
- height="35"
name="conversations_pane_buttons_collapsed"
- width="41">
+ width="31">
<button
follows="right|top"
height="25"
@@ -106,8 +108,8 @@
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
- top="5"
- left="1"
+ top="1"
+ left="0"
name="expand_collapse_btn"
tool_tip="Collapse/Expand this list"
width="31" />
@@ -119,7 +121,7 @@
layout="topleft"
name="conversations_list_panel"
opaque="true"
- top="35"
+ top_pad="0"
left="5"
right="-1"/>
</layout_panel>
@@ -127,7 +129,7 @@
auto_resize="true"
user_resize="true"
name="messages_layout_panel"
- expanded_min_dim="222">
+ expanded_min_dim="212">
<panel_container
bottom="-1"
follows="all"
@@ -136,44 +138,44 @@
name="im_box_tab_container"
right="-1"
top="0">
- <panel
- bottom="-1"
- follows="all"
- layout="topleft"
- name="stub_panel"
- opaque="true"
- top_pad="0"
- left="0"
- right="-1">
- <button
- follows="right|top"
- height="25"
- image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="Conv_toolbar_collapse"
- image_selected="Toolbar_Middle_Selected"
- image_unselected="Toolbar_Middle_Off"
+ <panel
+ bottom="-1"
+ follows="all"
layout="topleft"
- top="5"
- right="-10"
- name="stub_collapse_btn"
- tool_tip="Collapse this pane"
- width="31" />
- <text
- type="string"
- clip_partial="false"
- follows="left|top|right"
- layout="topleft"
- left="15"
- right="-15"
- name="stub_textbox"
- top="25"
- height="40"
- valign="center"
- parse_urls="true"
- wrap="true">
- This conversation is in a separate window. [secondlife:/// Bring it back.]
- </text>
- </panel>
+ name="stub_panel"
+ opaque="true"
+ top_pad="0"
+ left="0"
+ right="-1">
+ <button
+ follows="right|top"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Conv_toolbar_collapse"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ top="1"
+ right="-10"
+ name="stub_collapse_btn"
+ tool_tip="Collapse this pane"
+ width="31" />
+ <text
+ type="string"
+ clip_partial="false"
+ follows="left|top|right"
+ layout="topleft"
+ left="15"
+ right="-15"
+ name="stub_textbox"
+ top="25"
+ height="40"
+ valign="center"
+ parse_urls="true"
+ wrap="true">
+ This conversation is in a separate window. [secondlife:/// Bring it back.]
+ </text>
+ </panel>
</panel_container>
</layout_panel>
</layout_stack>
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 2152a9f6e9..8da4213c65 100755
--- a/indra/newview/skins/default/xui/en/floater_im_session.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_session.xml
@@ -70,26 +70,23 @@
top="0"
left="0"
right="-1"
- bottom="-3">
+ bottom="-1">
<layout_stack
animate="false"
+ bottom="-1"
default_tab_group="2"
follows="all"
- right="-5"
- bottom="-1"
- top="0"
- left="5"
- border_size="0"
+ left="3"
layout="topleft"
- orientation="vertical"
name="main_stack"
- tab_group="1">
+ right="-3"
+ orientation="vertical"
+ tab_group="1"
+ top="0">
<layout_panel
auto_resize="false"
name="toolbar_panel"
- height="35"
- right="-1"
- left="1">
+ height="25">
<menu_button
menu_filename="menu_im_session_showmodes.xml"
follows="top|left"
@@ -102,7 +99,7 @@
left="5"
name="view_options_btn"
tool_tip="View/sort options"
- top="5"
+ top="1"
width="31" />
<menu_button
menu_filename="menu_im_conversation.xml"
@@ -113,7 +110,7 @@
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
- top="5"
+ top="1"
left_pad="2"
name="gear_btn"
visible="false"
@@ -128,7 +125,7 @@
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
- top="5"
+ top="1"
left_pad="2"
name="add_btn"
tool_tip="Add someone to this conversation"
@@ -141,7 +138,7 @@
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
- top="5"
+ top="1"
left_pad="2"
name="voice_call_btn"
tool_tip="Open voice connection"
@@ -166,8 +163,8 @@
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
- top="5"
- right="-67"
+ top="1"
+ right="-70"
name="close_btn"
tool_tip="End this conversation"
width="31" />
@@ -179,7 +176,7 @@
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
- top="5"
+ top="1"
left_pad="2"
name="expand_collapse_btn"
tool_tip="Collapse/Expand this pane"
@@ -194,18 +191,21 @@
layout="topleft"
left_pad="2"
name="tear_off_btn"
- top="5"
+ top="1"
width="31" />
</layout_panel>
<layout_panel
name="body_panel"
- top="1"
- bottom="-1">
+ height="235">
<layout_stack
default_tab_group="2"
+ drag_handle_gap="6"
+ drag_handle_first_indent="0"
+ drag_handle_second_indent="1"
follows="all"
orientation="horizontal"
name="im_panels"
+ show_drag_handle="true"
tab_group="1"
top="0"
right="-1"
@@ -217,14 +217,12 @@
min_dim="0"
width="150"
user_resize="true"
- auto_resize="false"
- bottom="-1" />
+ auto_resize="false" />
<layout_panel
default_tab_group="3"
tab_group="2"
name="right_part_holder"
- min_width="221"
- bottom="-1">
+ min_width="172">
<layout_stack
animate="true"
default_tab_group="2"
@@ -233,7 +231,7 @@
name="translate_and_chat_stack"
tab_group="1"
top="0"
- left="0"
+ left="1"
right="-1"
bottom="-1">
<layout_panel
@@ -259,7 +257,7 @@
parse_highlights="true"
parse_urls="true"
right="-1"
- left="5"
+ left="0"
top="0"
bottom="-1" />
</layout_panel>
@@ -268,10 +266,7 @@
</layout_stack>
</layout_panel>
<layout_panel
- top_delta="0"
- top="0"
- height="26"
- bottom="-1"
+ height="35"
auto_resize="false"
name="chat_layout_panel">
<layout_stack
@@ -281,15 +276,11 @@
orientation="horizontal"
name="input_panels"
top="0"
- bottom="-2"
+ bottom="-1"
left="0"
right="-1">
<layout_panel
- name="input_editor_layout_panel"
- auto_resize="true"
- user_resize="false"
- top="0"
- bottom="-1">
+ name="input_editor_layout_panel">
<chat_editor
layout="topleft"
expand_lines_count="5"
@@ -302,32 +293,27 @@
max_length="1023"
spellcheck="true"
tab_group="3"
- top="1"
- bottom="-2"
- left="4"
- right="-4"
+ bottom="-8"
+ left="5"
+ right="-5"
wrap="true" />
</layout_panel>
<layout_panel
auto_resize="false"
- user_resize="false"
name="input_button_layout_panel"
- width="30"
- top="0"
- bottom="-1">
+ width="32">
<button
- layout="topleft"
left="1"
- right="-1"
- top="1"
- height="22"
+ top="4"
+ height="25"
follows="left|right|top"
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" />
+ tool_tip="Shows/hides message panel"
+ width="28" />
</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..2c341b6ecc
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_gear_fbc.xml
@@ -0,0 +1,51 @@
+<?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>
+ <menu_item_check
+ label="Facebook Add 300 test users to AvatarList"
+ layout="topleft"
+ name="Facebook App Add">
+ <menu_item_check.on_click
+ function="People.testaddFBC"/>
+ </menu_item_check>
+ <menu_item_check
+ label="Facebook Add 300 test users to FolderView"
+ layout="topleft"
+ name="Facebook App Add">
+ <menu_item_check.on_click
+ function="People.testaddFBCFolderView"/>
+ </menu_item_check>
+ <menu_item_check
+ label="Facebook post checkin message"
+ layout="topleft"
+ name="Facebook Checkin">
+ <menu_item_check.on_click
+ function="People.testFBCCheckin"/>
+ </menu_item_check>
+</toggleable_menu> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index a11cd13fdb..b34816fb14 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -16,6 +16,13 @@
parameter="agent" />
</menu_item_call>
<menu_item_call
+ label="Connect to Facebook..."
+ name="ConnectToFacebook">
+ <menu_item_call.on_click
+ function="Facebook.Connect" />
+ </menu_item_call>
+ <menu_item_separator/>
+ <menu_item_call
label="Appearance..."
name="ChangeOutfit">
<menu_item_call.on_click
@@ -3018,6 +3025,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
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 970a11c6c4..9d1973f267 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -3709,6 +3709,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">
@@ -6573,7 +6584,7 @@ Your object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; has given you th
icon="notify.tga"
name="JoinGroup"
persist="true"
- type="notify">
+ type="offer">
<tag>group</tag>
[MESSAGE]
<form name="form">
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 7ce2627be9..9bab2ccb0b 100755
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -633,5 +633,200 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
top="0"
right="-1" />
</panel>
+
+<!-- ================================= FBC TEST tab (Temporary) ========================== -->
+
+ <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>
+
+<!-- ================================= FBC TEST TWO tab (Final, to be renamed) ========================== -->
+
+ <panel
+ background_opaque="true"
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ bg_opaque_color="DkGray"
+ follows="all"
+ height="383"
+ label="FBC TEST TWO"
+ layout="topleft"
+ left="0"
+ help_topic="people_fbctest_tab"
+ name="fbctesttwo_panel"
+ top="0">
+ <panel
+ follows="left|top|right"
+ height="27"
+ label="bottom_panel"
+ layout="topleft"
+ left="0"
+ name="fbc_buttons_panel"
+ right="-1"
+ top="0">
+ <filter_editor
+ follows="left|top|right"
+ height="23"
+ layout="topleft"
+ left="6"
+ label="Filter People"
+ max_length_chars="300"
+ name="fbc_filter_input"
+ text_color="Black"
+ text_pad_left="10"
+ top="4"
+ width="177" />
+ <button
+ commit_callback.function="People.Gear"
+ follows="right"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="8"
+ name="gear_btn"
+ tool_tip="Actions on selected person"
+ top="3"
+ width="31" />
+ <menu_button
+ follows="right"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Conv_toolbar_sort"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="2"
+ menu_filename="menu_people_friends_view.xml"
+ menu_position="bottomleft"
+ name="fbc_view_btn"
+ tool_tip="View/sort options"
+ top_delta="0"
+ width="31" />
+ <button
+ follows="right"
+ 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="2"
+ name="fbc_add_btn"
+ tool_tip="Offer friendship to a resident"
+ top_delta="0"
+ width="31">
+ <commit_callback
+ function="People.AddFriendWizard" />
+ </button>
+ <dnd_button
+ follows="right"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="TrashItem_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ left_pad="2"
+ layout="topleft"
+ name="fbc_del_btn"
+ tool_tip="Remove selected person as a friend"
+ top_delta="0"
+ width="31">
+ <commit_callback
+ function="People.DelFriend" />
+ </dnd_button>
+ </panel>
+ </panel>
</tab_container>
</panel>
diff --git a/indra/newview/skins/default/xui/en/widgets/person_tab_view.xml b/indra/newview/skins/default/xui/en/widgets/person_tab_view.xml
new file mode 100644
index 0000000000..af5aec2c34
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/person_tab_view.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<person_tab_view
+ folder_arrow_image="Folder_Arrow"
+ folder_indentation="5"
+ item_height="24"
+ item_top_pad="3"
+ mouse_opaque="true"
+ follows="left|top|right"
+ text_pad="6"
+ text_pad_left="4"
+ text_pad_right="4"
+ arrow_size="10"
+ max_folder_item_overlap="2"/>
diff --git a/indra/newview/skins/default/xui/en/widgets/person_view.xml b/indra/newview/skins/default/xui/en/widgets/person_view.xml
new file mode 100644
index 0000000000..46c1b7ff75
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/person_view.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<person_view
+ folder_arrow_image="Folder_Arrow"
+ folder_indentation="5"
+ item_height="24"
+ item_top_pad="3"
+ mouse_opaque="true"
+ follows="left|top|right"
+ icon_pad="4"
+ icon_width="20"
+ text_pad="6"
+ text_pad_left="4"
+ text_pad_right="4"
+ arrow_size="10"
+ max_folder_item_overlap="2">
+ <facebook_icon
+ follows="left"
+ height="14"
+ image_name="Facebook_Icon"
+ left="5"
+ bottom="6"
+ name="facebook_icon"
+ tool_tip="Facebook User"
+ visible="false"
+ width="14" />
+ <avatar_icon
+ follows="left"
+ layout="topleft"
+ height="20"
+ default_icon_name="Generic_Person"
+ left="5"
+ top="2"
+ visible="false"
+ width="20" />
+ <last_interaction_time_textbox
+ layout="topleft"
+ follows="right"
+ font="SansSerifSmall"
+ height="15"
+ left_pad="5"
+ right="-164"
+ name="last_interaction_time_textbox"
+ text_color="LtGray_50"
+ value="0s"
+ visible="false"
+ width="35" />
+ <permission_edit_theirs_icon
+ layout="topleft"
+ height="16"
+ follows="right"
+ image_name="Permission_Edit_Objects_Theirs"
+ left_pad="3"
+ right="-129"
+ name="permission_edit_theirs_icon"
+ tool_tip="You can edit this friend&apos;s objects"
+ top="4"
+ visible="false"
+ width="16" />
+ <permission_edit_mine_icon
+ layout="topleft"
+ height="16"
+ follows="right"
+ image_name="Permission_Edit_Objects_Mine"
+ left_pad="3"
+ right="-110"
+ name="permission_edit_mine_icon"
+ tool_tip="This friend can edit, delete or take your objects"
+ top="4"
+ visible="false"
+ width="16" />
+ <permission_map_icon
+ height="16"
+ follows="right"
+ image_name="Permission_Visible_Map"
+ left_pad="3"
+ tool_tip="This friend can locate you on the map"
+ right="-91"
+ name="permission_map_icon"
+ visible="false"
+ width="16" />
+ <permission_online_icon
+ height="16"
+ follows="right"
+ image_name="Permission_Visible_Online"
+ left_pad="3"
+ right="-72"
+ name="permission_online_icon"
+ tool_tip="This friend can see when you&apos;re online"
+ visible="false"
+ width="16" />
+ <info_btn
+ follows="right"
+ height="16"
+ image_pressed="Info_Press"
+ image_unselected="Info_Over"
+ left_pad="3"
+ right="-53"
+ name="info_btn"
+ tool_tip="More info"
+ tab_stop="false"
+ visible="false"
+ width="16" />
+ <profile_btn
+ layout="topleft"
+ follows="right"
+ height="20"
+ image_overlay="Web_Profile_Off"
+ left_pad="5"
+ right="-28"
+ name="profile_btn"
+ tab_stop="false"
+ tool_tip="View profile"
+ top="2"
+ visible="false"
+ width="20" />
+ <output_monitor
+ auto_update="true"
+ follows="right"
+ draw_border="false"
+ height="16"
+ right="-3"
+ mouse_opaque="true"
+ name="speaking_indicator"
+ visible="false"
+ width="20" />
+ </person_view>
+
diff --git a/indra/newview/tests/lltranslate_test.cpp b/indra/newview/tests/lltranslate_test.cpp
index fd9527d631..8ce56326d8 100755
--- a/indra/newview/tests/lltranslate_test.cpp
+++ b/indra/newview/tests/lltranslate_test.cpp
@@ -308,8 +308,8 @@ void LLCurl::Responder::errorWithContent(U32, std::string const&, LLSD const&) {
void LLCurl::Responder::result(LLSD const&) {}
LLCurl::Responder::~Responder() {}
-void LLHTTPClient::get(const std::string&, const LLSD&, ResponderPtr, const LLSD&, const F32) {}
-void LLHTTPClient::get(const std::string&, LLPointer<LLCurl::Responder>, const LLSD&, const F32) {}
+void LLHTTPClient::get(const std::string&, const LLSD&, ResponderPtr, const LLSD&, const F32, bool) {}
+void LLHTTPClient::get(const std::string&, LLPointer<LLCurl::Responder>, const LLSD&, const F32, bool) {}
LLBufferStream::LLBufferStream(const LLChannelDescriptors& channels, LLBufferArray* buffer)
: std::iostream(&mStreamBuf), mStreamBuf(channels, buffer) {}