diff options
Diffstat (limited to 'indra/newview')
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.pngBinary files differ new file mode 100644 index 0000000000..8287d56f88 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Facebook.png 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.pngBinary files differ new file mode 100644 index 0000000000..642eac4065 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/horizontal_drag_handle.png diff --git a/indra/newview/skins/default/textures/widgets/vertical_drag_handle.png b/indra/newview/skins/default/textures/widgets/vertical_drag_handle.pngBinary files differ new file mode 100644 index 0000000000..b06b70cf36 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/vertical_drag_handle.png 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 <nolink>[OBJECTFROMNAME]</nolink> 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'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'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) {} | 
