diff options
Diffstat (limited to 'indra/newview')
55 files changed, 4037 insertions, 1174 deletions
| diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 3a09bc530c..3e5a826826 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -190,6 +190,7 @@ set(viewer_SOURCE_FILES      llexpandabletextbox.cpp      llexternaleditor.cpp      llface.cpp +    llfacebookconnect.cpp      llfasttimerview.cpp      llfavoritesbar.cpp      llfeaturemanager.cpp @@ -272,6 +273,7 @@ set(viewer_SOURCE_FILES      llfloatersettingsdebug.cpp      llfloatersidepanelcontainer.cpp      llfloatersnapshot.cpp +    llfloatersocial.cpp      llfloatersounddevices.cpp      llfloaterspellchecksettings.cpp      llfloatertelehub.cpp @@ -507,6 +509,7 @@ set(viewer_SOURCE_FILES      llsidetraypanelcontainer.cpp      llsky.cpp      llslurl.cpp +    llsnapshotlivepreview.cpp      llspatialpartition.cpp      llspeakers.cpp      llspeakingindicatormanager.cpp @@ -774,6 +777,7 @@ set(viewer_HEADER_FILES      llexpandabletextbox.h      llexternaleditor.h      llface.h +    llfacebookconnect.h      llfasttimerview.h      llfavoritesbar.h      llfeaturemanager.h @@ -856,6 +860,7 @@ set(viewer_HEADER_FILES      llfloatersettingsdebug.h      llfloatersidepanelcontainer.h      llfloatersnapshot.h +    llfloatersocial.h      llfloatersounddevices.h      llfloaterspellchecksettings.h      llfloatertelehub.h @@ -1080,6 +1085,7 @@ set(viewer_HEADER_FILES      llsidetraypanelcontainer.h      llsky.h      llslurl.h +    llsnapshotlivepreview.h      llspatialpartition.h      llspeakers.h      llspeakingindicatormanager.h diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index 4659673333..60c942094a 100755 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -216,6 +216,16 @@             is_running_function="Floater.IsOpen"             is_running_parameters="snapshot"             /> +  <command name="social" +           available_in_toybox="true" +           icon="Command_Social_Icon" +           label_ref="Command_Social_Label" +           tooltip_ref="Command_Social_Tooltip" +           execute_function="Floater.ToggleOrBringToFront" +           execute_parameters="social" +           is_running_function="Floater.IsOpen" +           is_running_parameters="social" +           />    <command name="speak"             available_in_toybox="true"             icon="Command_Speak_Icon" diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 388589a398..d20386c0d6 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -13029,6 +13029,17 @@        <key>Value</key>        <integer>0</integer>      </map> +    <key>SocialPhotoResolution</key> +    <map> +      <key>Comment</key> +      <string>Default resolution when sharing photo using the social floater</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string>[i800,i600]</string> +    </map>        <key>sourceid</key>      <map>        <key>Comment</key> diff --git a/indra/newview/app_settings/toolbars.xml b/indra/newview/app_settings/toolbars.xml index 29c019719d..86f9912815 100755 --- a/indra/newview/app_settings/toolbars.xml +++ b/indra/newview/app_settings/toolbars.xml @@ -6,6 +6,7 @@      <command name="speak"/>      <command name="destinations"/>      <command name="people"/> +    <command name="social"/>      <command name="profile"/>      <command name="move"/>      <command name="view"/> diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp index b9ec304b7e..3410a37890 100755 --- a/indra/newview/llagentui.cpp +++ b/indra/newview/llagentui.cpp @@ -112,6 +112,11 @@ BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const  		case LOCATION_FORMAT_NORMAL:  			buffer = llformat("%s", region_name.c_str());  			break; +		case LOCATION_FORMAT_NORMAL_COORDS: +			buffer = llformat("%s (%d, %d, %d)", +				region_name.c_str(), +				pos_x, pos_y, pos_z); +			break;  		case LOCATION_FORMAT_NO_COORDS:  			buffer = llformat("%s%s%s",  				region_name.c_str(), @@ -143,6 +148,11 @@ BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const  		case LOCATION_FORMAT_NORMAL:  			buffer = llformat("%s, %s", parcel_name.c_str(), region_name.c_str());  			break; +		case LOCATION_FORMAT_NORMAL_COORDS: +			buffer = llformat("%s (%d, %d, %d)", +				parcel_name.c_str(), +				pos_x, pos_y, pos_z); +			break;  		case LOCATION_FORMAT_NO_MATURITY:  			buffer = llformat("%s, %s (%d, %d, %d)",  				parcel_name.c_str(), diff --git a/indra/newview/llagentui.h b/indra/newview/llagentui.h index dda5dc1fd1..bb48dad14c 100755 --- a/indra/newview/llagentui.h +++ b/indra/newview/llagentui.h @@ -35,6 +35,7 @@ public:  	enum ELocationFormat  	{  		LOCATION_FORMAT_NORMAL,			// Parcel +		LOCATION_FORMAT_NORMAL_COORDS,	// Parcel (x, y, z)  		LOCATION_FORMAT_LANDMARK,		// Parcel, Region  		LOCATION_FORMAT_NO_MATURITY,	// Parcel, Region (x, y, z)  		LOCATION_FORMAT_NO_COORDS,		// Parcel, Region - Maturity diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 02eb67bf80..92bd281da8 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2574,7 +2574,7 @@ bool LLAppViewer::initConfiguration()  	std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel"));  	if(! CmdLineChannel.empty()) -	{ +    {  		LLVersionInfo::resetChannel(CmdLineChannel);  	} @@ -2586,16 +2586,16 @@ bool LLAppViewer::initConfiguration()  		LLFastTimer::sLog = TRUE;  		LLFastTimer::sLogName = std::string("performance");		  	} - +	  	std::string test_name(gSavedSettings.getString("LogMetrics"));  	if (! test_name.empty()) -	{ -		LLFastTimer::sMetricLog = TRUE ; + 	{ + 		LLFastTimer::sMetricLog = TRUE ;  		// '--logmetrics' is specified with a named test metric argument so the data gathering is done only on that test  		// In the absence of argument, every metric would be gathered (makes for a rather slow run and hard to decipher report...)  		llinfos << "'--logmetrics' argument : " << test_name << llendl; -		LLFastTimer::sLogName = test_name; - 	} +			LLFastTimer::sLogName = test_name; +		}  	if (clp.hasOption("graphicslevel"))  	{ @@ -2604,14 +2604,14 @@ bool LLAppViewer::initConfiguration()  		// that value for validity.  		U32 graphicslevel = gSavedSettings.getU32("RenderQualityPerformance");  		if (LLFeatureManager::instance().isValidGraphicsLevel(graphicslevel)) -		{ +        {  			// graphicslevel is valid: save it and engage it later. Capture  			// the requested value separately from the settings variable  			// because, if this is the first run, LLViewerWindow's constructor  			// will call LLFeatureManager::applyRecommendedSettings(), which  			// overwrites this settings variable!  			mForceGraphicsLevel = graphicslevel; -		} +        }  	}  	LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance"); @@ -2642,16 +2642,32 @@ 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 start_slurl;  	std::string CmdLineLoginLocation(gSavedSettings.getString("CmdLineLoginLocation"));  	if(! CmdLineLoginLocation.empty()) -	{ -		LLSLURL start_slurl(CmdLineLoginLocation); +    { +		start_slurl = CmdLineLoginLocation;  		LLStartUp::setStartSLURL(start_slurl);  		if(start_slurl.getType() == LLSLURL::LOCATION)   		{    			LLGridManager::getInstance()->setGridChoice(start_slurl.getGrid()); +    } +    } + +	//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 (start_slurl.isValid() && +		(gSavedSettings.getBOOL("SLURLPassToOtherInstance"))) +	{ +		if (sendURLToOtherInstance(start_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()) @@ -2792,7 +2808,7 @@ bool LLAppViewer::initConfiguration()  		LL_DEBUGS("AppInit")<<"set start from NextLoginLocation: "<<nextLoginLocation<<LL_ENDL;  		LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation));  	} -	else if ((clp.hasOption("login") || clp.hasOption("autologin")) +	else if (   (   clp.hasOption("login") || clp.hasOption("autologin"))  			 && gSavedSettings.getString("CmdLineLoginLocation").empty())  	{  		// If automatic login from command line with --login switch @@ -3176,7 +3192,7 @@ bool LLAppViewer::initWindow()  		LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false);  		gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel);  	} - +			  	// Set this flag in case we crash while initializing GL  	gSavedSettings.setBOOL("RenderInitError", TRUE);  	gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp new file mode 100644 index 0000000000..611d18d6d6 --- /dev/null +++ b/indra/newview/llfacebookconnect.cpp @@ -0,0 +1,577 @@ +/**  + * @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 "llnotificationsutil.h" +#include "llurlaction.h" +#include "llimagepng.h" +#include "llimagejpeg.h" +#include "lltrans.h" +#include "llevents.h" +#include "llviewerregion.h" + +#include "llfloaterwebcontent.h" +#include "llfloaterreg.h" + +boost::scoped_ptr<LLEventPump> LLFacebookConnect::sStateWatcher(new LLEventStream("FacebookConnectState")); +boost::scoped_ptr<LLEventPump> LLFacebookConnect::sInfoWatcher(new LLEventStream("FacebookConnectInfo")); +boost::scoped_ptr<LLEventPump> LLFacebookConnect::sContentWatcher(new LLEventStream("FacebookConnectContent")); + +// Local functions +void log_facebook_connect_error(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description) +{ +    // Note: 302 (redirect) is *not* an error that warrants logging +    if (status != 302) +    { +		LL_WARNS("FacebookConnect") << request << " request failed with a " << status << " " << reason << ". Reason: " << code << " (" << description << ")" << LL_ENDL; +    } +} + +void toast_user_for_success() +{ +	LLSD args; +    args["MESSAGE"] = LLTrans::getString("facebook_post_success"); +    LLNotificationsUtil::add("FacebookConnect", args); +} + +/////////////////////////////////////////////////////////////////////////////// +// +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") +			{ +				// this command probably came from the fbc_web browser, so close it +				LLFloater* fbc_web = LLFloaterReg::getInstance("fbc_web"); +				if (fbc_web) +				{ +					fbc_web->closeFloater(); +				} + +				// connect to facebook +				if (query_map.has("code")) +				{ +                    LLFacebookConnect::instance().connectToFacebook(query_map["code"], query_map.get("state")); +				} +				return true; +			} +		} +		return false; +	} +}; +LLFacebookConnectHandler gFacebookConnectHandler; + +/////////////////////////////////////////////////////////////////////////////// +// +class LLFacebookConnectResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLFacebookConnectResponder); +public: +	 +    LLFacebookConnectResponder() +    { +        LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS); +    } +     +	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (isGoodStatus(status)) +		{ +			LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL; +			 +            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); +		} +		else if (status != 302) +		{ +            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); +            log_facebook_connect_error("Connect", status, reason, content.get("error_code"), content.get("error_description")); +		} +	} +     +    void completedHeader(U32 status, const std::string& reason, const LLSD& content) +    { +        if (status == 302) +        { +            LLFacebookConnect::instance().openFacebookWeb(content["location"]); +        } +    } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +class LLFacebookShareResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLFacebookShareResponder); +public: +     +	LLFacebookShareResponder() +	{ +		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTING); +	} +	 +	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (isGoodStatus(status)) +		{ +            toast_user_for_success(); +			LL_DEBUGS("FacebookConnect") << "Post successful. content: " << content << LL_ENDL; +			 +			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED); +		} +		else if (status == 404) +		{ +			LLFacebookConnect::instance().connectToFacebook(); +		} +		else +		{ +            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POST_FAILED); +            log_facebook_connect_error("Share", status, reason, content.get("error_code"), content.get("error_description")); +		} +	} +     +    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: +  +	LLFacebookDisconnectResponder() +	{ +		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECTING); +	} + +	void setUserDisconnected() +	{ +		// Clear data +		LLFacebookConnect::instance().clearInfo(); +		LLFacebookConnect::instance().clearContent(); +		//Notify state change +		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); +	} + +	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (isGoodStatus(status))  +		{ +			LL_DEBUGS("FacebookConnect") << "Disconnect successful. content: " << content << LL_ENDL; +			setUserDisconnected(); + +		} +		//User not found so already disconnected +		else if(status == 404) +		{ +			LL_DEBUGS("FacebookConnect") << "Already disconnected. content: " << content << LL_ENDL; +			setUserDisconnected(); +		} +		else +		{ +			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); +            log_facebook_connect_error("Disconnect", status, reason, content.get("error_code"), content.get("error_description")); +		} +	} +}; + +/////////////////////////////////////////////////////////////////////////////// +// +class LLFacebookConnectedResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLFacebookConnectedResponder); +public: +     +	LLFacebookConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect) +    { +		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS); +    } +     +	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (isGoodStatus(status)) +		{ +			LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL; +             +            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); +		} +		else +		{ +			// show the facebook login page if not connected yet +			if (status == 404) +			{ +				if (mAutoConnect) +				{ +					LLFacebookConnect::instance().connectToFacebook(); +				} +				else +				{ +					LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); +				} +			} +            else +            { +                LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); +				log_facebook_connect_error("Connected", status, reason, content.get("error_code"), content.get("error_description")); +            } +		} +	} +     +private: +	bool mAutoConnect; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +class LLFacebookInfoResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLFacebookInfoResponder); +public: + +	virtual void completed(U32 status, const std::string& reason, const LLSD& info) +	{ +		if (isGoodStatus(status)) +		{ +			llinfos << "Facebook: Info received" << llendl; +			LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. info: " << info << LL_ENDL; +			LLFacebookConnect::instance().storeInfo(info); +		} +		else +		{ +			log_facebook_connect_error("Info", status, reason, info.get("error_code"), info.get("error_description")); +		} +	} + +	void completedHeader(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (status == 302) +		{ +			LLFacebookConnect::instance().openFacebookWeb(content["location"]); +		} +	} +}; + +/////////////////////////////////////////////////////////////////////////////// +// +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 +		{ +            log_facebook_connect_error("Friends", status, reason, content.get("error_code"), content.get("error_description")); +		} +	} + +    void completedHeader(U32 status, const std::string& reason, const LLSD& content) +    { +        if (status == 302) +        { +            LLFacebookConnect::instance().openFacebookWeb(content["location"]); +        } +    } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +LLFacebookConnect::LLFacebookConnect() +:	mConnectionState(FB_NOT_CONNECTED), +	mConnected(false), +	mInfo(), +    mContent(), +	mRefreshInfo(false), +	mRefreshContent(false), +	mReadFromMaster(false) +{ +} + +void LLFacebookConnect::openFacebookWeb(std::string url) +{ +	// Open the URL in an internal browser window without navigation UI +	LLFloaterWebContent::Params p; +    p.url(url).show_chrome(true); +    p.url(url).allow_address_entry(false); +    p.url(url).allow_back_forward_navigation(false); +    p.url(url).trusted_content(true); +	LLFloater *floater = LLFloaterReg::showInstance("fbc_web", p); +	//the internal web browser has a bug that prevents it from gaining focus unless a mouse event occurs first (it seems). +	//So when showing the internal web browser, set focus to it's containing floater "fbc_web". When a mouse event  +	//occurs on the "webbrowser" panel part of the floater, a mouse cursor will properly show and the "webbrowser" will gain focus. +	//fbc_web floater contains the "webbrowser" panel.    JIRA: ACME-744 +	gFocusMgr.setKeyboardFocus( floater ); + +	//LLUrlAction::openURLExternal(url); +} + +std::string LLFacebookConnect::getFacebookConnectURL(const std::string& route, bool include_read_from_master) +{ +	std::string url = gAgent.getRegion()->getCapability("FacebookConnect"); +	url += route; +     +	if (include_read_from_master && mReadFromMaster) +	{ +		url += "?read_from_master=true"; +	} +	return url; +} + +void LLFacebookConnect::connectToFacebook(const std::string& auth_code, const std::string& auth_state) +{ +	LLSD body; +	if (!auth_code.empty()) +		body["code"] = auth_code; +	if (!auth_state.empty()) +		body["state"] = auth_state; +     +	LLHTTPClient::put(getFacebookConnectURL("/connection"), body, new LLFacebookConnectResponder()); +} + +void LLFacebookConnect::disconnectFromFacebook() +{ +	LLHTTPClient::del(getFacebookConnectURL("/connection"), new LLFacebookDisconnectResponder()); +} + +void LLFacebookConnect::checkConnectionToFacebook(bool auto_connect) +{ +	const bool follow_redirects = false; +	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	LLHTTPClient::get(getFacebookConnectURL("/connection", true), new LLFacebookConnectedResponder(auto_connect), +						LLSD(), timeout, follow_redirects); +} + +void LLFacebookConnect::loadFacebookInfo() +{ +	if(mRefreshInfo) +	{ +		const bool follow_redirects = false; +		const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +		LLHTTPClient::get(getFacebookConnectURL("/info", true), new LLFacebookInfoResponder(), +			LLSD(), timeout, follow_redirects); +	} +} + +void LLFacebookConnect::loadFacebookFriends() +{ +	if(mRefreshContent) +	{ +		const bool follow_redirects = false; +		const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +		LLHTTPClient::get(getFacebookConnectURL("/friends", true), new LLFacebookFriendsResponder(), +			LLSD(), timeout, follow_redirects); +	} +} + +void LLFacebookConnect::postCheckin(const std::string& location, const std::string& name, const std::string& description, const std::string& image, const std::string& message) +{ +	LLSD body; +	if (!location.empty()) +		body["location"] = location; +	if (!name.empty()) +		body["name"] = name; +	if (!description.empty()) +		body["description"] = description; +	if (!image.empty()) +		body["image"] = image; +	if (!message.empty()) +		body["message"] = message; + +	// Note: we can use that route for different publish action. We should be able to use the same responder. +	LLHTTPClient::post(getFacebookConnectURL("/share/checkin", true), body, new LLFacebookShareResponder()); +} + +void LLFacebookConnect::sharePhoto(const std::string& image_url, const std::string& caption) +{ +	LLSD body; +	body["image"] = image_url; +	body["caption"] = caption; +	 +    // Note: we can use that route for different publish action. We should be able to use the same responder. +	LLHTTPClient::post(getFacebookConnectURL("/share/photo", true), body, new LLFacebookShareResponder()); +} + +void LLFacebookConnect::sharePhoto(LLPointer<LLImageFormatted> image, const std::string& caption) +{ +	std::string imageFormat; +	if (dynamic_cast<LLImagePNG*>(image.get())) +	{ +		imageFormat = "png"; +	} +	else if (dynamic_cast<LLImageJPEG*>(image.get())) +	{ +		imageFormat = "jpg"; +	} +	else +	{ +		llwarns << "Image to upload is not a PNG or JPEG" << llendl; +		return; +	} +	 +	// All this code is mostly copied from LLWebProfile::post() +	const std::string boundary = "----------------------------0123abcdefab"; + +	LLSD headers; +	headers["Content-Type"] = "multipart/form-data; boundary=" + boundary; + +	std::ostringstream body; + +	// *NOTE: The order seems to matter. +	body	<< "--" << boundary << "\r\n" +			<< "Content-Disposition: form-data; name=\"caption\"\r\n\r\n" +			<< caption << "\r\n"; + +	body	<< "--" << boundary << "\r\n" +			<< "Content-Disposition: form-data; name=\"image\"; filename=\"snapshot." << imageFormat << "\"\r\n" +			<< "Content-Type: image/" << imageFormat << "\r\n\r\n"; + +	// Insert the image data. +	// *FIX: Treating this as a string will probably screw it up ... +	U8* image_data = image->getData(); +	for (S32 i = 0; i < image->getDataSize(); ++i) +	{ +		body << image_data[i]; +	} + +	body <<	"\r\n--" << boundary << "--\r\n"; + +	// postRaw() takes ownership of the buffer and releases it later. +	size_t size = body.str().size(); +	U8 *data = new U8[size]; +	memcpy(data, body.str().data(), size); +	 +    // Note: we can use that route for different publish action. We should be able to use the same responder. +	LLHTTPClient::postRaw(getFacebookConnectURL("/share/photo", true), data, size, new LLFacebookShareResponder(), headers); +} + +void LLFacebookConnect::updateStatus(const std::string& message) +{ +	LLSD body; +	body["message"] = message; +	 +    // Note: we can use that route for different publish action. We should be able to use the same responder. +	LLHTTPClient::post(getFacebookConnectURL("/share/wall", true), body, new LLFacebookShareResponder()); +} + +void LLFacebookConnect::storeInfo(const LLSD& info) +{ +	mInfo = info; +	mRefreshInfo = false; + +	sInfoWatcher->post(info); +} + +const LLSD& LLFacebookConnect::getInfo() const +{ +	return mInfo; +} + +void LLFacebookConnect::clearInfo() +{ +	mInfo = LLSD(); +} + +void LLFacebookConnect::storeContent(const LLSD& content) +{ +    mContent = content; +	mRefreshContent = false; + +	sContentWatcher->post(content); +} + +const LLSD& LLFacebookConnect::getContent() const +{ +    return mContent; +} + +void LLFacebookConnect::clearContent() +{ +    mContent = LLSD(); +} + +void LLFacebookConnect::setDataDirty() +{ +	mRefreshInfo = true; +	mRefreshContent = true; +} + +void LLFacebookConnect::setConnectionState(LLFacebookConnect::EConnectionState connection_state) +{ +	if(connection_state == FB_CONNECTED) +	{ +		mReadFromMaster = true; +		setConnected(true); +		setDataDirty(); +	} +	else if(connection_state == FB_NOT_CONNECTED) +	{ +		setConnected(false); +	} +	else if(connection_state == FB_POSTED) +	{ +		mReadFromMaster = false; +	} + +	if (mConnectionState != connection_state) +	{ +		LLSD state_info; +		state_info["enum"] = connection_state; +		sStateWatcher->post(state_info); +	} +	 +	mConnectionState = connection_state; +} + +void LLFacebookConnect::setConnected(bool connected) +{ +	mConnected = connected; +} diff --git a/indra/newview/llfacebookconnect.h b/indra/newview/llfacebookconnect.h new file mode 100644 index 0000000000..a77ac24167 --- /dev/null +++ b/indra/newview/llfacebookconnect.h @@ -0,0 +1,106 @@ +/**  + * @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" +#include "llimage.h" + +class LLEventPump; + +/** + * @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: +    enum EConnectionState +	{ +		FB_NOT_CONNECTED = 0, +		FB_CONNECTION_IN_PROGRESS = 1, +		FB_CONNECTED = 2, +		FB_CONNECTION_FAILED = 3, +		FB_POSTING = 4, +		FB_POSTED = 5, +		FB_POST_FAILED = 6, +		FB_DISCONNECTING = 7, +		FB_DISCONNECT_FAILED = 8 +	}; +	 +	void connectToFacebook(const std::string& auth_code = "", const std::string& auth_state = "");	// Initiate the complete FB connection. Please use checkConnectionToFacebook() in normal use. +	void disconnectFromFacebook();																	// Disconnect from the FBC service. +    void checkConnectionToFacebook(bool auto_connect = false);										// Check if an access token is available on the FBC service. If not, call connectToFacebook(). +     +	void loadFacebookInfo(); +    void loadFacebookFriends(); +	void postCheckin(const std::string& location, const std::string& name, const std::string& description, const std::string& picture, const std::string& message); +    void sharePhoto(const std::string& image_url, const std::string& caption); +	void sharePhoto(LLPointer<LLImageFormatted> image, const std::string& caption); +	void updateStatus(const std::string& message); +	 +	void storeInfo(const LLSD& info); +	const LLSD& getInfo() const; +	void clearInfo(); +	void storeContent(const LLSD& content); +    const LLSD& getContent() const; +	void clearContent(); +	void setDataDirty(); +     +    void setConnectionState(EConnectionState connection_state); +	void setConnected(bool connected); +	bool isConnected() { return mConnected; } +	bool isTransactionOngoing() { return ((mConnectionState == FB_CONNECTION_IN_PROGRESS) || (mConnectionState == FB_POSTING) || (mConnectionState == FB_DISCONNECTING)); } +    EConnectionState getConnectionState() { return mConnectionState; } +     +    void openFacebookWeb(std::string url); + +private: +	friend class LLSingleton<LLFacebookConnect>; + +	LLFacebookConnect(); +	~LLFacebookConnect() {}; + 	std::string getFacebookConnectURL(const std::string& route = "", bool include_read_from_master = false); +    +    EConnectionState mConnectionState; +	BOOL mConnected; +	LLSD mInfo; +    LLSD mContent; +	bool mRefreshInfo; +	bool mRefreshContent; +	bool mReadFromMaster; +	 +	static boost::scoped_ptr<LLEventPump> sStateWatcher; +	static boost::scoped_ptr<LLEventPump> sInfoWatcher; +	static boost::scoped_ptr<LLEventPump> sContentWatcher; +}; + +#endif // LL_LLFACEBOOKCONNECT_H diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 4591b80ac4..cc73ae031b 100755 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -662,10 +662,10 @@ void LLFloaterIMContainer::setVisible(BOOL visible)  			LLFloater* session_floater = widget->getSessionFloater();  			if (session_floater != nearby_chat)  			{ -				widget->setVisibleIfDetached(visible); -			} +		    widget->setVisibleIfDetached(visible);  		}  	} +	}  	// Now, do the normal multifloater show/hide  	LLMultiFloater::setVisible(visible); @@ -695,13 +695,13 @@ void LLFloaterIMContainer::setVisibleAndFrontmost(BOOL take_focus, const LLSD& k  	// Only select other sessions  	if (!getSelectedSession().isNull())  	{ -		selectConversationPair(getSelectedSession(), false, take_focus); +    selectConversationPair(getSelectedSession(), false, take_focus);  	}  	if (mInitialized && mIsFirstLaunch)  	{  		collapseMessagesPane(gSavedPerAccountSettings.getBOOL("ConversationsMessagePaneCollapsed"));  		mIsFirstLaunch = false; -	} +}  }  void LLFloaterIMContainer::updateResizeLimits() @@ -829,7 +829,7 @@ void LLFloaterIMContainer::assignResizeLimits()  	S32 conv_pane_target_width = is_conv_pane_expanded  		? ( is_msg_pane_expanded?mConversationsPane->getRect().getWidth():mConversationsPane->getExpandedMinDim() ) -		: mConversationsPane->getMinDim(); +			: 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; @@ -990,7 +990,7 @@ void LLFloaterIMContainer::setSortOrder(const LLConversationSort& order)  			conversation_floater->setSortOrder(order);  		}  	} - +	  	gSavedSettings.setU32("ConversationSortOrder", (U32)order);  } @@ -1177,7 +1177,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());  			} @@ -1199,7 +1199,7 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,      	    {      	      	LLFloaterReg::showInstance("preview_conversation", LLSD(LLUUID::null), true);      	    } -    	} +}      }  } @@ -1230,7 +1230,7 @@ void LLFloaterIMContainer::doToSelectedGroup(const LLSD& userdata)      if (action == "group_profile")      { -    	LLGroupActions::show(mSelectedSession); +        LLGroupActions::show(mSelectedSession);      }      else if (action == "activate_group")      { diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index d8d62e5bbb..ea385d7baf 100755 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -28,60 +28,23 @@  #include "llfloatersnapshot.h" -#include "llfloaterreg.h" - -// Viewer includes  #include "llagent.h" -#include "llagentcamera.h" -#include "llcallbacklist.h" -#include "llcriticaldamp.h" -#include "llfloaterperms.h" -#include "llui.h" -#include "llfocusmgr.h" -#include "llbutton.h" +#include "llfacebookconnect.h" +#include "llfloaterreg.h" +#include "llfloatersocial.h" +#include "llcheckboxctrl.h"  #include "llcombobox.h" -#include "lleconomy.h" -#include "lllandmarkactions.h" -#include "llpanelsnapshot.h" +#include "llpostcard.h" +#include "llresmgr.h"		// LLLocale +#include "llsdserialize.h"  #include "llsidetraypanelcontainer.h" -#include "llsliderctrl.h" +#include "llsnapshotlivepreview.h"  #include "llspinctrl.h"  #include "llviewercontrol.h" -#include "lluictrlfactory.h" -#include "llviewerstats.h" -#include "llviewercamera.h" -#include "llviewerwindow.h" -#include "llviewermenufile.h"	// upload_new_resource() -#include "llcheckboxctrl.h" -#include "llslurl.h"  #include "lltoolfocus.h"  #include "lltoolmgr.h" -#include "llwebsharing.h" -#include "llworld.h" -#include "llagentui.h" - -// Linden library includes -#include "llfontgl.h" -#include "llsys.h" -#include "llrender.h" -#include "v3dmath.h" -#include "llmath.h" -#include "lldir.h" -#include "llsdserialize.h" -#include "llgl.h" -#include "llglheaders.h" -#include "llimagejpeg.h" -#include "llimagepng.h" -#include "llimagebmp.h" -#include "llimagej2c.h" -#include "lllocalcliprect.h" -#include "llnotificationsutil.h" -#include "llpostcard.h" -#include "llresmgr.h"		// LLLocale -#include "llvfile.h" -#include "llvfs.h"  #include "llwebprofile.h" -#include "llwindow.h" +#include "llwebsharing.h"  ///----------------------------------------------------------------------------  /// Local function declarations, constants, enums, and typedefs @@ -91,949 +54,12 @@ LLSnapshotFloaterView* gSnapshotFloaterView = NULL;  const F32 AUTO_SNAPSHOT_TIME_DELAY = 1.f; -F32 SHINE_TIME = 0.5f; -F32 SHINE_WIDTH = 0.6f; -F32 SHINE_OPACITY = 0.3f; -F32 FALL_TIME = 0.6f; -S32 BORDER_WIDTH = 6; -  const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte  const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512  static LLDefaultChildRegistry::Register<LLSnapshotFloaterView> r("snapshot_floater_view"); -///---------------------------------------------------------------------------- -/// Class LLSnapshotLivePreview  -///---------------------------------------------------------------------------- -class LLSnapshotLivePreview : public LLView -{ -	LOG_CLASS(LLSnapshotLivePreview); -public: -	enum ESnapshotType -	{ -		SNAPSHOT_POSTCARD, -		SNAPSHOT_TEXTURE, -		SNAPSHOT_LOCAL, -		SNAPSHOT_WEB -	}; - - -	struct Params : public LLInitParam::Block<Params, LLView::Params> -	{ -		Params() -		{ -			name = "snapshot_live_preview"; -			mouse_opaque = false; -		} -	}; - - -	LLSnapshotLivePreview(const LLSnapshotLivePreview::Params& p); -	~LLSnapshotLivePreview(); - -	/*virtual*/ void draw(); -	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent); -	 -	void setSize(S32 w, S32 h); -	void setWidth(S32 w) { mWidth[mCurImageIndex] = w; } -	void setHeight(S32 h) { mHeight[mCurImageIndex] = h; } -	void getSize(S32& w, S32& h) const; -	S32 getWidth() const { return mWidth[mCurImageIndex]; } -	S32 getHeight() const { return mHeight[mCurImageIndex]; } -	S32 getDataSize() const { return mDataSize; } -	void setMaxImageSize(S32 size) ; -	S32  getMaxImageSize() {return mMaxImageSize ;} -	 -	ESnapshotType getSnapshotType() const { return mSnapshotType; } -	LLFloaterSnapshot::ESnapshotFormat getSnapshotFormat() const { return mSnapshotFormat; } -	BOOL getSnapshotUpToDate() const { return mSnapshotUpToDate; } -	BOOL isSnapshotActive() { return mSnapshotActive; } -	LLViewerTexture* getThumbnailImage() const { return mThumbnailImage ; } -	S32  getThumbnailWidth() const { return mThumbnailWidth ; } -	S32  getThumbnailHeight() const { return mThumbnailHeight ; } -	BOOL getThumbnailLock() const { return mThumbnailUpdateLock ; } -	BOOL getThumbnailUpToDate() const { return mThumbnailUpToDate ;} -	LLViewerTexture* getCurrentImage(); -	F32 getImageAspect(); -	F32 getAspect() ; -	const LLRect& getImageRect() const { return mImageRect[mCurImageIndex]; } -	BOOL isImageScaled() const { return mImageScaled[mCurImageIndex]; } -	void setImageScaled(BOOL scaled) { mImageScaled[mCurImageIndex] = scaled; } -	const LLVector3d& getPosTakenGlobal() const { return mPosTakenGlobal; } -	 -	void setSnapshotType(ESnapshotType type) { mSnapshotType = type; } -	void setSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat type) { mSnapshotFormat = type; } -	void setSnapshotQuality(S32 quality); -	void setSnapshotBufferType(LLViewerWindow::ESnapshotType type) { mSnapshotBufferType = type; } -	void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f); -	void saveWeb(); -	void saveTexture(); -	BOOL saveLocal(); - -	LLPointer<LLImageFormatted>	getFormattedImage() const { return mFormattedImage; } -	LLPointer<LLImageRaw>		getEncodedImage() const { return mPreviewImageEncoded; } - -	/// Sets size of preview thumbnail image and thhe surrounding rect. -	BOOL setThumbnailImageSize() ; -	void generateThumbnailImage(BOOL force_update = FALSE) ; -	void resetThumbnailImage() { mThumbnailImage = NULL ; } -	void drawPreviewRect(S32 offset_x, S32 offset_y) ; - -	// Returns TRUE when snapshot generated, FALSE otherwise. -	static BOOL onIdle( void* snapshot_preview ); - -	// callback for region name resolve -	void regionNameCallback(LLImageJPEG* snapshot, LLSD& metadata, const std::string& name, S32 x, S32 y, S32 z); - -private: -	LLColor4					mColor; -	LLPointer<LLViewerTexture>	mViewerImage[2]; //used to represent the scene when the frame is frozen. -	LLRect						mImageRect[2]; -	S32							mWidth[2]; -	S32							mHeight[2]; -	BOOL						mImageScaled[2]; -	S32                         mMaxImageSize ; -	 -	//thumbnail image -	LLPointer<LLViewerTexture>	mThumbnailImage ; -	S32                         mThumbnailWidth ; -	S32                         mThumbnailHeight ; -	LLRect                      mPreviewRect ; -	BOOL                        mThumbnailUpdateLock ; -	BOOL                        mThumbnailUpToDate ; - -	S32							mCurImageIndex; -	LLPointer<LLImageRaw>		mPreviewImage; -	LLPointer<LLImageRaw>		mPreviewImageEncoded; -	LLPointer<LLImageFormatted>	mFormattedImage; -	LLFrameTimer				mSnapshotDelayTimer; -	S32							mShineCountdown; -	LLFrameTimer				mShineAnimTimer; -	F32							mFlashAlpha; -	BOOL						mNeedsFlash; -	LLVector3d					mPosTakenGlobal; -	S32							mSnapshotQuality; -	S32							mDataSize; -	ESnapshotType				mSnapshotType; -	LLFloaterSnapshot::ESnapshotFormat	mSnapshotFormat; -	BOOL						mSnapshotUpToDate; -	LLFrameTimer				mFallAnimTimer; -	LLVector3					mCameraPos; -	LLQuaternion				mCameraRot; -	BOOL						mSnapshotActive; -	LLViewerWindow::ESnapshotType mSnapshotBufferType; - -public: -	static std::set<LLSnapshotLivePreview*> sList; -	BOOL                        mKeepAspectRatio ; -}; - -std::set<LLSnapshotLivePreview*> LLSnapshotLivePreview::sList; - -LLSnapshotLivePreview::LLSnapshotLivePreview (const LLSnapshotLivePreview::Params& p)  -:	LLView(p), -	mColor(1.f, 0.f, 0.f, 0.5f),  -	mCurImageIndex(0), -	mPreviewImage(NULL), -	mThumbnailImage(NULL) , -	mThumbnailWidth(0), -	mThumbnailHeight(0), -	mPreviewImageEncoded(NULL), -	mFormattedImage(NULL), -	mShineCountdown(0), -	mFlashAlpha(0.f), -	mNeedsFlash(TRUE), -	mSnapshotQuality(gSavedSettings.getS32("SnapshotQuality")), -	mDataSize(0), -	mSnapshotType(SNAPSHOT_POSTCARD), -	mSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat"))), -	mSnapshotUpToDate(FALSE), -	mCameraPos(LLViewerCamera::getInstance()->getOrigin()), -	mCameraRot(LLViewerCamera::getInstance()->getQuaternion()), -	mSnapshotActive(FALSE), -	mSnapshotBufferType(LLViewerWindow::SNAPSHOT_TYPE_COLOR) -{ -	setSnapshotQuality(gSavedSettings.getS32("SnapshotQuality")); -	mSnapshotDelayTimer.setTimerExpirySec(0.0f); -	mSnapshotDelayTimer.start(); -// 	gIdleCallbacks.addFunction( &LLSnapshotLivePreview::onIdle, (void*)this ); -	sList.insert(this); -	setFollowsAll(); -	mWidth[0] = gViewerWindow->getWindowWidthRaw(); -	mWidth[1] = gViewerWindow->getWindowWidthRaw(); -	mHeight[0] = gViewerWindow->getWindowHeightRaw(); -	mHeight[1] = gViewerWindow->getWindowHeightRaw(); -	mImageScaled[0] = FALSE; -	mImageScaled[1] = FALSE; - -	mMaxImageSize = MAX_SNAPSHOT_IMAGE_SIZE ; -	mKeepAspectRatio = gSavedSettings.getBOOL("KeepAspectForSnapshot") ; -	mThumbnailUpdateLock = FALSE ; -	mThumbnailUpToDate   = FALSE ; -} - -LLSnapshotLivePreview::~LLSnapshotLivePreview() -{ -	// delete images -	mPreviewImage = NULL; -	mPreviewImageEncoded = NULL; -	mFormattedImage = NULL; - -// 	gIdleCallbacks.deleteFunction( &LLSnapshotLivePreview::onIdle, (void*)this ); -	sList.erase(this); -} - -void LLSnapshotLivePreview::setMaxImageSize(S32 size)  -{ -	if(size < MAX_SNAPSHOT_IMAGE_SIZE) -	{ -		mMaxImageSize = size; -	} -	else -	{ -		mMaxImageSize = MAX_SNAPSHOT_IMAGE_SIZE ; -	} -} - -LLViewerTexture* LLSnapshotLivePreview::getCurrentImage() -{ -	return mViewerImage[mCurImageIndex]; -} - -F32 LLSnapshotLivePreview::getAspect() -{ -	F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight()); -	F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight()); - -	if (!mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot")) -	{ -		return image_aspect_ratio; -	} -	else -	{ -		return window_aspect_ratio; -	} -} - -F32 LLSnapshotLivePreview::getImageAspect() -{ -	if (!getCurrentImage()) -	{ -		return 0.f; -	} - -	return getAspect() ;	 -} - -void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail, F32 delay)  -{ -	// Invalidate current image. -	lldebugs << "updateSnapshot: mSnapshotUpToDate = " << getSnapshotUpToDate() << llendl; -	if (getSnapshotUpToDate()) -	{ -		S32 old_image_index = mCurImageIndex; -		mCurImageIndex = (mCurImageIndex + 1) % 2;  -		setSize(mWidth[old_image_index], mHeight[old_image_index]); -		mFallAnimTimer.start();		 -	} -	mSnapshotUpToDate = FALSE; 		 - -	// Update snapshot source rect depending on whether we keep the aspect ratio. -	LLRect& rect = mImageRect[mCurImageIndex]; -	rect.set(0, getRect().getHeight(), getRect().getWidth(), 0); - -	F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight()); -	F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight()); - -	if (mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot")) -	{ -		if (image_aspect_ratio > window_aspect_ratio) -		{ -			// trim off top and bottom -			S32 new_height = llround((F32)getRect().getWidth() / image_aspect_ratio);  -			rect.mBottom += (getRect().getHeight() - new_height) / 2; -			rect.mTop -= (getRect().getHeight() - new_height) / 2; -		} -		else if (image_aspect_ratio < window_aspect_ratio) -		{ -			// trim off left and right -			S32 new_width = llround((F32)getRect().getHeight() * image_aspect_ratio);  -			rect.mLeft += (getRect().getWidth() - new_width) / 2; -			rect.mRight -= (getRect().getWidth() - new_width) / 2; -		} -	} - -	// Stop shining animation. -	mShineAnimTimer.stop(); - -	// Update snapshot if requested. -	if (new_snapshot) -	{ -		mSnapshotDelayTimer.start(); -		mSnapshotDelayTimer.setTimerExpirySec(delay); -		LLFloaterSnapshot::preUpdate(); -	} - -	// Update thumbnail if requested. -	if(new_thumbnail) -	{ -		mThumbnailUpToDate = FALSE ; -	} -} - -void LLSnapshotLivePreview::setSnapshotQuality(S32 quality) -{ -	llclamp(quality, 0, 100); -	if (quality != mSnapshotQuality) -	{ -		mSnapshotQuality = quality; -		gSavedSettings.setS32("SnapshotQuality", quality); -		mSnapshotUpToDate = FALSE; -	} -} - -void LLSnapshotLivePreview::drawPreviewRect(S32 offset_x, S32 offset_y) -{ -	F32 line_width ;  -	glGetFloatv(GL_LINE_WIDTH, &line_width) ; -	glLineWidth(2.0f * line_width) ; -	LLColor4 color(0.0f, 0.0f, 0.0f, 1.0f) ; -	gl_rect_2d( mPreviewRect.mLeft + offset_x, mPreviewRect.mTop + offset_y, -				mPreviewRect.mRight + offset_x, mPreviewRect.mBottom + offset_y, color, FALSE ) ; -	glLineWidth(line_width) ; - -	//draw four alpha rectangles to cover areas outside of the snapshot image -	if(!mKeepAspectRatio) -	{ -		LLColor4 alpha_color(0.5f, 0.5f, 0.5f, 0.8f) ; -		S32 dwl = 0, dwr = 0 ; -		if(mThumbnailWidth > mPreviewRect.getWidth()) -		{ -			dwl = (mThumbnailWidth - mPreviewRect.getWidth()) >> 1 ; -			dwr = mThumbnailWidth - mPreviewRect.getWidth() - dwl ; - -			gl_rect_2d(mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mTop + offset_y, -				mPreviewRect.mLeft + offset_x, mPreviewRect.mBottom + offset_y, alpha_color, TRUE ) ; -			gl_rect_2d( mPreviewRect.mRight + offset_x, mPreviewRect.mTop + offset_y, -				mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mBottom + offset_y, alpha_color, TRUE ) ; -		} - -		if(mThumbnailHeight > mPreviewRect.getHeight()) -		{ -			S32 dh = (mThumbnailHeight - mPreviewRect.getHeight()) >> 1 ; -			gl_rect_2d(mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mBottom + offset_y , -				mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mBottom + offset_y - dh, alpha_color, TRUE ) ; - -			dh = mThumbnailHeight - mPreviewRect.getHeight() - dh ; -			gl_rect_2d( mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mTop + offset_y + dh, -				mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mTop + offset_y, alpha_color, TRUE ) ; -		} -	} -} - -//called when the frame is frozen. -void LLSnapshotLivePreview::draw() -{ -	if (getCurrentImage() && -	    mPreviewImageEncoded.notNull() && -	    getSnapshotUpToDate()) -	{ -		LLColor4 bg_color(0.f, 0.f, 0.3f, 0.4f); -		gl_rect_2d(getRect(), bg_color); -		const LLRect& rect = getImageRect(); -		LLRect shadow_rect = rect; -		shadow_rect.stretch(BORDER_WIDTH); -		gl_drop_shadow(shadow_rect.mLeft, shadow_rect.mTop, shadow_rect.mRight, shadow_rect.mBottom, LLColor4(0.f, 0.f, 0.f, mNeedsFlash ? 0.f :0.5f), 10); - -		LLColor4 image_color(1.f, 1.f, 1.f, 1.f); -		gGL.color4fv(image_color.mV); -		gGL.getTexUnit(0)->bind(getCurrentImage()); -		// calculate UV scale -		F32 uv_width = isImageScaled() ? 1.f : llmin((F32)getWidth() / (F32)getCurrentImage()->getWidth(), 1.f); -		F32 uv_height = isImageScaled() ? 1.f : llmin((F32)getHeight() / (F32)getCurrentImage()->getHeight(), 1.f); -		gGL.pushMatrix(); -		{ -			gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom, 0.f); -			gGL.begin(LLRender::QUADS); -			{ -				gGL.texCoord2f(uv_width, uv_height); -				gGL.vertex2i(rect.getWidth(), rect.getHeight() ); - -				gGL.texCoord2f(0.f, uv_height); -				gGL.vertex2i(0, rect.getHeight() ); - -				gGL.texCoord2f(0.f, 0.f); -				gGL.vertex2i(0, 0); - -				gGL.texCoord2f(uv_width, 0.f); -				gGL.vertex2i(rect.getWidth(), 0); -			} -			gGL.end(); -		} -		gGL.popMatrix(); - -		gGL.color4f(1.f, 1.f, 1.f, mFlashAlpha); -		gl_rect_2d(getRect()); -		if (mNeedsFlash) -		{ -			if (mFlashAlpha < 1.f) -			{ -				mFlashAlpha = lerp(mFlashAlpha, 1.f, LLCriticalDamp::getInterpolant(0.02f)); -			} -			else -			{ -				mNeedsFlash = FALSE; -			} -		} -		else -		{ -			mFlashAlpha = lerp(mFlashAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f)); -		} - -		// Draw shining animation if appropriate. -		if (mShineCountdown > 0) -		{ -			mShineCountdown--; -			if (mShineCountdown == 0) -			{ -				mShineAnimTimer.start(); -			} -		} -		else if (mShineAnimTimer.getStarted()) -		{ -			lldebugs << "Drawing shining animation" << llendl; -			F32 shine_interp = llmin(1.f, mShineAnimTimer.getElapsedTimeF32() / SHINE_TIME); -			 -			// draw "shine" effect -			LLLocalClipRect clip(getLocalRect()); -			{ -				// draw diagonal stripe with gradient that passes over screen -				S32 x1 = gViewerWindow->getWindowWidthScaled() * llround((clamp_rescale(shine_interp, 0.f, 1.f, -1.f - SHINE_WIDTH, 1.f))); -				S32 x2 = x1 + llround(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH); -				S32 x3 = x2 + llround(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH); -				S32 y1 = 0; -				S32 y2 = gViewerWindow->getWindowHeightScaled(); - -				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -				gGL.begin(LLRender::QUADS); -				{ -					gGL.color4f(1.f, 1.f, 1.f, 0.f); -					gGL.vertex2i(x1, y1); -					gGL.vertex2i(x1 + gViewerWindow->getWindowWidthScaled(), y2); -					gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY); -					gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2); -					gGL.vertex2i(x2, y1); - -					gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY); -					gGL.vertex2i(x2, y1); -					gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2); -					gGL.color4f(1.f, 1.f, 1.f, 0.f); -					gGL.vertex2i(x3 + gViewerWindow->getWindowWidthScaled(), y2); -					gGL.vertex2i(x3, y1); -				} -				gGL.end(); -			} - -			// if we're at the end of the animation, stop -			if (shine_interp >= 1.f) -			{ -				mShineAnimTimer.stop(); -			} -		} -	} - -	// draw framing rectangle -	{ -		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -		gGL.color4f(1.f, 1.f, 1.f, 1.f); -		const LLRect& outline_rect = getImageRect(); -		gGL.begin(LLRender::QUADS); -		{ -			gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); -			gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); -			gGL.vertex2i(outline_rect.mRight, outline_rect.mTop); -			gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop); - -			gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom); -			gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom); -			gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); -			gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); - -			gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop); -			gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom); -			gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); -			gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); - -			gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom); -			gGL.vertex2i(outline_rect.mRight, outline_rect.mTop); -			gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); -			gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); -		} -		gGL.end(); -	} - -	// draw old image dropping away -	if (mFallAnimTimer.getStarted()) -	{ -		S32 old_image_index = (mCurImageIndex + 1) % 2; -		if (mViewerImage[old_image_index].notNull() && mFallAnimTimer.getElapsedTimeF32() < FALL_TIME) -		{ -			lldebugs << "Drawing fall animation" << llendl; -			F32 fall_interp = mFallAnimTimer.getElapsedTimeF32() / FALL_TIME; -			F32 alpha = clamp_rescale(fall_interp, 0.f, 1.f, 0.8f, 0.4f); -			LLColor4 image_color(1.f, 1.f, 1.f, alpha); -			gGL.color4fv(image_color.mV); -			gGL.getTexUnit(0)->bind(mViewerImage[old_image_index]); -			// calculate UV scale -			// *FIX get this to work with old image -			BOOL rescale = !mImageScaled[old_image_index] && mViewerImage[mCurImageIndex].notNull(); -			F32 uv_width = rescale ? llmin((F32)mWidth[old_image_index] / (F32)mViewerImage[mCurImageIndex]->getWidth(), 1.f) : 1.f; -			F32 uv_height = rescale ? llmin((F32)mHeight[old_image_index] / (F32)mViewerImage[mCurImageIndex]->getHeight(), 1.f) : 1.f; -			gGL.pushMatrix(); -			{ -				LLRect& rect = mImageRect[old_image_index]; -				gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom - llround(getRect().getHeight() * 2.f * (fall_interp * fall_interp)), 0.f); -				gGL.rotatef(-45.f * fall_interp, 0.f, 0.f, 1.f); -				gGL.begin(LLRender::QUADS); -				{ -					gGL.texCoord2f(uv_width, uv_height); -					gGL.vertex2i(rect.getWidth(), rect.getHeight() ); - -					gGL.texCoord2f(0.f, uv_height); -					gGL.vertex2i(0, rect.getHeight() ); - -					gGL.texCoord2f(0.f, 0.f); -					gGL.vertex2i(0, 0); -					gGL.texCoord2f(uv_width, 0.f); -					gGL.vertex2i(rect.getWidth(), 0); -				} -				gGL.end(); -			} -			gGL.popMatrix(); -		} -	} -} - -/*virtual*/  -void LLSnapshotLivePreview::reshape(S32 width, S32 height, BOOL called_from_parent) -{ -	LLRect old_rect = getRect(); -	LLView::reshape(width, height, called_from_parent); -	if (old_rect.getWidth() != width || old_rect.getHeight() != height) -	{ -		lldebugs << "window reshaped, updating thumbnail" << llendl; -		updateSnapshot(FALSE, TRUE); -	} -} - -BOOL LLSnapshotLivePreview::setThumbnailImageSize() -{ -	if(getWidth() < 10 || getHeight() < 10) -	{ -		return FALSE ; -	} -	S32 window_width = gViewerWindow->getWindowWidthRaw() ; -	S32 window_height = gViewerWindow->getWindowHeightRaw() ; - -	F32 window_aspect_ratio = ((F32)window_width) / ((F32)window_height); - -	// UI size for thumbnail -	// *FIXME: the rect does not change, so maybe there's no need to recalculate max w/h. -	const LLRect& thumbnail_rect = LLFloaterSnapshot::getThumbnailPlaceholderRect(); -	S32 max_width = thumbnail_rect.getWidth(); -	S32 max_height = thumbnail_rect.getHeight(); - -	if (window_aspect_ratio > (F32)max_width / max_height) -	{ -		// image too wide, shrink to width -		mThumbnailWidth = max_width; -		mThumbnailHeight = llround((F32)max_width / window_aspect_ratio); -	} -	else -	{ -		// image too tall, shrink to height -		mThumbnailHeight = max_height; -		mThumbnailWidth = llround((F32)max_height * window_aspect_ratio); -	} -	 -	if(mThumbnailWidth > window_width || mThumbnailHeight > window_height) -	{ -		return FALSE ;//if the window is too small, ignore thumbnail updating. -	} - -	S32 left = 0 , top = mThumbnailHeight, right = mThumbnailWidth, bottom = 0 ; -	if(!mKeepAspectRatio) -	{ -		F32 ratio_x = (F32)getWidth() / window_width ; -		F32 ratio_y = (F32)getHeight() / window_height ; - -		//if(getWidth() > window_width || -		//	getHeight() > window_height ) -		{ -			if(ratio_x > ratio_y) -			{ -				top = (S32)(top * ratio_y / ratio_x) ; -			} -			else -			{ -				right = (S32)(right * ratio_x / ratio_y) ; -			}			 -		} -		//else -		//{ -		//	right = (S32)(right * ratio_x) ; -		//	top = (S32)(top * ratio_y) ; -		//} -		left = (S32)((mThumbnailWidth - right) * 0.5f) ; -		bottom = (S32)((mThumbnailHeight - top) * 0.5f) ; -		top += bottom ; -		right += left ; -	} -	mPreviewRect.set(left - 1, top + 1, right + 1, bottom - 1) ; - -	return TRUE ; -} - -void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update) -{	 -	if(mThumbnailUpdateLock) //in the process of updating -	{ -		return ; -	} -	if(getThumbnailUpToDate() && !force_update)//already updated -	{ -		return ; -	} -	if(getWidth() < 10 || getHeight() < 10) -	{ -		return ; -	} - -	////lock updating -	mThumbnailUpdateLock = TRUE ; - -	if(!setThumbnailImageSize()) -	{ -		mThumbnailUpdateLock = FALSE ; -		mThumbnailUpToDate = TRUE ; -		return ; -	} - -	if(mThumbnailImage) -	{ -		resetThumbnailImage() ; -	}		 - -	LLPointer<LLImageRaw> raw = new LLImageRaw; -	if(!gViewerWindow->thumbnailSnapshot(raw, -							mThumbnailWidth, mThumbnailHeight, -							gSavedSettings.getBOOL("RenderUIInSnapshot"), -							FALSE, -							mSnapshotBufferType) )								 -	{ -		raw = NULL ; -	} - -	if(raw) -	{ -		raw->expandToPowerOfTwo(); -		mThumbnailImage = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); 		 -		mThumbnailUpToDate = TRUE ; -	} - -	//unlock updating -	mThumbnailUpdateLock = FALSE ;		 -} - - -// Called often. Checks whether it's time to grab a new snapshot and if so, does it. -// Returns TRUE if new snapshot generated, FALSE otherwise. -//static  -BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) -{ -	LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)snapshot_preview; -	if (previewp->getWidth() == 0 || previewp->getHeight() == 0) -	{ -		llwarns << "Incorrect dimensions: " << previewp->getWidth() << "x" << previewp->getHeight() << llendl; -		return FALSE; -	} - -	// If we're in freeze-frame mode and camera has moved, update snapshot. -	LLVector3 new_camera_pos = LLViewerCamera::getInstance()->getOrigin(); -	LLQuaternion new_camera_rot = LLViewerCamera::getInstance()->getQuaternion(); -	if (gSavedSettings.getBOOL("FreezeTime") &&  -		(new_camera_pos != previewp->mCameraPos || dot(new_camera_rot, previewp->mCameraRot) < 0.995f)) -	{ -		previewp->mCameraPos = new_camera_pos; -		previewp->mCameraRot = new_camera_rot; -		// request a new snapshot whenever the camera moves, with a time delay -		BOOL autosnap = gSavedSettings.getBOOL("AutoSnapshot"); -		lldebugs << "camera moved, updating thumbnail" << llendl; -		previewp->updateSnapshot( -			autosnap, // whether a new snapshot is needed or merely invalidate the existing one -			FALSE, // or if 1st arg is false, whether to produce a new thumbnail image. -			autosnap ? AUTO_SNAPSHOT_TIME_DELAY : 0.f); // shutter delay if 1st arg is true. -	} - -	// see if it's time yet to snap the shot and bomb out otherwise. -	previewp->mSnapshotActive =  -		(previewp->mSnapshotDelayTimer.getStarted() &&	previewp->mSnapshotDelayTimer.hasExpired()) -		&& !LLToolCamera::getInstance()->hasMouseCapture(); // don't take snapshots while ALT-zoom active -	if ( ! previewp->mSnapshotActive) -	{ -		return FALSE; -	} - -	// time to produce a snapshot -	previewp->setThumbnailImageSize(); - -	lldebugs << "producing snapshot" << llendl; -	if (!previewp->mPreviewImage) -	{ -		previewp->mPreviewImage = new LLImageRaw; -	} - -	if (!previewp->mPreviewImageEncoded) -	{ -		previewp->mPreviewImageEncoded = new LLImageRaw; -	} - -	previewp->setVisible(FALSE); -	previewp->setEnabled(FALSE); -	 -	previewp->getWindow()->incBusyCount(); -	previewp->setImageScaled(FALSE); - -	// grab the raw image and encode it into desired format -	if(gViewerWindow->rawSnapshot( -							previewp->mPreviewImage, -							previewp->getWidth(), -							previewp->getHeight(), -							previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"), -							previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_TEXTURE, -							gSavedSettings.getBOOL("RenderUIInSnapshot"), -							FALSE, -							previewp->mSnapshotBufferType, -							previewp->getMaxImageSize())) -	{ -		previewp->mPreviewImageEncoded->resize( -			previewp->mPreviewImage->getWidth(),  -			previewp->mPreviewImage->getHeight(),  -			previewp->mPreviewImage->getComponents()); - -		if(previewp->getSnapshotType() == SNAPSHOT_TEXTURE) -		{ -			lldebugs << "Encoding new image of format J2C" << llendl; -			LLPointer<LLImageJ2C> formatted = new LLImageJ2C; -			LLPointer<LLImageRaw> scaled = new LLImageRaw( -				previewp->mPreviewImage->getData(), -				previewp->mPreviewImage->getWidth(), -				previewp->mPreviewImage->getHeight(), -				previewp->mPreviewImage->getComponents()); -		 -			scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE); -			previewp->setImageScaled(TRUE); -			if (formatted->encode(scaled, 0.f)) -			{ -				previewp->mDataSize = formatted->getDataSize(); -				formatted->decode(previewp->mPreviewImageEncoded, 0); -			} -		} -		else -		{ -			// delete any existing image -			previewp->mFormattedImage = NULL; -			// now create the new one of the appropriate format. -			LLFloaterSnapshot::ESnapshotFormat format = previewp->getSnapshotFormat(); -			lldebugs << "Encoding new image of format " << format << llendl; - -			switch(format) -			{ -			case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG: -				previewp->mFormattedImage = new LLImagePNG();  -				break; -			case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG: -				previewp->mFormattedImage = new LLImageJPEG(previewp->mSnapshotQuality);  -				break; -			case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP: -				previewp->mFormattedImage = new LLImageBMP();  -				break; -			} -			if (previewp->mFormattedImage->encode(previewp->mPreviewImage, 0)) -			{ -				previewp->mDataSize = previewp->mFormattedImage->getDataSize(); -				// special case BMP to copy instead of decode otherwise decode will crash. -				if(format == LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP) -				{ -					previewp->mPreviewImageEncoded->copy(previewp->mPreviewImage); -				} -				else -				{ -					previewp->mFormattedImage->decode(previewp->mPreviewImageEncoded, 0); -				} -			} -		} - -		LLPointer<LLImageRaw> scaled = new LLImageRaw( -			previewp->mPreviewImageEncoded->getData(), -			previewp->mPreviewImageEncoded->getWidth(), -			previewp->mPreviewImageEncoded->getHeight(), -			previewp->mPreviewImageEncoded->getComponents()); -		 -		if(!scaled->isBufferInvalid()) -		{ -			// leave original image dimensions, just scale up texture buffer -			if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024) -			{ -				// go ahead and shrink image to appropriate power of 2 for display -				scaled->biasedScaleToPowerOfTwo(1024); -				previewp->setImageScaled(TRUE); -			} -			else -			{ -				// expand image but keep original image data intact -				scaled->expandToPowerOfTwo(1024, FALSE); -			} - -			previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE); -			LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex]; -			gGL.getTexUnit(0)->bind(curr_preview_image); -			if (previewp->getSnapshotType() != SNAPSHOT_TEXTURE) -			{ -				curr_preview_image->setFilteringOption(LLTexUnit::TFO_POINT); -			} -			else -			{ -				curr_preview_image->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); -			} -			curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP); - -			previewp->mSnapshotUpToDate = TRUE; -			previewp->generateThumbnailImage(TRUE) ; - -			previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal(); -			previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame -		} -	} -	previewp->getWindow()->decBusyCount(); -	// only show fullscreen preview when in freeze frame mode -	previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame")); -	previewp->mSnapshotDelayTimer.stop(); -	previewp->mSnapshotActive = FALSE; - -	if(!previewp->getThumbnailUpToDate()) -	{ -		previewp->generateThumbnailImage() ; -	} -	lldebugs << "done creating snapshot" << llendl; -	LLFloaterSnapshot::postUpdate(); - -	return TRUE; -} - -void LLSnapshotLivePreview::setSize(S32 w, S32 h) -{ -	lldebugs << "setSize(" << w << ", " << h << ")" << llendl; -	setWidth(w); -	setHeight(h); -} - -void LLSnapshotLivePreview::getSize(S32& w, S32& h) const -{ -	w = getWidth(); -	h = getHeight(); -} - -void LLSnapshotLivePreview::saveTexture() -{ -	lldebugs << "saving texture: " << mPreviewImage->getWidth() << "x" << mPreviewImage->getHeight() << llendl; -	// gen a new uuid for this asset -	LLTransactionID tid; -	tid.generate(); -	LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); -		 -	LLPointer<LLImageJ2C> formatted = new LLImageJ2C; -	LLPointer<LLImageRaw> scaled = new LLImageRaw(mPreviewImage->getData(), -												  mPreviewImage->getWidth(), -												  mPreviewImage->getHeight(), -												  mPreviewImage->getComponents()); -	 -	scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE); -	lldebugs << "scaled texture to " << scaled->getWidth() << "x" << scaled->getHeight() << llendl; - -	if (formatted->encode(scaled, 0.0f)) -	{ -		LLVFile::writeFile(formatted->getData(), formatted->getDataSize(), gVFS, new_asset_id, LLAssetType::AT_TEXTURE); -		std::string pos_string; -		LLAgentUI::buildLocationString(pos_string, LLAgentUI::LOCATION_FORMAT_FULL); -		std::string who_took_it; -		LLAgentUI::buildFullname(who_took_it); -		LLAssetStorage::LLStoreAssetCallback callback = NULL; -		S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); -		void *userdata = NULL; -		upload_new_resource(tid,	// tid -				    LLAssetType::AT_TEXTURE, -				    "Snapshot : " + pos_string, -				    "Taken by " + who_took_it + " at " + pos_string, -				    0, -				    LLFolderType::FT_SNAPSHOT_CATEGORY, -				    LLInventoryType::IT_SNAPSHOT, -				    PERM_ALL,  // Note: Snapshots to inventory is a special case of content upload -				    LLFloaterPerms::getGroupPerms(), // that is more permissive than other uploads -				    LLFloaterPerms::getEveryonePerms(), -				    "Snapshot : " + pos_string, -				    callback, expected_upload_cost, userdata); -		gViewerWindow->playSnapshotAnimAndSound(); -	} -	else -	{ -		LLNotificationsUtil::add("ErrorEncodingSnapshot"); -		llwarns << "Error encoding snapshot" << llendl; -	} - -	LLViewerStats::getInstance()->incStat(LLViewerStats::ST_SNAPSHOT_COUNT ); -	 -	mDataSize = 0; -} - -BOOL LLSnapshotLivePreview::saveLocal() -{ -	BOOL success = gViewerWindow->saveImageNumbered(mFormattedImage); - -	if(success) -	{ -		gViewerWindow->playSnapshotAnimAndSound(); -	} -	return success; -} - -void LLSnapshotLivePreview::saveWeb() -{ -	// *FIX: Will break if the window closes because of CloseSnapshotOnKeep! -	// Needs to pass on ownership of the image. -	LLImageJPEG* jpg = dynamic_cast<LLImageJPEG*>(mFormattedImage.get()); -	if(!jpg) -	{ -		llwarns << "Formatted image not a JPEG" << llendl; -		return; -	} - -	LLSD metadata; -	metadata["description"] = getChild<LLLineEditor>("description")->getText(); - -	LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(gAgentCamera.getCameraPositionGlobal(), -		boost::bind(&LLSnapshotLivePreview::regionNameCallback, this, jpg, metadata, _1, _2, _3, _4)); - -	gViewerWindow->playSnapshotAnimAndSound(); -} - -void LLSnapshotLivePreview::regionNameCallback(LLImageJPEG* snapshot, LLSD& metadata, const std::string& name, S32 x, S32 y, S32 z) -{ -	metadata["slurl"] = LLSLURL(name, LLVector3d(x, y, z)).getSLURLString(); - -	LLWebSharing::instance().shareSnapshot(snapshot, metadata); -}  ///----------------------------------------------------------------------------  /// Class LLFloaterSnapshot::Impl @@ -2037,7 +1063,7 @@ BOOL LLFloaterSnapshot::postBuild()  	getChild<LLUICtrl>("auto_snapshot_check")->setValue(gSavedSettings.getBOOL("AutoSnapshot"));  	childSetCommitCallback("auto_snapshot_check", Impl::onClickAutoSnap, this); - +	  	LLWebProfile::setImageUploadResultCallback(boost::bind(&LLFloaterSnapshot::Impl::onSnapshotUploadFinished, _1));  	LLPostCard::setPostResultCallback(boost::bind(&LLFloaterSnapshot::Impl::onSendingPostcardFinished, _1)); @@ -2070,6 +1096,9 @@ BOOL LLFloaterSnapshot::postBuild()  	impl.updateControls(this);  	impl.updateLayout(this); + +	previewp->setThumbnailPlaceholderRect(getThumbnailPlaceholderRect()); +  	return TRUE;  } @@ -2235,7 +1264,9 @@ S32 LLFloaterSnapshot::notify(const LLSD& info)  void LLFloaterSnapshot::update()  {  	LLFloaterSnapshot* inst = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); -	if (!inst) +	LLFloaterSocial* floater_social  = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social");  + +	if (!inst && !floater_social)  		return;  	BOOL changed = FALSE; @@ -2245,7 +1276,8 @@ void LLFloaterSnapshot::update()  	{  		changed |= LLSnapshotLivePreview::onIdle(*iter);  	} -	if(changed) +     +	if (inst && changed)  	{  		lldebugs << "changed" << llendl;  		inst->impl.updateControls(inst); diff --git a/indra/newview/llfloatersnapshot.h b/indra/newview/llfloatersnapshot.h index afe135fa40..82af8c7a9d 100755 --- a/indra/newview/llfloatersnapshot.h +++ b/indra/newview/llfloatersnapshot.h @@ -27,7 +27,6 @@  #ifndef LL_LLFLOATERSNAPSHOT_H  #define LL_LLFLOATERSNAPSHOT_H -#include "llimage.h"  #include "llfloater.h"  class LLSpinCtrl; diff --git a/indra/newview/llfloatersocial.cpp b/indra/newview/llfloatersocial.cpp new file mode 100644 index 0000000000..2a74c8e3ea --- /dev/null +++ b/indra/newview/llfloatersocial.cpp @@ -0,0 +1,920 @@ +/**  +* @file llfloatersocial.cpp +* @brief Implementation of llfloatersocial +* @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 "llfloatersocial.h" + +#include "llagent.h" +#include "llagentui.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llfacebookconnect.h" +#include "llfloaterreg.h" +#include "lliconctrl.h" +#include "llresmgr.h"		// LLLocale +#include "llsdserialize.h" +#include "llloadingindicator.h" +#include "llplugincookiestore.h" +#include "llslurl.h" +#include "lltrans.h" +#include "llsnapshotlivepreview.h" +#include "llviewerregion.h" +#include "llviewercontrol.h" +#include "llviewermedia.h" + +static LLRegisterPanelClassWrapper<LLSocialStatusPanel> t_panel_status("llsocialstatuspanel"); +static LLRegisterPanelClassWrapper<LLSocialPhotoPanel> t_panel_photo("llsocialphotopanel"); +static LLRegisterPanelClassWrapper<LLSocialCheckinPanel> t_panel_checkin("llsocialcheckinpanel"); +static LLRegisterPanelClassWrapper<LLSocialAccountPanel> t_panel_account("llsocialaccountpanel"); + +const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte +const std::string DEFAULT_CHECKIN_LOCATION_URL = "http://maps.secondlife.com/"; +const std::string DEFAULT_CHECKIN_ICON_URL = "http://map.secondlife.com.s3.amazonaws.com/map_placeholder.png"; +const std::string DEFAULT_CHECKIN_QUERY_PARAMETERS = "?sourceid=slshare_checkin&utm_source=facebook&utm_medium=checkin&utm_campaign=slshare"; +const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=facebook&utm_medium=photo&utm_campaign=slshare"; + +std::string get_map_url() +{ +    LLVector3d center_agent; +    if (gAgent.getRegion()) +    { +        center_agent = gAgent.getRegion()->getCenterGlobal(); +    } +    int x_pos = center_agent[0] / 256.0; +    int y_pos = center_agent[1] / 256.0; +    std::string map_url = gSavedSettings.getString("CurrentMapServerURL") + llformat("map-1-%d-%d-objects.jpg", x_pos, y_pos); +    return map_url; +} + +/////////////////////////// +//LLSocialStatusPanel////// +/////////////////////////// + +LLSocialStatusPanel::LLSocialStatusPanel() : +	mMessageTextEditor(NULL), +	mPostButton(NULL), +    mCancelButton(NULL) +{ +	mCommitCallbackRegistrar.add("SocialSharing.SendStatus", boost::bind(&LLSocialStatusPanel::onSend, this)); +} + +BOOL LLSocialStatusPanel::postBuild() +{ +	mMessageTextEditor = getChild<LLUICtrl>("status_message"); +	mPostButton = getChild<LLUICtrl>("post_status_btn"); +	mCancelButton = getChild<LLUICtrl>("cancel_status_btn"); + +	return LLPanel::postBuild(); +} + +void LLSocialStatusPanel::draw() +{ +    if (mMessageTextEditor && mPostButton && mCancelButton) +	{ +        bool no_ongoing_connection = !(LLFacebookConnect::instance().isTransactionOngoing()); +        std::string message = mMessageTextEditor->getValue().asString(); +        mMessageTextEditor->setEnabled(no_ongoing_connection); +        mCancelButton->setEnabled(no_ongoing_connection); +        mPostButton->setEnabled(no_ongoing_connection && !message.empty()); +    } + +	LLPanel::draw(); +} + +void LLSocialStatusPanel::onSend() +{ +	LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialStatusPanel"); // just in case it is already listening +	LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialStatusPanel", boost::bind(&LLSocialStatusPanel::onFacebookConnectStateChange, this, _1)); +		 +	// Connect to Facebook if necessary and then post +	if (LLFacebookConnect::instance().isConnected()) +	{ +		sendStatus(); +	} +	else +	{ +		LLFacebookConnect::instance().checkConnectionToFacebook(true); +	} +} + +bool LLSocialStatusPanel::onFacebookConnectStateChange(const LLSD& data) +{ +	switch (data.get("enum").asInteger()) +	{ +		case LLFacebookConnect::FB_CONNECTED: +			sendStatus(); +			break; + +		case LLFacebookConnect::FB_POSTED: +			LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialStatusPanel"); +			clearAndClose(); +			break; +	} + +	return false; +} + +void LLSocialStatusPanel::sendStatus() +{ +	std::string message = mMessageTextEditor->getValue().asString(); +	if (!message.empty()) +	{ +		LLFacebookConnect::instance().updateStatus(message); +	} +} + +void LLSocialStatusPanel::clearAndClose() +{ +	mMessageTextEditor->setValue(""); + +	LLFloater* floater = getParentByType<LLFloater>(); +	if (floater) +	{ +		floater->closeFloater(); +	} +} + +/////////////////////////// +//LLSocialPhotoPanel/////// +/////////////////////////// + +LLSocialPhotoPanel::LLSocialPhotoPanel() : +mSnapshotPanel(NULL), +mResolutionComboBox(NULL), +mRefreshBtn(NULL), +mWorkingLabel(NULL), +mThumbnailPlaceholder(NULL), +mCaptionTextBox(NULL), +mLocationCheckbox(NULL), +mPostButton(NULL) +{ +	mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLSocialPhotoPanel::onSend, this)); +	mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLSocialPhotoPanel::onClickNewSnapshot, this)); +} + +LLSocialPhotoPanel::~LLSocialPhotoPanel() +{ +	if(mPreviewHandle.get()) +	{ +		mPreviewHandle.get()->die(); +	} +} + +BOOL LLSocialPhotoPanel::postBuild() +{ +	setVisibleCallback(boost::bind(&LLSocialPhotoPanel::onVisibilityChange, this, _2)); +	 +	mSnapshotPanel = getChild<LLUICtrl>("snapshot_panel"); +	mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox"); +	mResolutionComboBox->setCommitCallback(boost::bind(&LLSocialPhotoPanel::updateResolution, this, TRUE)); +	mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn"); +    mWorkingLabel = getChild<LLUICtrl>("working_lbl"); +	mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder"); +	mCaptionTextBox = getChild<LLUICtrl>("photo_caption"); +	mLocationCheckbox = getChild<LLUICtrl>("add_location_cb"); +	mPostButton = getChild<LLUICtrl>("post_photo_btn"); +	mCancelButton = getChild<LLUICtrl>("cancel_photo_btn"); + +	return LLPanel::postBuild(); +} + +void LLSocialPhotoPanel::draw() +{  +	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get()); + +    // Enable interaction only if no transaction with the service is on-going (prevent duplicated posts) +    bool no_ongoing_connection = !(LLFacebookConnect::instance().isTransactionOngoing()); +    mCancelButton->setEnabled(no_ongoing_connection); +    mCaptionTextBox->setEnabled(no_ongoing_connection); +    mResolutionComboBox->setEnabled(no_ongoing_connection); +    mRefreshBtn->setEnabled(no_ongoing_connection); +    mLocationCheckbox->setEnabled(no_ongoing_connection); +     +    // Display the preview if one is available +	if (previewp && previewp->getThumbnailImage()) +	{ +		const LLRect& thumbnail_rect = mThumbnailPlaceholder->getRect(); +		const S32 thumbnail_w = previewp->getThumbnailWidth(); +		const S32 thumbnail_h = previewp->getThumbnailHeight(); + +		// calc preview offset within the preview rect +		const S32 local_offset_x = (thumbnail_rect.getWidth()  - thumbnail_w) / 2 ; +		const S32 local_offset_y = (thumbnail_rect.getHeight() - thumbnail_h) / 2 ; + +		// calc preview offset within the floater rect +        // Hack : To get the full offset, we need to take into account each and every offset of each widgets up to the floater. +        // This is almost as arbitrary as using a fixed offset so that's what we do here for the sake of simplicity. +        // *TODO : Get the offset looking through the hierarchy of widgets, should be done in postBuild() so to avoid traversing the hierarchy each time. +		S32 offset_x = thumbnail_rect.mLeft + local_offset_x - 1; +		S32 offset_y = thumbnail_rect.mBottom + local_offset_y - 39; +         +		mSnapshotPanel->localPointToOtherView(offset_x, offset_y, &offset_x, &offset_y, getParentByType<LLFloater>()); +         +		gGL.matrixMode(LLRender::MM_MODELVIEW); +		// Apply floater transparency to the texture unless the floater is focused. +		F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency(); +		LLColor4 color = LLColor4::white; +		gl_draw_scaled_image(offset_x, offset_y,  +			thumbnail_w, thumbnail_h, +			previewp->getThumbnailImage(), color % alpha); + +		previewp->drawPreviewRect(offset_x, offset_y) ; +	} + +    // Update the visibility of the working (computing preview) label +    mWorkingLabel->setVisible(!(previewp && previewp->getSnapshotUpToDate())); +     +    // Enable Post if we have a preview to send and no on going connection being processed +    mPostButton->setEnabled(no_ongoing_connection && (previewp && previewp->getSnapshotUpToDate())); +     +    // Draw the rest of the panel on top of it +	LLPanel::draw(); +} + +LLSnapshotLivePreview* LLSocialPhotoPanel::getPreviewView() +{ +	LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get(); +	return previewp; +} + +void LLSocialPhotoPanel::onVisibilityChange(const LLSD& new_visibility) +{ +	bool visible = new_visibility.asBoolean(); +	if (visible) +	{ +		if (mPreviewHandle.get()) +		{ +			LLSnapshotLivePreview* preview = getPreviewView(); +			if(preview) +			{ +				lldebugs << "opened, updating snapshot" << llendl; +				preview->updateSnapshot(TRUE); +			} +		} +		else +		{ +			LLRect full_screen_rect = getRootView()->getRect(); +			LLSnapshotLivePreview::Params p; +			p.rect(full_screen_rect); +			LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p); +			mPreviewHandle = previewp->getHandle();	 + +			previewp->setSnapshotType(previewp->SNAPSHOT_WEB); +			previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG); +			//previewp->setSnapshotQuality(98); +			previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect()); + +			updateControls(); +		} +	} +} + +void LLSocialPhotoPanel::onClickNewSnapshot() +{ +	LLSnapshotLivePreview* previewp = getPreviewView(); +	if (previewp) +	{ +		//setStatus(Impl::STATUS_READY); +		lldebugs << "updating snapshot" << llendl; +		previewp->updateSnapshot(TRUE); +	} +} + +void LLSocialPhotoPanel::onSend() +{ +	LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialPhotoPanel"); // just in case it is already listening +	LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialPhotoPanel", boost::bind(&LLSocialPhotoPanel::onFacebookConnectStateChange, this, _1)); +	 +	// Connect to Facebook if necessary and then post +	if (LLFacebookConnect::instance().isConnected()) +	{ +		sendPhoto(); +	} +	else +	{ +		LLFacebookConnect::instance().checkConnectionToFacebook(true); +	} +} + +bool LLSocialPhotoPanel::onFacebookConnectStateChange(const LLSD& data) +{ +	switch (data.get("enum").asInteger()) +	{ +		case LLFacebookConnect::FB_CONNECTED: +			sendPhoto(); +			break; + +		case LLFacebookConnect::FB_POSTED: +			LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialPhotoPanel"); +			clearAndClose(); +			break; +	} + +	return false; +} + +void LLSocialPhotoPanel::sendPhoto() +{ +	// Get the caption +	std::string caption = mCaptionTextBox->getValue().asString(); + +	// Add the location if required +	bool add_location = mLocationCheckbox->getValue().asBoolean(); +	if (add_location) +	{ +		// Get the SLURL for the location +		LLSLURL slurl; +		LLAgentUI::buildSLURL(slurl); +		std::string slurl_string = slurl.getSLURLString(); + +		// Add query parameters so Google Analytics can track incoming clicks! +		slurl_string += DEFAULT_PHOTO_QUERY_PARAMETERS; + +		// Add it to the caption (pretty crude, but we don't have a better option with photos) +		if (caption.empty()) +			caption = slurl_string; +		else +			caption = caption + " " + slurl_string; +	} + +	// Get the image +	LLSnapshotLivePreview* previewp = getPreviewView(); +	 +	// Post to Facebook +	LLFacebookConnect::instance().sharePhoto(previewp->getFormattedImage(), caption); + +	updateControls(); +} + +void LLSocialPhotoPanel::clearAndClose() +{ +	mCaptionTextBox->setValue(""); + +	LLFloater* floater = getParentByType<LLFloater>(); +	if (floater) +	{ +		floater->closeFloater(); +	} +} + +void LLSocialPhotoPanel::updateControls() +{ +	LLSnapshotLivePreview* previewp = getPreviewView(); +	BOOL got_bytes = previewp && previewp->getDataSize() > 0; +	BOOL got_snap = previewp && previewp->getSnapshotUpToDate(); +	LLSnapshotLivePreview::ESnapshotType shot_type = (previewp ? previewp->getSnapshotType() : LLSnapshotLivePreview::SNAPSHOT_POSTCARD); + +	// *TODO: Separate maximum size for Web images from postcards +	lldebugs << "Is snapshot up-to-date? " << got_snap << llendl; + +	LLLocale locale(LLLocale::USER_LOCALE); +	std::string bytes_string; +	if (got_snap) +	{ +		LLResMgr::getInstance()->getIntegerString(bytes_string, (previewp->getDataSize()) >> 10 ); +	} + +	//getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : getString("unknown")); <---uses localized string +	getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : "unknown"); +	getChild<LLUICtrl>("file_size_label")->setColor( +		shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD  +		&& got_bytes +		&& previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLUIColor(LLColor4::red) : LLUIColorTable::instance().getColor( "LabelTextColor" )); + +	updateResolution(FALSE); +} + +void LLSocialPhotoPanel::updateResolution(BOOL do_update) +{ +	LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox); + +	std::string sdstring = combobox->getSelectedValue(); +	LLSD sdres; +	std::stringstream sstream(sdstring); +	LLSDSerialize::fromNotation(sdres, sstream, sdstring.size()); + +	S32 width = sdres[0]; +	S32 height = sdres[1]; + +	LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get()); +	if (previewp && combobox->getCurrentIndex() >= 0) +	{ +		S32 original_width = 0 , original_height = 0 ; +		previewp->getSize(original_width, original_height) ; + +		if (width == 0 || height == 0) +		{ +			// take resolution from current window size +			lldebugs << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << llendl; +			previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); +		} +		else +		{ +			// use the resolution from the selected pre-canned drop-down choice +			lldebugs << "Setting preview res selected from combo: " << width << "x" << height << llendl; +			previewp->setSize(width, height); +		} + +		checkAspectRatio(width); + +		previewp->getSize(width, height); +		 +		if(original_width != width || original_height != height) +		{ +			previewp->setSize(width, height); + +			// hide old preview as the aspect ratio could be wrong +			lldebugs << "updating thumbnail" << llendl; +			 +			previewp->updateSnapshot(FALSE, TRUE); +			if(do_update) +			{ +				lldebugs << "Will update controls" << llendl; +				updateControls(); +                LLSocialPhotoPanel::onClickNewSnapshot(); +			} +		} +		 +	} +} + +void LLSocialPhotoPanel::checkAspectRatio(S32 index) +{ +	LLSnapshotLivePreview *previewp = getPreviewView() ; + +	BOOL keep_aspect = FALSE; + +	if (0 == index) // current window size +	{ +		keep_aspect = TRUE; +	} +	else // predefined resolution +	{ +		keep_aspect = FALSE; +	} + +	if (previewp) +	{ +		previewp->mKeepAspectRatio = keep_aspect; +	} +} + +LLUICtrl* LLSocialPhotoPanel::getRefreshBtn() +{ +	return mRefreshBtn; +} + +//////////////////////// +//LLSocialCheckinPanel// +//////////////////////// + +LLSocialCheckinPanel::LLSocialCheckinPanel() : +    mMapUrl(""), +    mReloadingMapTexture(false) +{ +	mCommitCallbackRegistrar.add("SocialSharing.SendCheckin", boost::bind(&LLSocialCheckinPanel::onSend, this)); +} + +BOOL LLSocialCheckinPanel::postBuild() +{ +    // Keep pointers to widgets so we don't traverse the UI hierarchy too often +	mPostButton = getChild<LLUICtrl>("post_place_btn"); +	mCancelButton = getChild<LLUICtrl>("cancel_place_btn"); +	mMessageTextEditor = getChild<LLUICtrl>("place_caption"); +    mMapLoadingIndicator = getChild<LLUICtrl>("map_loading_indicator"); +    mMapPlaceholder = getChild<LLIconCtrl>("map_placeholder"); +    mMapDefault = getChild<LLIconCtrl>("map_default"); +    mMapCheckBox = getChild<LLCheckBoxCtrl>("add_place_view_cb"); +     +	return LLPanel::postBuild(); +} + +void LLSocialCheckinPanel::draw() +{ +    bool no_ongoing_connection = !(LLFacebookConnect::instance().isTransactionOngoing()); +    mPostButton->setEnabled(no_ongoing_connection); +    mCancelButton->setEnabled(no_ongoing_connection); +    mMessageTextEditor->setEnabled(no_ongoing_connection); +    mMapCheckBox->setEnabled(no_ongoing_connection); + +    std::string map_url = get_map_url(); +    // Did we change location? +    if (map_url != mMapUrl) +    { +        mMapUrl = map_url; +        // Load the map tile +        mMapTexture = LLViewerTextureManager::getFetchedTextureFromUrl(mMapUrl, FTT_MAP_TILE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); +        mMapTexture->setBoostLevel(LLGLTexture::BOOST_MAP); +        mReloadingMapTexture = true; +        // In the meantime, put the "loading" indicator on, hide the tile map and disable the checkbox +        mMapLoadingIndicator->setVisible(true); +        mMapPlaceholder->setVisible(false); +    } +    // Are we done loading the map tile? +    if (mReloadingMapTexture && mMapTexture->isFullyLoaded()) +    { +        // Don't do it again next time around +        mReloadingMapTexture = false; +        // Convert the map texture to the appropriate image object +        LLPointer<LLUIImage> ui_image = new LLUIImage(mMapUrl, mMapTexture); +        // Load the map widget with the correct map tile image +        mMapPlaceholder->setImage(ui_image); +        // Now hide the loading indicator, bring the tile in view and reenable the checkbox with its previous value +        mMapLoadingIndicator->setVisible(false); +        mMapPlaceholder->setVisible(true); +    } +    // Show the default icon if that's the checkbox value (the real one...) +    // This will hide/show the loading indicator and/or tile underneath +    mMapDefault->setVisible(!(mMapCheckBox->get())); + +	LLPanel::draw(); +} + +void LLSocialCheckinPanel::onSend() +{ +	LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialCheckinPanel"); // just in case it is already listening +	LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialCheckinPanel", boost::bind(&LLSocialCheckinPanel::onFacebookConnectStateChange, this, _1)); +	 +	// Connect to Facebook if necessary and then post +	if (LLFacebookConnect::instance().isConnected()) +	{ +		sendCheckin(); +	} +	else +	{ +		LLFacebookConnect::instance().checkConnectionToFacebook(true); +	} +} + +bool LLSocialCheckinPanel::onFacebookConnectStateChange(const LLSD& data) +{ +	switch (data.get("enum").asInteger()) +	{ +		case LLFacebookConnect::FB_CONNECTED: +			sendCheckin(); +			break; + +		case LLFacebookConnect::FB_POSTED: +			LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialCheckinPanel"); +			clearAndClose(); +			break; +	} + +	return false; +} + +void LLSocialCheckinPanel::sendCheckin() +{ +	// Get the location SLURL +	LLSLURL slurl; +	LLAgentUI::buildSLURL(slurl); +	std::string slurl_string = slurl.getSLURLString(); + +	// Use a valid http:// URL if the scheme is secondlife://  +	LLURI slurl_uri(slurl_string); +	if (slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME) +	{ +		slurl_string = DEFAULT_CHECKIN_LOCATION_URL; +	} + +	// Add query parameters so Google Analytics can track incoming clicks! +	slurl_string += DEFAULT_CHECKIN_QUERY_PARAMETERS; +     +	// Get the region name +	std::string region_name = gAgent.getRegion()->getName(); +     +	// Get the region description +	std::string description; +	LLAgentUI::buildLocationString(description, LLAgentUI::LOCATION_FORMAT_NORMAL_COORDS, gAgent.getPositionAgent()); +     +	// Optionally add the region map view +	bool add_map_view = mMapCheckBox->getValue().asBoolean(); +    std::string map_url = (add_map_view ? get_map_url() : DEFAULT_CHECKIN_ICON_URL); +     +	// Get the caption +	std::string caption = mMessageTextEditor->getValue().asString(); + +	// Post to Facebook +	LLFacebookConnect::instance().postCheckin(slurl_string, region_name, description, map_url, caption); +} + +void LLSocialCheckinPanel::clearAndClose() +{ +	mMessageTextEditor->setValue(""); + +	LLFloater* floater = getParentByType<LLFloater>(); +	if (floater) +	{ +		floater->closeFloater(); +	} +} + +/////////////////////////// +//LLSocialAccountPanel////// +/////////////////////////// + +LLSocialAccountPanel::LLSocialAccountPanel() :  +mAccountCaptionLabel(NULL), +mAccountNameLabel(NULL), +mPanelButtons(NULL), +mConnectButton(NULL), +mDisconnectButton(NULL) +{ +	mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLSocialAccountPanel::onConnect, this)); +	mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLSocialAccountPanel::onDisconnect, this)); + +	setVisibleCallback(boost::bind(&LLSocialAccountPanel::onVisibilityChange, this, _2)); +} + +BOOL LLSocialAccountPanel::postBuild() +{ +	mAccountCaptionLabel = getChild<LLTextBox>("account_caption_label"); +	mAccountNameLabel = getChild<LLTextBox>("account_name_label"); +	mPanelButtons = getChild<LLUICtrl>("panel_buttons"); +	mConnectButton = getChild<LLUICtrl>("connect_btn"); +	mDisconnectButton = getChild<LLUICtrl>("disconnect_btn"); + +	return LLPanel::postBuild(); +} + +void LLSocialAccountPanel::draw() +{ +	LLFacebookConnect::EConnectionState connection_state = LLFacebookConnect::instance().getConnectionState(); + +	//Disable the 'disconnect' button and the 'use another account' button when disconnecting in progress +	bool disconnecting = connection_state == LLFacebookConnect::FB_DISCONNECTING; +	mDisconnectButton->setEnabled(!disconnecting); + +	//Disable the 'connect' button when a connection is in progress +	bool connecting = connection_state == LLFacebookConnect::FB_CONNECTION_IN_PROGRESS; +	mConnectButton->setEnabled(!connecting); + +	LLPanel::draw(); +} + +void LLSocialAccountPanel::onVisibilityChange(const LLSD& new_visibility) +{ +	bool visible = new_visibility.asBoolean(); + +	if(visible) +	{ +		LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialAccountPanel"); +		LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialAccountPanel", boost::bind(&LLSocialAccountPanel::onFacebookConnectStateChange, this, _1)); + +		LLEventPumps::instance().obtain("FacebookConnectInfo").stopListening("LLSocialAccountPanel"); +		LLEventPumps::instance().obtain("FacebookConnectInfo").listen("LLSocialAccountPanel", boost::bind(&LLSocialAccountPanel::onFacebookConnectInfoChange, this)); + +		//Connected +		if(LLFacebookConnect::instance().isConnected()) +		{ +			showConnectedLayout(); +		} +		//Check if connected (show disconnected layout in meantime) +		else +		{ +			showDisconnectedLayout(); +		} +        if ((LLFacebookConnect::instance().getConnectionState() == LLFacebookConnect::FB_NOT_CONNECTED) || +            (LLFacebookConnect::instance().getConnectionState() == LLFacebookConnect::FB_CONNECTION_FAILED)) +        { +            LLFacebookConnect::instance().checkConnectionToFacebook(); +        } +	} +	else +	{ +		LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialAccountPanel"); +		LLEventPumps::instance().obtain("FacebookConnectInfo").stopListening("LLSocialAccountPanel"); +	} +} + +bool LLSocialAccountPanel::onFacebookConnectStateChange(const LLSD& data) +{ +	if(LLFacebookConnect::instance().isConnected()) +	{ +		//In process of disconnecting so leave the layout as is +		if(data.get("enum").asInteger() != LLFacebookConnect::FB_DISCONNECTING) +		{ +			showConnectedLayout(); +		} +	} +	else +	{ +		showDisconnectedLayout(); +	} + +	return false; +} + +bool LLSocialAccountPanel::onFacebookConnectInfoChange() +{ +	LLSD info = LLFacebookConnect::instance().getInfo(); +	std::string clickable_name; + +	//Strings of format [http://www.somewebsite.com Click Me] become clickable text +	if(info.has("link") && info.has("name")) +	{ +		clickable_name = "[" + info["link"].asString() + " " + info["name"].asString() + "]"; +	} + +	mAccountNameLabel->setText(clickable_name); + +	return false; +} + +void LLSocialAccountPanel::showConnectButton() +{ +	if(!mConnectButton->getVisible()) +	{ +		mConnectButton->setVisible(TRUE); +		mDisconnectButton->setVisible(FALSE); +	} +} + +void LLSocialAccountPanel::hideConnectButton() +{ +	if(mConnectButton->getVisible()) +	{ +		mConnectButton->setVisible(FALSE); +		mDisconnectButton->setVisible(TRUE); +	} +} + +void LLSocialAccountPanel::showDisconnectedLayout() +{ +	mAccountCaptionLabel->setText(getString("facebook_disconnected")); +	mAccountNameLabel->setText(std::string("")); +	showConnectButton(); +} + +void LLSocialAccountPanel::showConnectedLayout() +{ +	LLFacebookConnect::instance().loadFacebookInfo(); + +	mAccountCaptionLabel->setText(getString("facebook_connected")); +	hideConnectButton(); +} + +void LLSocialAccountPanel::onConnect() +{ +	LLFacebookConnect::instance().checkConnectionToFacebook(true); + +	//Clear only the facebook browser cookies so that the facebook login screen appears +	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".facebook.com");  +} + +void LLSocialAccountPanel::onDisconnect() +{ +	LLFacebookConnect::instance().disconnectFromFacebook(); + +	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".facebook.com");  +} + +//////////////////////// +//LLFloaterSocial/////// +//////////////////////// + +LLFloaterSocial::LLFloaterSocial(const LLSD& key) : LLFloater(key), +    mSocialPhotoPanel(NULL), +    mStatusErrorText(NULL), +    mStatusLoadingText(NULL), +    mStatusLoadingIndicator(NULL) +{ +	mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterSocial::onCancel, this)); +} + +void LLFloaterSocial::onCancel() +{ +    closeFloater(); +} + +BOOL LLFloaterSocial::postBuild() +{ +    // Keep tab of the Photo Panel +	mSocialPhotoPanel = static_cast<LLSocialPhotoPanel*>(getChild<LLUICtrl>("panel_social_photo")); +    // Connection status widgets +    mStatusErrorText = getChild<LLTextBox>("connection_error_text"); +    mStatusLoadingText = getChild<LLTextBox>("connection_loading_text"); +    mStatusLoadingIndicator = getChild<LLUICtrl>("connection_loading_indicator"); +	return LLFloater::postBuild(); +} + +// static +void LLFloaterSocial::preUpdate() +{ +	LLFloaterSocial* instance = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social"); +	if (instance) +	{ +		//Will set file size text to 'unknown' +		instance->mSocialPhotoPanel->updateControls(); +	} +} + +// static +void LLFloaterSocial::postUpdate() +{ +	LLFloaterSocial* instance = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social"); +	if (instance) +	{ +		//Will set the file size text +		instance->mSocialPhotoPanel->updateControls(); + +		// The refresh button is initially hidden. We show it after the first update, +		// i.e. after snapshot is taken +		LLUICtrl * refresh_button = instance->mSocialPhotoPanel->getRefreshBtn(); + +		if (!refresh_button->getVisible()) +		{ +			refresh_button->setVisible(true); +		} +		 +	} +} + +void LLFloaterSocial::draw() +{ +    if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator) +    { +        mStatusErrorText->setVisible(false); +        mStatusLoadingText->setVisible(false); +        mStatusLoadingIndicator->setVisible(false); +        LLFacebookConnect::EConnectionState connection_state = LLFacebookConnect::instance().getConnectionState(); +        std::string status_text; +         +        switch (connection_state) +        { +        case LLFacebookConnect::FB_NOT_CONNECTED: +            // No status displayed when first opening the panel and no connection done +        case LLFacebookConnect::FB_CONNECTED: +            // When successfully connected, no message is displayed +        case LLFacebookConnect::FB_POSTED: +            // No success message to show since we actually close the floater after successful posting completion +            break; +        case LLFacebookConnect::FB_CONNECTION_IN_PROGRESS: +            // Connection loading indicator +            mStatusLoadingText->setVisible(true); +            status_text = LLTrans::getString("SocialFacebookConnecting"); +            mStatusLoadingText->setValue(status_text); +            mStatusLoadingIndicator->setVisible(true); +            break; +        case LLFacebookConnect::FB_POSTING: +            // Posting indicator +            mStatusLoadingText->setVisible(true); +            status_text = LLTrans::getString("SocialFacebookPosting"); +            mStatusLoadingText->setValue(status_text); +            mStatusLoadingIndicator->setVisible(true); +			break; +        case LLFacebookConnect::FB_CONNECTION_FAILED: +            // Error connecting to the service +            mStatusErrorText->setVisible(true); +            status_text = LLTrans::getString("SocialFacebookErrorConnecting"); +            mStatusErrorText->setValue(status_text); +            break; +        case LLFacebookConnect::FB_POST_FAILED: +            // Error posting to the service +            mStatusErrorText->setVisible(true); +            status_text = LLTrans::getString("SocialFacebookErrorPosting"); +            mStatusErrorText->setValue(status_text); +            break; +		case LLFacebookConnect::FB_DISCONNECTING: +			// Disconnecting loading indicator +			mStatusLoadingText->setVisible(true); +			status_text = LLTrans::getString("SocialFacebookDisconnecting"); +			mStatusLoadingText->setValue(status_text); +			mStatusLoadingIndicator->setVisible(true); +			break; +		case LLFacebookConnect::FB_DISCONNECT_FAILED: +			// Error disconnecting from the service +			mStatusErrorText->setVisible(true); +			status_text = LLTrans::getString("SocialFacebookErrorDisconnecting"); +			mStatusErrorText->setValue(status_text); +			break; +        } +    } +	LLFloater::draw(); +} + diff --git a/indra/newview/llfloatersocial.h b/indra/newview/llfloatersocial.h new file mode 100644 index 0000000000..bbe07c9704 --- /dev/null +++ b/indra/newview/llfloatersocial.h @@ -0,0 +1,165 @@ +/**  +* @file   llfloatersocial.h +* @brief  Header file for llfloatersocial +* @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_LLFLOATERSOCIAL_H +#define LL_LLFLOATERSOCIAL_H + +#include "llfloater.h" +#include "lltextbox.h" +#include "llviewertexture.h" + +class LLIconCtrl; +class LLCheckBoxCtrl; +class LLSnapshotLivePreview; + +class LLSocialStatusPanel : public LLPanel +{ +public: +    LLSocialStatusPanel(); +	BOOL postBuild(); +	void draw(); +    void onSend(); +	bool onFacebookConnectStateChange(const LLSD& data); + +	void sendStatus(); +	void clearAndClose(); + +private: +	LLUICtrl* mMessageTextEditor; +	LLUICtrl* mPostButton; +	LLUICtrl* mCancelButton; +}; + +class LLSocialPhotoPanel : public LLPanel +{ +public: +	LLSocialPhotoPanel(); +	~LLSocialPhotoPanel(); + +	BOOL postBuild(); +	void draw(); + +	LLSnapshotLivePreview* getPreviewView(); +	void onVisibilityChange(const LLSD& new_visibility); +	void onClickNewSnapshot(); +	void onSend(); +	bool onFacebookConnectStateChange(const LLSD& data); + +	void sendPhoto(); +	void clearAndClose(); + +	void updateControls(); +	void updateResolution(BOOL do_update); +	void checkAspectRatio(S32 index); +	LLUICtrl* getRefreshBtn(); + +private: +	LLHandle<LLView> mPreviewHandle; + +	LLUICtrl * mSnapshotPanel; +	LLUICtrl * mResolutionComboBox; +	LLUICtrl * mRefreshBtn; +	LLUICtrl * mWorkingLabel; +	LLUICtrl * mThumbnailPlaceholder; +	LLUICtrl * mCaptionTextBox; +	LLUICtrl * mLocationCheckbox; +	LLUICtrl * mPostButton; +	LLUICtrl* mCancelButton; +}; + +class LLSocialCheckinPanel : public LLPanel +{ +public: +    LLSocialCheckinPanel(); +	BOOL postBuild(); +	void draw(); +    void onSend(); +	bool onFacebookConnectStateChange(const LLSD& data); + +	void sendCheckin(); +	void clearAndClose(); + +private: +    std::string mMapUrl; +    LLPointer<LLViewerFetchedTexture> mMapTexture; +	LLUICtrl* mPostButton; +	LLUICtrl* mCancelButton; +	LLUICtrl* mMessageTextEditor; +    LLUICtrl* mMapLoadingIndicator; +    LLIconCtrl* mMapPlaceholder; +    LLIconCtrl* mMapDefault; +    LLCheckBoxCtrl* mMapCheckBox; +    bool mReloadingMapTexture; +}; + +class LLSocialAccountPanel : public LLPanel +{ +public: +	LLSocialAccountPanel(); +	BOOL postBuild(); +	void draw(); + +private: +	void onVisibilityChange(const LLSD& new_visibility); +	bool onFacebookConnectStateChange(const LLSD& data); +	bool onFacebookConnectInfoChange(); +	void onConnect(); +	void onUseAnotherAccount(); +	void onDisconnect(); + +	void showConnectButton(); +	void hideConnectButton(); +	void showDisconnectedLayout(); +	void showConnectedLayout(); + +	LLTextBox * mAccountCaptionLabel; +	LLTextBox * mAccountNameLabel; +	LLUICtrl * mPanelButtons; +	LLUICtrl * mConnectButton; +	LLUICtrl * mDisconnectButton; +}; + + +class LLFloaterSocial : public LLFloater +{ +public: +	LLFloaterSocial(const LLSD& key); +	BOOL postBuild(); +	void draw(); +	void onCancel(); + +	static void preUpdate(); +	static void postUpdate(); + +private: +	LLSocialPhotoPanel* mSocialPhotoPanel; +    LLTextBox* mStatusErrorText; +    LLTextBox* mStatusLoadingText; +    LLUICtrl*  mStatusLoadingIndicator; +}; + +#endif // LL_LLFLOATERSOCIAL_H + diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index 3fe2518de6..9d703d2752 100755 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -29,6 +29,7 @@  #include "llcombobox.h"  #include "lliconctrl.h"  #include "llfloaterreg.h" +#include "llfacebookconnect.h"  #include "lllayoutstack.h"  #include "llpluginclassmedia.h"  #include "llprogressbar.h" @@ -46,7 +47,8 @@ LLFloaterWebContent::_Params::_Params()  	id("id"),  	window_class("window_class", "web_content"),  	show_chrome("show_chrome", true), -	allow_address_entry("allow_address_entry", true), +    allow_address_entry("allow_address_entry", true), +    allow_back_forward_navigation("allow_back_forward_navigation", true),  	preferred_media_size("preferred_media_size"),  	trusted_content("trusted_content", false),  	show_page_title("show_page_title", true) @@ -65,7 +67,11 @@ LLFloaterWebContent::LLFloaterWebContent( const Params& params )  	mBtnReload(NULL),  	mBtnStop(NULL),  	mUUID(params.id()), -	mShowPageTitle(params.show_page_title) +	mShowPageTitle(params.show_page_title), +    mAllowNavigation(true), +    mCurrentURL(""), +    mDisplayURL(""), +    mSecureURL(false)  {  	mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this ));  	mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this )); @@ -97,7 +103,7 @@ BOOL LLFloaterWebContent::postBuild()  	// cache image for secure browsing  	mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag"); - +      	// initialize the URL history using the system URL History manager  	initializeURLHistory(); @@ -243,6 +249,7 @@ void LLFloaterWebContent::open_media(const Params& p)  	getChild<LLLayoutPanel>("status_bar")->setVisible(p.show_chrome);  	getChild<LLLayoutPanel>("nav_controls")->setVisible(p.show_chrome);  	bool address_entry_enabled = p.allow_address_entry && !p.trusted_content; +    mAllowNavigation = p.allow_back_forward_navigation;  	getChildView("address")->setEnabled(address_entry_enabled);  	getChildView("popexternal")->setEnabled(address_entry_enabled); @@ -287,6 +294,16 @@ void LLFloaterWebContent::onOpen(const LLSD& key)  //virtual  void LLFloaterWebContent::onClose(bool app_quitting)  { +    // If we close the web browsing window showing the facebook login, we need to signal to this object that the connection will not happen +    LLFloater* fbc_web = LLFloaterReg::getInstance("fbc_web"); +    if (fbc_web == this) +    { +        if (!LLFacebookConnect::instance().isConnected()) +        { +            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); +        } +    } +      	LLViewerMedia::proxyWindowClosed(mUUID);  	destroy();  } @@ -295,8 +312,11 @@ void LLFloaterWebContent::onClose(bool app_quitting)  void LLFloaterWebContent::draw()  {  	// this is asynchronous so we need to keep checking -	mBtnBack->setEnabled( mWebBrowser->canNavigateBack() ); -	mBtnForward->setEnabled( mWebBrowser->canNavigateForward() ); +	mBtnBack->setEnabled( mWebBrowser->canNavigateBack() && mAllowNavigation); +	mBtnForward->setEnabled( mWebBrowser->canNavigateForward() && mAllowNavigation); + +    // Show/hide the lock icon +    mSecureLockIcon->setVisible(mSecureURL && !mAddressCombo->hasFocus());  	LLFloater::draw();  } @@ -342,19 +362,6 @@ void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent  		// we populate the status bar with URLs as they change so clear it now we're done  		const std::string end_str = "";  		mStatusBarText->setText( end_str ); - -		// decide if secure browsing icon should be displayed -		std::string prefix =  std::string("https://"); -		std::string test_prefix = mCurrentURL.substr(0, prefix.length()); -		LLStringUtil::toLower(test_prefix); -		if(test_prefix == prefix) -		{ -			mSecureLockIcon->setVisible(true); -		} -		else -		{ -			mSecureLockIcon->setVisible(false); -		}  	}  	else if(event == MEDIA_EVENT_CLOSE_REQUEST)  	{ @@ -397,15 +404,40 @@ void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent  void LLFloaterWebContent::set_current_url(const std::string& url)  { -	mCurrentURL = url; - -	// serialize url history into the system URL History manager -	LLURLHistory::removeURL("browser", mCurrentURL); -	LLURLHistory::addURL("browser", mCurrentURL); - -	mAddressCombo->remove( mCurrentURL ); -	mAddressCombo->add( mCurrentURL ); -	mAddressCombo->selectByValue( mCurrentURL ); +    if (!url.empty()) +    { +        if (!mCurrentURL.empty()) +        { +            // Clean up the current browsing list to show true URL +            mAddressCombo->remove(mDisplayURL); +            mAddressCombo->add(mCurrentURL); +        } + +        // Update current URL +        mCurrentURL = url; +        LLStringUtil::trim(mCurrentURL); + +        // Serialize url history into the system URL History manager +        LLURLHistory::removeURL("browser", mCurrentURL); +        LLURLHistory::addURL("browser", mCurrentURL); + +		// Check if this is a secure URL +		static const std::string secure_prefix = std::string("https://"); +		std::string prefix = mCurrentURL.substr(0, secure_prefix.length()); +		LLStringUtil::toLower(prefix); +        mSecureURL = (prefix == secure_prefix); +         +        // Hack : we move the text a bit to make space for the lock icon in the secure URL case +		mDisplayURL = (mSecureURL ? "      " + mCurrentURL : mCurrentURL); + +        // Clean up browsing list (prevent dupes) and add/select the new URL to it +        mAddressCombo->remove(mCurrentURL); +        mAddressCombo->add(mDisplayURL); +        mAddressCombo->selectByValue(mDisplayURL); + +        // Set the focus back to the web page. When setting the url, there's no point to leave the focus anywhere else. +		mWebBrowser->setFocus(TRUE); +    }  }  void LLFloaterWebContent::onClickForward() @@ -449,6 +481,7 @@ void LLFloaterWebContent::onEnterAddress()  	// make sure there is at least something there.  	// (perhaps this test should be for minimum length of a URL)  	std::string url = mAddressCombo->getValue().asString(); +    LLStringUtil::trim(url);  	if ( url.length() > 0 )  	{  		mWebBrowser->navigateTo( url, "text/html"); @@ -460,6 +493,7 @@ void LLFloaterWebContent::onPopExternal()  	// make sure there is at least something there.  	// (perhaps this test should be for minimum length of a URL)  	std::string url = mAddressCombo->getValue().asString(); +    LLStringUtil::trim(url);  	if ( url.length() > 0 )  	{  		LLWeb::loadURLExternal( url ); diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h index cfc87e9015..f7e0db8d9e 100755 --- a/indra/newview/llfloaterwebcontent.h +++ b/indra/newview/llfloaterwebcontent.h @@ -54,6 +54,7 @@ public:  								id;  		Optional<bool>			show_chrome,  								allow_address_entry, +                                allow_back_forward_navigation,  								trusted_content,  								show_page_title;  		Optional<LLRect>		preferred_media_size; @@ -105,9 +106,12 @@ protected:  	LLView*			mBtnReload;  	LLView*			mBtnStop; -	std::string		mCurrentURL; +	std::string		mCurrentURL;    // Current URL +	std::string		mDisplayURL;    // URL being displayed in the address bar (can differ by trailing / leading space)  	std::string		mUUID;  	bool			mShowPageTitle; +    bool            mAllowNavigation; +    bool            mSecureURL;     // true when the current url is prefixed "https://"  };  #endif  // LL_LLFLOATERWEBCONTENT_H diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 9e23755d73..3cd64618aa 100755 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -130,10 +130,10 @@ 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) -	} +		}  	notify_of_message(data, true); -} +    } @@ -155,22 +155,22 @@ static void on_avatar_name_cache_toast(const LLUUID& agent_id,  void notify_of_message(const LLSD& msg, bool is_dnd_msg)  { -	std::string user_preferences; +    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); +    LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id); -	// do not show notification which goes from agent -	if (gAgent.getID() == participant_id) -	{ -		return; -	} +    // 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; +    // 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  	bool is_session_focused = session_floater->isTornOff() && session_floater->hasFocus(); @@ -179,23 +179,23 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)  		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()) -	{ +    //  determine user prefs for this session +    if (session_id.isNull()) +    {  		if (msg["source_type"].asInteger() == CHAT_SOURCE_OBJECT)  		{  			user_preferences = gSavedSettings.getString("NotificationObjectIMOptions"); @@ -206,50 +206,50 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)  		}  		else  		{ -			user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions"); +    	user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions");  			if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM") == TRUE))  			{  				make_ui_sound("UISndNewIncomingIMSession"); -			} +    }  		}  	} -	else if(session->isP2PSessionType()) -	{ -		if (LLAvatarTracker::instance().isBuddy(participant_id)) -		{ -			user_preferences = gSavedSettings.getString("NotificationFriendIMOptions"); +    else if(session->isP2PSessionType()) +    { +        if (LLAvatarTracker::instance().isBuddy(participant_id)) +        { +        	user_preferences = gSavedSettings.getString("NotificationFriendIMOptions");  			if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM") == TRUE))  			{  				make_ui_sound("UISndNewIncomingIMSession");  			} -		} -		else -		{ -			user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions"); +        } +        else +        { +        	user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions");  			if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM") == TRUE))  			{  				make_ui_sound("UISndNewIncomingIMSession"); -			} -		} +        } +    }  	} -	else if(session->isAdHocSessionType()) -	{ -		user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions"); +    else if(session->isAdHocSessionType()) +    { +    	user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions");  		if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM") == TRUE))  		{  			make_ui_sound("UISndNewIncomingIMSession"); -		} +    }  	} -	else if(session->isGroupSessionType()) -	{ -		user_preferences = gSavedSettings.getString("NotificationGroupChatOptions"); +    else if(session->isGroupSessionType()) +    { +    	user_preferences = gSavedSettings.getString("NotificationGroupChatOptions");  		if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM") == TRUE))  		{  			make_ui_sound("UISndNewIncomingIMSession");  		} -	} +    } -	// actions: +    // actions:      // 0. nothing - exit      if (("noaction" == user_preferences || @@ -287,23 +287,23 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)  				}  			}  		} -		else -		{ +        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) +    // 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  				 	 	 	 	 	 	|| NOT_ON_TOP == conversations_floater_status))  		|| is_dnd_msg) -	{ -		if(!LLMuteList::getInstance()->isMuted(participant_id)) -		{ +    { +    	if(!LLMuteList::getInstance()->isMuted(participant_id)) +    	{  			if(gAgent.isDoNotDisturb())  			{  				store_dnd_message = true; @@ -318,43 +318,43 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)  				}  				else  				{ -					im_box->flashConversationItemWidget(session_id, true); -				} -			} +    		im_box->flashConversationItemWidget(session_id, true); +    	} +    }  		}  	} -	// 3. Flash FUI button -	if (("toast" == user_preferences || "flash" == user_preferences) && -		(CLOSED == conversations_floater_status +    // 3. Flash FUI button +    if (("toast" == user_preferences || "flash" == user_preferences) && +    		(CLOSED == conversations_floater_status  		|| NOT_ON_TOP == conversations_floater_status)  		&& !is_session_focused  		&& !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, im_box->isMinimized()); -			} +    	}  			else  			{  				store_dnd_message = true;  			} -		} +    }  	} -	// 4. Toast -	if ((("toast" == user_preferences) && +    // 4. Toast +    if ((("toast" == user_preferences) &&  		(ON_TOP_AND_ITEM_IS_SELECTED != conversations_floater_status) &&  		(!session_floater->isTornOff() || !LLFloater::isVisible(session_floater))) -		|| !session_floater->isMessagePaneExpanded()) +    		    || !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()) -		{ +    { +        //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()) @@ -363,10 +363,10 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)  				}  				else  				{ -					LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); -				} -			} -		} +            LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); +        } +    } +}  	}  	if (store_dnd_message)  	{ diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp index 08c98e4f28..2854962922 100755 --- a/indra/newview/llnotificationscripthandler.cpp +++ b/indra/newview/llnotificationscripthandler.cpp @@ -35,6 +35,9 @@  #include "llnotificationmanager.h"  #include "llnotifications.h"  #include "llscriptfloater.h" +#include "llfacebookconnect.h" +#include "llavatarname.h" +#include "llavatarnamecache.h"  using namespace LLNotificationsUI; diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index d7c634d619..f551fc96ee 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,15 +50,19 @@  #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 "llsidetraypanelcontainer.h"  #include "llrecentpeople.h"  #include "llviewercontrol.h"		// for gSavedSettings @@ -64,6 +70,10 @@  #include "llvoiceclient.h"  #include "llworld.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 @@ -73,9 +83,9 @@ 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 COLLAPSED_BY_USER  = "collapsed_by_user"; +  extern S32 gMaxAgentGroups;  /** Comparator for comparing avatar items by last interaction date */ @@ -495,6 +505,7 @@ public:  LLPanelPeople::LLPanelPeople()  	:	LLPanel(), +		mTryToConnectToFbc(true),  		mTabContainer(NULL),  		mOnlineFriendList(NULL),  		mAllFriendList(NULL), @@ -573,6 +584,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)); @@ -583,8 +595,11 @@ BOOL LLPanelPeople::postBuild()  	// updater is active only if panel is visible to user.  	friends_tab->setVisibleCallback(boost::bind(&Updater::setActive, mFriendListUpdater, _2));      friends_tab->setVisibleCallback(boost::bind(&LLPanelPeople::removePicker, this)); +	friends_tab->setVisibleCallback(boost::bind(&LLPanelPeople::updateFacebookList, this, _2)); +  	mOnlineFriendList = friends_tab->getChild<LLAvatarList>("avatars_online");  	mAllFriendList = friends_tab->getChild<LLAvatarList>("avatars_all"); +	mSuggestedFriends = friends_tab->getChild<LLAvatarList>("suggested_friends");  	mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online"));  	mOnlineFriendList->setShowIcons("FriendsListShowIcons");  	mOnlineFriendList->showPermissions("FriendsListShowPermissions"); @@ -617,6 +632,7 @@ BOOL LLPanelPeople::postBuild()  	mRecentList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);  	mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);  	mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); +	mSuggestedFriends->setContextMenu(&LLPanelPeopleMenus::gSuggestedFriendsContextMenu);  	setSortOrder(mRecentList,		(ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"),	false);  	setSortOrder(mAllFriendList,	(ESortOrder)gSavedSettings.getU32("FriendsSortOrder"),		false); @@ -695,7 +711,7 @@ void LLPanelPeople::updateFriendListHelpText()  	// Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...)  	// So, lets check all lists to avoid overlapping the text with online list. See EXT-6448. -	bool any_friend_exists = mAllFriendList->filterHasMatches() || mOnlineFriendList->filterHasMatches(); +	bool any_friend_exists = mAllFriendList->filterHasMatches() || mOnlineFriendList->filterHasMatches() || mSuggestedFriends->filterHasMatches();  	no_friends_text->setVisible(!any_friend_exists);  	if (no_friends_text->getVisible())  	{ @@ -762,9 +778,40 @@ void LLPanelPeople::updateFriendList()  	mAllFriendList->setDirty(true, !mAllFriendList->filterHasMatches());  	//update trash and other buttons according to a selected item  	updateButtons(); +	updateSuggestedFriendList();  	showFriendsAccordionsIfNeeded();  } +bool LLPanelPeople::updateSuggestedFriendList() +{ +	const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); +	uuid_vec_t& suggested_friends = mSuggestedFriends->getIDs(); +	suggested_friends.clear(); + +	//Add suggested friends +	LLSD friends = LLFacebookConnect::instance().getContent(); +	for (LLSD::array_const_iterator i = friends.beginArray(); i != friends.endArray(); ++i) +	{ +		LLUUID agent_id = (*i).asUUID(); +		bool second_life_buddy = agent_id.notNull() ? av_tracker.isBuddy(agent_id) : false; + +		if(!second_life_buddy) +		{ +			//FB+SL but not SL friend +			if (agent_id.notNull()) +			{ +				suggested_friends.push_back(agent_id); +			} +		} +	} + +	//Force a refresh when there aren't any filter matches (prevent displaying content that shouldn't display) +	mSuggestedFriends->setDirty(true, !mSuggestedFriends->filterHasMatches()); +	showFriendsAccordionsIfNeeded(); + +	return false; +} +  void LLPanelPeople::updateNearbyList()  {  	if (!mNearbyList) @@ -788,6 +835,51 @@ void LLPanelPeople::updateRecentList()  	mRecentList->setDirty();  } +bool LLPanelPeople::onConnectedToFacebook(const LLSD& data) +{ +	LLSD::Integer connection_state = data.get("enum").asInteger(); + +	if (connection_state == LLFacebookConnect::FB_CONNECTED) +	{ +		LLFacebookConnect::instance().loadFacebookFriends(); +	} +	else if(connection_state == LLFacebookConnect::FB_NOT_CONNECTED) +	{ +		updateSuggestedFriendList(); +	}; + +	return false; +} + +void LLPanelPeople::updateFacebookList(bool visible) +{ +	if (visible) +	{ +		LLEventPumps::instance().obtain("FacebookConnectContent").stopListening("LLPanelPeople"); // just in case it is already listening +		LLEventPumps::instance().obtain("FacebookConnectContent").listen("LLPanelPeople", boost::bind(&LLPanelPeople::updateSuggestedFriendList, this)); + +		LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLPanelPeople"); // just in case it is already listening +		LLEventPumps::instance().obtain("FacebookConnectState").listen("LLPanelPeople", boost::bind(&LLPanelPeople::onConnectedToFacebook, this, _1)); + +		if (LLFacebookConnect::instance().isConnected()) +		{ +			LLFacebookConnect::instance().loadFacebookFriends(); +		} +		else if(mTryToConnectToFbc) +		{ +			LLFacebookConnect::instance().checkConnectionToFacebook(); +			mTryToConnectToFbc = false; +		} +     +		updateSuggestedFriendList(); +	} +	else +	{ +		LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLPanelPeople"); +		LLEventPumps::instance().obtain("FacebookConnectContent").stopListening("LLPanelPeople"); +	} +} +  void LLPanelPeople::updateButtons()  {  	std::string cur_tab		= getActiveTabName(); @@ -993,23 +1085,25 @@ 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); +		mSuggestedFriends->setNameFilter(filter); -	setAccordionCollapsedByUser("tab_online", false); -	setAccordionCollapsedByUser("tab_all", false); -	showFriendsAccordionsIfNeeded(); +        setAccordionCollapsedByUser("tab_online", false); +        setAccordionCollapsedByUser("tab_all", false); +		setAccordionCollapsedByUser("tab_suggested_friends", 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); @@ -1229,7 +1323,7 @@ void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata)  		mAllFriendList->showPermissions(show_permissions);  		mOnlineFriendList->showPermissions(show_permissions);  	} -} +	}  void LLPanelPeople::onGroupsViewSortMenuItemClicked(const LLSD& userdata)  { @@ -1387,6 +1481,7 @@ void LLPanelPeople::showFriendsAccordionsIfNeeded()  		// Expand and show accordions if needed, else - hide them  		showAccordion("tab_online", mOnlineFriendList->filterHasMatches());  		showAccordion("tab_all", mAllFriendList->filterHasMatches()); +		showAccordion("tab_suggested_friends", mSuggestedFriends->filterHasMatches());  		// Rearrange accordions  		LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion"); @@ -1450,4 +1545,5 @@ bool LLPanelPeople::isAccordionCollapsedByUser(const std::string& name)  	return isAccordionCollapsedByUser(getChild<LLUICtrl>(name));  } +  // EOF diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index 4740964dee..c7141f36ee 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,6 +30,7 @@  #include <llpanel.h>  #include "llcallingcard.h" // for avatar tracker +#include "llfloaterwebcontent.h"  #include "llvoiceclient.h"  class LLAvatarList; @@ -55,6 +56,8 @@ public:  	// when voice is available  	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); +    bool mTryToConnectToFbc; +  	// internals  	class Updater; @@ -73,8 +76,10 @@ private:  	// methods indirectly called by the updaters  	void					updateFriendListHelpText();  	void					updateFriendList(); +	bool					updateSuggestedFriendList();  	void					updateNearbyList();  	void					updateRecentList(); +	void					updateFacebookList(bool visible);  	bool					isItemsFreeOfFriends(const uuid_vec_t& uuids); @@ -121,6 +126,8 @@ private:  	void					onFriendListRefreshComplete(LLUICtrl*ctrl, const LLSD& param); +	bool					onConnectedToFacebook(const LLSD& data); +  	void					setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed);  	void					setAccordionCollapsedByUser(const std::string& name, bool collapsed);  	bool					isAccordionCollapsedByUser(LLUICtrl* acc_tab); @@ -129,6 +136,7 @@ private:  	LLTabContainer*			mTabContainer;  	LLAvatarList*			mOnlineFriendList;  	LLAvatarList*			mAllFriendList; +	LLAvatarList*			mSuggestedFriends;  	LLAvatarList*			mNearbyList;  	LLAvatarList*			mRecentList;  	LLGroupList*			mGroupList; @@ -140,6 +148,7 @@ private:  	Updater*				mFriendListUpdater;  	Updater*				mNearbyListUpdater;  	Updater*				mRecentListUpdater; +	Updater*				mFacebookListUpdater;  	Updater*				mButtonsUpdater;      LLHandle< LLFloater >	mPicker;  }; diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp index 49f7361c4a..313056f06a 100755 --- a/indra/newview/llpanelpeoplemenus.cpp +++ b/indra/newview/llpanelpeoplemenus.cpp @@ -47,6 +47,7 @@ namespace LLPanelPeopleMenus  PeopleContextMenu gPeopleContextMenu;  NearbyPeopleContextMenu gNearbyPeopleContextMenu; +SuggestedFriendsContextMenu gSuggestedFriendsContextMenu;  //== PeopleContextMenu =============================================================== @@ -301,4 +302,36 @@ void NearbyPeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags)      hide_context_entries(menu, items, disabled_items);  } +//== SuggestedFriendsContextMenu =============================================================== + +LLContextMenu* SuggestedFriendsContextMenu::createMenu() +{ +	// set up the callbacks for all of the avatar menu items +	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; +	LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; +	LLContextMenu* menu; + +	// Set up for one person selected menu +	const LLUUID& id = mUUIDs.front(); +	registrar.add("Avatar.Profile",			boost::bind(&LLAvatarActions::showProfile,				id)); +	registrar.add("Avatar.AddFriend",		boost::bind(&LLAvatarActions::requestFriendshipDialog,	id)); + +	// create the context menu from the XUI +	menu = createFromFile("menu_people_nearby.xml"); +	buildContextMenu(*menu, 0x0); + +	return menu; +} + +void SuggestedFriendsContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags) +{  +	menuentry_vec_t items; +	menuentry_vec_t disabled_items; + +	items.push_back(std::string("view_profile")); +	items.push_back(std::string("add_friend")); + +	hide_context_entries(menu, items, disabled_items); +} +  } // namespace LLPanelPeopleMenus diff --git a/indra/newview/llpanelpeoplemenus.h b/indra/newview/llpanelpeoplemenus.h index 0a1dcef303..5367eca0d3 100755 --- a/indra/newview/llpanelpeoplemenus.h +++ b/indra/newview/llpanelpeoplemenus.h @@ -58,8 +58,21 @@ protected:  	/*virtual*/ void buildContextMenu(class LLMenuGL& menu, U32 flags);  }; +/** + * Menu used in the suggested friends list. + */ +class SuggestedFriendsContextMenu : public PeopleContextMenu +{ +public: +	/*virtual*/ LLContextMenu * createMenu(); + +protected: +	/*virtual*/ void buildContextMenu(class LLMenuGL& menu, U32 flags); +}; +  extern PeopleContextMenu gPeopleContextMenu;  extern NearbyPeopleContextMenu gNearbyPeopleContextMenu; +extern SuggestedFriendsContextMenu gSuggestedFriendsContextMenu;  } // namespace LLPanelPeopleMenus diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index 76d38f067d..9504f22a1d 100755 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -94,7 +94,8 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() :  	mZoomObjectFace(0),  	mVolumeSliderVisible(0),  	mWindowShade(NULL), -	mHideImmediately(false) +	mHideImmediately(false), +    mSecureURL(false)  {  	mCommitCallbackRegistrar.add("MediaCtrl.Close",		boost::bind(&LLPanelPrimMediaControls::onClickClose, this));  	mCommitCallbackRegistrar.add("MediaCtrl.Back",		boost::bind(&LLPanelPrimMediaControls::onClickBack, this)); @@ -345,7 +346,7 @@ void LLPanelPrimMediaControls::updateShape()  		// Disable zoom if HUD  		mZoomCtrl->setEnabled(!is_hud);  		mUnzoomCtrl->setEnabled(!is_hud); -		mSecureLockIcon->setVisible(false); +        mSecureURL = false;  		mCurrentURL = media_impl->getCurrentMediaURL();  		mBackCtrl->setEnabled((media_impl != NULL) && media_impl->canNavigateBack() && can_navigate); @@ -382,7 +383,7 @@ void LLPanelPrimMediaControls::updateShape()  			mVolumeSliderCtrl->setVisible(has_focus && shouldVolumeSliderBeVisible());  			mWhitelistIcon->setVisible(false); -			mSecureLockIcon->setVisible(false); +            mSecureURL = false;  			if (mMediaPanelScroll)  			{  				mMediaPanelScroll->setVisible(false); @@ -416,7 +417,7 @@ void LLPanelPrimMediaControls::updateShape()  				mMediaPlaySliderCtrl->setEnabled(true);  			} -			// video vloume +			// video volume  			if(volume <= 0.0)  			{  				mMuteBtn->setToggleState(true); @@ -492,10 +493,8 @@ void LLPanelPrimMediaControls::updateShape()  			std::string prefix =  std::string("https://");  			std::string test_prefix = mCurrentURL.substr(0, prefix.length());  			LLStringUtil::toLower(test_prefix); -			if(test_prefix == prefix) -			{ -				mSecureLockIcon->setVisible(has_focus); -			} +            mSecureURL = has_focus && (test_prefix == prefix); +            mCurrentURL = (mSecureURL ? "      " + mCurrentURL : mCurrentURL);  			if(mCurrentURL!=mPreviousURL)  			{ @@ -746,6 +745,9 @@ void LLPanelPrimMediaControls::draw()  			clearFaceOnFade();  		}  	} + +    // Show/hide the lock icon for secure browsing +    mSecureLockIcon->setVisible(mSecureURL && !mMediaAddress->hasFocus());  	// Build rect for icon area in coord system of this panel  	// Assumes layout_stack is a direct child of this panel diff --git a/indra/newview/llpanelprimmediacontrols.h b/indra/newview/llpanelprimmediacontrols.h index eeb433e306..6d2eb3430e 100755 --- a/indra/newview/llpanelprimmediacontrols.h +++ b/indra/newview/llpanelprimmediacontrols.h @@ -191,6 +191,7 @@ private:  	bool mUpdateSlider;  	bool mClearFaceOnFade;  	bool mHideImmediately; +    bool mSecureURL;  	LLMatrix4 mLastCameraMat;  	EZoomLevel mCurrentZoom; diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index c53760bca1..ee6893907e 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,8 @@ void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id)  	adjustParticipant(avatar_id);  } +static LLFastTimer::DeclareTimer FTM_FOLDERVIEW_TEST("add test avatar agents"); +  void LLParticipantList::adjustParticipant(const LLUUID& speaker_id)  {  	LLPointer<LLSpeaker> speakerp = mSpeakerMgr->findSpeaker(speaker_id); diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp new file mode 100644 index 0000000000..7532ebfc57 --- /dev/null +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -0,0 +1,874 @@ +/**  +* @file llsnapshotlivepreview.cpp +* @brief Implementation of llsnapshotlivepreview +* @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 "llagent.h" +#include "llagentcamera.h" +#include "llagentui.h" +#include "llcombobox.h" +#include "lleconomy.h" +#include "llfloaterperms.h" +#include "llfloaterreg.h" +#include "llfloatersocial.h" +#include "llimagebmp.h" +#include "llimagej2c.h" +#include "llimagejpeg.h" +#include "llimagepng.h" +#include "lllandmarkactions.h" +#include "lllocalcliprect.h" +#include "llnotificationsutil.h" +#include "llslurl.h" +#include "llsnapshotlivepreview.h" +#include "lltoolfocus.h" +#include "llviewercontrol.h" +#include "llviewermenufile.h"	// upload_new_resource() +#include "llviewerstats.h" +#include "llvfile.h" +#include "llvfs.h" +#include "llwebsharing.h" +#include "llwindow.h" +#include "llworld.h" + +const F32 AUTO_SNAPSHOT_TIME_DELAY = 1.f; + +F32 SHINE_TIME = 0.5f; +F32 SHINE_WIDTH = 0.6f; +F32 SHINE_OPACITY = 0.3f; +F32 FALL_TIME = 0.6f; +S32 BORDER_WIDTH = 6; + +const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512 + +std::set<LLSnapshotLivePreview*> LLSnapshotLivePreview::sList; + +LLSnapshotLivePreview::LLSnapshotLivePreview (const LLSnapshotLivePreview::Params& p)  +	:	LLView(p), +	mColor(1.f, 0.f, 0.f, 0.5f),  +	mCurImageIndex(0), +	mPreviewImage(NULL), +	mThumbnailImage(NULL) , +	mThumbnailWidth(0), +	mThumbnailHeight(0), +	mPreviewImageEncoded(NULL), +	mFormattedImage(NULL), +	mShineCountdown(0), +	mFlashAlpha(0.f), +	mNeedsFlash(TRUE), +	mSnapshotQuality(gSavedSettings.getS32("SnapshotQuality")), +	mDataSize(0), +	mSnapshotType(SNAPSHOT_POSTCARD), +	mSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat"))), +	mSnapshotUpToDate(FALSE), +	mCameraPos(LLViewerCamera::getInstance()->getOrigin()), +	mCameraRot(LLViewerCamera::getInstance()->getQuaternion()), +	mSnapshotActive(FALSE), +	mSnapshotBufferType(LLViewerWindow::SNAPSHOT_TYPE_COLOR) +{ +	setSnapshotQuality(gSavedSettings.getS32("SnapshotQuality")); +	mSnapshotDelayTimer.setTimerExpirySec(0.0f); +	mSnapshotDelayTimer.start(); +	// 	gIdleCallbacks.addFunction( &LLSnapshotLivePreview::onIdle, (void*)this ); +	sList.insert(this); +	setFollowsAll(); +	mWidth[0] = gViewerWindow->getWindowWidthRaw(); +	mWidth[1] = gViewerWindow->getWindowWidthRaw(); +	mHeight[0] = gViewerWindow->getWindowHeightRaw(); +	mHeight[1] = gViewerWindow->getWindowHeightRaw(); +	mImageScaled[0] = FALSE; +	mImageScaled[1] = FALSE; + +	mMaxImageSize = MAX_SNAPSHOT_IMAGE_SIZE ; +	mKeepAspectRatio = gSavedSettings.getBOOL("KeepAspectForSnapshot") ; +	mThumbnailUpdateLock = FALSE ; +	mThumbnailUpToDate   = FALSE ; +} + +LLSnapshotLivePreview::~LLSnapshotLivePreview() +{ +	// delete images +	mPreviewImage = NULL; +	mPreviewImageEncoded = NULL; +	mFormattedImage = NULL; + +	// 	gIdleCallbacks.deleteFunction( &LLSnapshotLivePreview::onIdle, (void*)this ); +	sList.erase(this); +} + +void LLSnapshotLivePreview::setMaxImageSize(S32 size)  +{ +	if(size < MAX_SNAPSHOT_IMAGE_SIZE) +	{ +		mMaxImageSize = size; +	} +	else +	{ +		mMaxImageSize = MAX_SNAPSHOT_IMAGE_SIZE ; +	} +} + +LLViewerTexture* LLSnapshotLivePreview::getCurrentImage() +{ +	return mViewerImage[mCurImageIndex]; +} + +F32 LLSnapshotLivePreview::getAspect() +{ +	F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight()); +	F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight()); + +	if (!mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot")) +	{ +		return image_aspect_ratio; +	} +	else +	{ +		return window_aspect_ratio; +	} +} + +F32 LLSnapshotLivePreview::getImageAspect() +{ +	if (!getCurrentImage()) +	{ +		return 0.f; +	} + +	return getAspect() ;	 +} + +void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail, F32 delay)  +{ +	// Invalidate current image. +	lldebugs << "updateSnapshot: mSnapshotUpToDate = " << getSnapshotUpToDate() << llendl; +	if (getSnapshotUpToDate()) +	{ +		S32 old_image_index = mCurImageIndex; +		mCurImageIndex = (mCurImageIndex + 1) % 2;  +		setSize(mWidth[old_image_index], mHeight[old_image_index]); +		mFallAnimTimer.start();		 +	} +	mSnapshotUpToDate = FALSE; 		 + +	// Update snapshot source rect depending on whether we keep the aspect ratio. +	LLRect& rect = mImageRect[mCurImageIndex]; +	rect.set(0, getRect().getHeight(), getRect().getWidth(), 0); + +	F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight()); +	F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight()); + +	if (mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot")) +	{ +		if (image_aspect_ratio > window_aspect_ratio) +		{ +			// trim off top and bottom +			S32 new_height = llround((F32)getRect().getWidth() / image_aspect_ratio);  +			rect.mBottom += (getRect().getHeight() - new_height) / 2; +			rect.mTop -= (getRect().getHeight() - new_height) / 2; +		} +		else if (image_aspect_ratio < window_aspect_ratio) +		{ +			// trim off left and right +			S32 new_width = llround((F32)getRect().getHeight() * image_aspect_ratio);  +			rect.mLeft += (getRect().getWidth() - new_width) / 2; +			rect.mRight -= (getRect().getWidth() - new_width) / 2; +		} +	} + +	// Stop shining animation. +	mShineAnimTimer.stop(); + +	// Update snapshot if requested. +	if (new_snapshot) +	{ +		mSnapshotDelayTimer.start(); +		mSnapshotDelayTimer.setTimerExpirySec(delay); +		LLFloaterSnapshot::preUpdate(); +		LLFloaterSocial::preUpdate(); +	} + +	// Update thumbnail if requested. +	if(new_thumbnail) +	{ +		mThumbnailUpToDate = FALSE ; +	} +} + +void LLSnapshotLivePreview::setSnapshotQuality(S32 quality) +{ +	llclamp(quality, 0, 100); +	if (quality != mSnapshotQuality) +	{ +		mSnapshotQuality = quality; +		gSavedSettings.setS32("SnapshotQuality", quality); +		mSnapshotUpToDate = FALSE; +	} +} + +void LLSnapshotLivePreview::drawPreviewRect(S32 offset_x, S32 offset_y) +{ +	F32 line_width ;  +	glGetFloatv(GL_LINE_WIDTH, &line_width) ; +	glLineWidth(2.0f * line_width) ; +	LLColor4 color(0.0f, 0.0f, 0.0f, 1.0f) ; +	gl_rect_2d( mPreviewRect.mLeft + offset_x, mPreviewRect.mTop + offset_y, +		mPreviewRect.mRight + offset_x, mPreviewRect.mBottom + offset_y, color, FALSE ) ; +	glLineWidth(line_width) ; + +	//draw four alpha rectangles to cover areas outside of the snapshot image +	if(!mKeepAspectRatio) +	{ +		LLColor4 alpha_color(0.5f, 0.5f, 0.5f, 0.8f) ; +		S32 dwl = 0, dwr = 0 ; +		if(mThumbnailWidth > mPreviewRect.getWidth()) +		{ +			dwl = (mThumbnailWidth - mPreviewRect.getWidth()) >> 1 ; +			dwr = mThumbnailWidth - mPreviewRect.getWidth() - dwl ; + +			gl_rect_2d(mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mTop + offset_y, +				mPreviewRect.mLeft + offset_x, mPreviewRect.mBottom + offset_y, alpha_color, TRUE ) ; +			gl_rect_2d( mPreviewRect.mRight + offset_x, mPreviewRect.mTop + offset_y, +				mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mBottom + offset_y, alpha_color, TRUE ) ; +		} + +		if(mThumbnailHeight > mPreviewRect.getHeight()) +		{ +			S32 dh = (mThumbnailHeight - mPreviewRect.getHeight()) >> 1 ; +			gl_rect_2d(mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mBottom + offset_y , +				mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mBottom + offset_y - dh, alpha_color, TRUE ) ; + +			dh = mThumbnailHeight - mPreviewRect.getHeight() - dh ; +			gl_rect_2d( mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mTop + offset_y + dh, +				mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mTop + offset_y, alpha_color, TRUE ) ; +		} +	} +} + +//called when the frame is frozen. +void LLSnapshotLivePreview::draw() +{ +	if (getCurrentImage() && +		mPreviewImageEncoded.notNull() && +		getSnapshotUpToDate()) +	{ +		LLColor4 bg_color(0.f, 0.f, 0.3f, 0.4f); +		gl_rect_2d(getRect(), bg_color); +		const LLRect& rect = getImageRect(); +		LLRect shadow_rect = rect; +		shadow_rect.stretch(BORDER_WIDTH); +		gl_drop_shadow(shadow_rect.mLeft, shadow_rect.mTop, shadow_rect.mRight, shadow_rect.mBottom, LLColor4(0.f, 0.f, 0.f, mNeedsFlash ? 0.f :0.5f), 10); + +		LLColor4 image_color(1.f, 1.f, 1.f, 1.f); +		gGL.color4fv(image_color.mV); +		gGL.getTexUnit(0)->bind(getCurrentImage()); +		// calculate UV scale +		F32 uv_width = isImageScaled() ? 1.f : llmin((F32)getWidth() / (F32)getCurrentImage()->getWidth(), 1.f); +		F32 uv_height = isImageScaled() ? 1.f : llmin((F32)getHeight() / (F32)getCurrentImage()->getHeight(), 1.f); +		gGL.pushMatrix(); +		{ +			gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom, 0.f); +			gGL.begin(LLRender::QUADS); +			{ +				gGL.texCoord2f(uv_width, uv_height); +				gGL.vertex2i(rect.getWidth(), rect.getHeight() ); + +				gGL.texCoord2f(0.f, uv_height); +				gGL.vertex2i(0, rect.getHeight() ); + +				gGL.texCoord2f(0.f, 0.f); +				gGL.vertex2i(0, 0); + +				gGL.texCoord2f(uv_width, 0.f); +				gGL.vertex2i(rect.getWidth(), 0); +			} +			gGL.end(); +		} +		gGL.popMatrix(); + +		gGL.color4f(1.f, 1.f, 1.f, mFlashAlpha); +		gl_rect_2d(getRect()); +		if (mNeedsFlash) +		{ +			if (mFlashAlpha < 1.f) +			{ +				mFlashAlpha = lerp(mFlashAlpha, 1.f, LLCriticalDamp::getInterpolant(0.02f)); +			} +			else +			{ +				mNeedsFlash = FALSE; +			} +		} +		else +		{ +			mFlashAlpha = lerp(mFlashAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f)); +		} + +		// Draw shining animation if appropriate. +		if (mShineCountdown > 0) +		{ +			mShineCountdown--; +			if (mShineCountdown == 0) +			{ +				mShineAnimTimer.start(); +			} +		} +		else if (mShineAnimTimer.getStarted()) +		{ +			lldebugs << "Drawing shining animation" << llendl; +			F32 shine_interp = llmin(1.f, mShineAnimTimer.getElapsedTimeF32() / SHINE_TIME); + +			// draw "shine" effect +			LLLocalClipRect clip(getLocalRect()); +			{ +				// draw diagonal stripe with gradient that passes over screen +				S32 x1 = gViewerWindow->getWindowWidthScaled() * llround((clamp_rescale(shine_interp, 0.f, 1.f, -1.f - SHINE_WIDTH, 1.f))); +				S32 x2 = x1 + llround(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH); +				S32 x3 = x2 + llround(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH); +				S32 y1 = 0; +				S32 y2 = gViewerWindow->getWindowHeightScaled(); + +				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +				gGL.begin(LLRender::QUADS); +				{ +					gGL.color4f(1.f, 1.f, 1.f, 0.f); +					gGL.vertex2i(x1, y1); +					gGL.vertex2i(x1 + gViewerWindow->getWindowWidthScaled(), y2); +					gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY); +					gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2); +					gGL.vertex2i(x2, y1); + +					gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY); +					gGL.vertex2i(x2, y1); +					gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2); +					gGL.color4f(1.f, 1.f, 1.f, 0.f); +					gGL.vertex2i(x3 + gViewerWindow->getWindowWidthScaled(), y2); +					gGL.vertex2i(x3, y1); +				} +				gGL.end(); +			} + +			// if we're at the end of the animation, stop +			if (shine_interp >= 1.f) +			{ +				mShineAnimTimer.stop(); +			} +		} +	} + +	// draw framing rectangle +	{ +		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +		gGL.color4f(1.f, 1.f, 1.f, 1.f); +		const LLRect& outline_rect = getImageRect(); +		gGL.begin(LLRender::QUADS); +		{ +			gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); +			gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); +			gGL.vertex2i(outline_rect.mRight, outline_rect.mTop); +			gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop); + +			gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom); +			gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom); +			gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); +			gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); + +			gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop); +			gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom); +			gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); +			gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); + +			gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom); +			gGL.vertex2i(outline_rect.mRight, outline_rect.mTop); +			gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); +			gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); +		} +		gGL.end(); +	} + +	// draw old image dropping away +	if (mFallAnimTimer.getStarted()) +	{ +		S32 old_image_index = (mCurImageIndex + 1) % 2; +		if (mViewerImage[old_image_index].notNull() && mFallAnimTimer.getElapsedTimeF32() < FALL_TIME) +		{ +			lldebugs << "Drawing fall animation" << llendl; +			F32 fall_interp = mFallAnimTimer.getElapsedTimeF32() / FALL_TIME; +			F32 alpha = clamp_rescale(fall_interp, 0.f, 1.f, 0.8f, 0.4f); +			LLColor4 image_color(1.f, 1.f, 1.f, alpha); +			gGL.color4fv(image_color.mV); +			gGL.getTexUnit(0)->bind(mViewerImage[old_image_index]); +			// calculate UV scale +			// *FIX get this to work with old image +			BOOL rescale = !mImageScaled[old_image_index] && mViewerImage[mCurImageIndex].notNull(); +			F32 uv_width = rescale ? llmin((F32)mWidth[old_image_index] / (F32)mViewerImage[mCurImageIndex]->getWidth(), 1.f) : 1.f; +			F32 uv_height = rescale ? llmin((F32)mHeight[old_image_index] / (F32)mViewerImage[mCurImageIndex]->getHeight(), 1.f) : 1.f; +			gGL.pushMatrix(); +			{ +				LLRect& rect = mImageRect[old_image_index]; +				gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom - llround(getRect().getHeight() * 2.f * (fall_interp * fall_interp)), 0.f); +				gGL.rotatef(-45.f * fall_interp, 0.f, 0.f, 1.f); +				gGL.begin(LLRender::QUADS); +				{ +					gGL.texCoord2f(uv_width, uv_height); +					gGL.vertex2i(rect.getWidth(), rect.getHeight() ); + +					gGL.texCoord2f(0.f, uv_height); +					gGL.vertex2i(0, rect.getHeight() ); + +					gGL.texCoord2f(0.f, 0.f); +					gGL.vertex2i(0, 0); + +					gGL.texCoord2f(uv_width, 0.f); +					gGL.vertex2i(rect.getWidth(), 0); +				} +				gGL.end(); +			} +			gGL.popMatrix(); +		} +	} +} + +/*virtual*/  +void LLSnapshotLivePreview::reshape(S32 width, S32 height, BOOL called_from_parent) +{ +	LLRect old_rect = getRect(); +	LLView::reshape(width, height, called_from_parent); +	if (old_rect.getWidth() != width || old_rect.getHeight() != height) +	{ +		lldebugs << "window reshaped, updating thumbnail" << llendl; +		updateSnapshot(FALSE, TRUE); +	} +} + +BOOL LLSnapshotLivePreview::setThumbnailImageSize() +{ +	if(getWidth() < 10 || getHeight() < 10) +	{ +		return FALSE ; +	} +	S32 window_width = gViewerWindow->getWindowWidthRaw() ; +	S32 window_height = gViewerWindow->getWindowHeightRaw() ; + +	F32 window_aspect_ratio = ((F32)window_width) / ((F32)window_height); + +	// UI size for thumbnail +	// *FIXME: the rect does not change, so maybe there's no need to recalculate max w/h. +	const LLRect& thumbnail_rect = mThumbnailPlaceholderRect; +	S32 max_width = thumbnail_rect.getWidth(); +	S32 max_height = thumbnail_rect.getHeight(); + +	if (window_aspect_ratio > (F32)max_width / max_height) +	{ +		// image too wide, shrink to width +		mThumbnailWidth = max_width; +		mThumbnailHeight = llround((F32)max_width / window_aspect_ratio); +	} +	else +	{ +		// image too tall, shrink to height +		mThumbnailHeight = max_height; +		mThumbnailWidth = llround((F32)max_height * window_aspect_ratio); +	} + +	if(mThumbnailWidth > window_width || mThumbnailHeight > window_height) +	{ +		return FALSE ;//if the window is too small, ignore thumbnail updating. +	} + +	S32 left = 0 , top = mThumbnailHeight, right = mThumbnailWidth, bottom = 0 ; +	if(!mKeepAspectRatio) +	{ +		F32 ratio_x = (F32)getWidth() / window_width ; +		F32 ratio_y = (F32)getHeight() / window_height ; + +		//if(getWidth() > window_width || +		//	getHeight() > window_height ) +		{ +			if(ratio_x > ratio_y) +			{ +				top = (S32)(top * ratio_y / ratio_x) ; +			} +			else +			{ +				right = (S32)(right * ratio_x / ratio_y) ; +			}			 +		} +		//else +		//{ +		//	right = (S32)(right * ratio_x) ; +		//	top = (S32)(top * ratio_y) ; +		//} +		left = (S32)((mThumbnailWidth - right) * 0.5f) ; +		bottom = (S32)((mThumbnailHeight - top) * 0.5f) ; +		top += bottom ; +		right += left ; +	} +	mPreviewRect.set(left - 1, top + 1, right + 1, bottom - 1) ; + +	return TRUE ; +} + +void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update) +{	 +	if(mThumbnailUpdateLock) //in the process of updating +	{ +		return ; +	} +	if(getThumbnailUpToDate() && !force_update)//already updated +	{ +		return ; +	} +	if(getWidth() < 10 || getHeight() < 10) +	{ +		return ; +	} + +	////lock updating +	mThumbnailUpdateLock = TRUE ; + +	if(!setThumbnailImageSize()) +	{ +		mThumbnailUpdateLock = FALSE ; +		mThumbnailUpToDate = TRUE ; +		return ; +	} + +	if(mThumbnailImage) +	{ +		resetThumbnailImage() ; +	}		 + +	LLPointer<LLImageRaw> raw = new LLImageRaw; +	if(!gViewerWindow->thumbnailSnapshot(raw, +		mThumbnailWidth, mThumbnailHeight, +		gSavedSettings.getBOOL("RenderUIInSnapshot"), +		FALSE, +		mSnapshotBufferType) )								 +	{ +		raw = NULL ; +	} + +	if(raw) +	{ +		raw->expandToPowerOfTwo(); +		mThumbnailImage = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); 		 +		mThumbnailUpToDate = TRUE ; +	} + +	//unlock updating +	mThumbnailUpdateLock = FALSE ;		 +} + + +// Called often. Checks whether it's time to grab a new snapshot and if so, does it. +// Returns TRUE if new snapshot generated, FALSE otherwise. +//static  +BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) +{ +	LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)snapshot_preview; +	if (previewp->getWidth() == 0 || previewp->getHeight() == 0) +	{ +		llwarns << "Incorrect dimensions: " << previewp->getWidth() << "x" << previewp->getHeight() << llendl; +		return FALSE; +	} + +	// If we're in freeze-frame mode and camera has moved, update snapshot. +	LLVector3 new_camera_pos = LLViewerCamera::getInstance()->getOrigin(); +	LLQuaternion new_camera_rot = LLViewerCamera::getInstance()->getQuaternion(); +	if (gSavedSettings.getBOOL("FreezeTime") &&  +		(new_camera_pos != previewp->mCameraPos || dot(new_camera_rot, previewp->mCameraRot) < 0.995f)) +	{ +		previewp->mCameraPos = new_camera_pos; +		previewp->mCameraRot = new_camera_rot; +		// request a new snapshot whenever the camera moves, with a time delay +		BOOL autosnap = gSavedSettings.getBOOL("AutoSnapshot"); +		lldebugs << "camera moved, updating thumbnail" << llendl; +		previewp->updateSnapshot( +			autosnap, // whether a new snapshot is needed or merely invalidate the existing one +			FALSE, // or if 1st arg is false, whether to produce a new thumbnail image. +			autosnap ? AUTO_SNAPSHOT_TIME_DELAY : 0.f); // shutter delay if 1st arg is true. +	} + +	// see if it's time yet to snap the shot and bomb out otherwise. +	previewp->mSnapshotActive =  +		(previewp->mSnapshotDelayTimer.getStarted() &&	previewp->mSnapshotDelayTimer.hasExpired()) +		&& !LLToolCamera::getInstance()->hasMouseCapture(); // don't take snapshots while ALT-zoom active +	if ( ! previewp->mSnapshotActive) +	{ +		return FALSE; +	} + +	// time to produce a snapshot +	previewp->setThumbnailImageSize(); + +	lldebugs << "producing snapshot" << llendl; +	if (!previewp->mPreviewImage) +	{ +		previewp->mPreviewImage = new LLImageRaw; +	} + +	if (!previewp->mPreviewImageEncoded) +	{ +		previewp->mPreviewImageEncoded = new LLImageRaw; +	} + +	previewp->setVisible(FALSE); +	previewp->setEnabled(FALSE); + +	previewp->getWindow()->incBusyCount(); +	previewp->setImageScaled(FALSE); + +	// grab the raw image and encode it into desired format +	if(gViewerWindow->rawSnapshot( +		previewp->mPreviewImage, +		previewp->getWidth(), +		previewp->getHeight(), +		previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"), +		previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_TEXTURE, +		gSavedSettings.getBOOL("RenderUIInSnapshot"), +		FALSE, +		previewp->mSnapshotBufferType, +		previewp->getMaxImageSize())) +	{ +		previewp->mPreviewImageEncoded->resize( +			previewp->mPreviewImage->getWidth(),  +			previewp->mPreviewImage->getHeight(),  +			previewp->mPreviewImage->getComponents()); + +		if(previewp->getSnapshotType() == SNAPSHOT_TEXTURE) +		{ +			lldebugs << "Encoding new image of format J2C" << llendl; +			LLPointer<LLImageJ2C> formatted = new LLImageJ2C; +			LLPointer<LLImageRaw> scaled = new LLImageRaw( +				previewp->mPreviewImage->getData(), +				previewp->mPreviewImage->getWidth(), +				previewp->mPreviewImage->getHeight(), +				previewp->mPreviewImage->getComponents()); + +			scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE); +			previewp->setImageScaled(TRUE); +			if (formatted->encode(scaled, 0.f)) +			{ +				previewp->mDataSize = formatted->getDataSize(); +				formatted->decode(previewp->mPreviewImageEncoded, 0); +			} +		} +		else +		{ +			// delete any existing image +			previewp->mFormattedImage = NULL; +			// now create the new one of the appropriate format. +			LLFloaterSnapshot::ESnapshotFormat format = previewp->getSnapshotFormat(); +			lldebugs << "Encoding new image of format " << format << llendl; + +			switch(format) +			{ +			case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG: +				previewp->mFormattedImage = new LLImagePNG();  +				break; +			case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG: +				previewp->mFormattedImage = new LLImageJPEG(previewp->mSnapshotQuality);  +				break; +			case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP: +				previewp->mFormattedImage = new LLImageBMP();  +				break; +			} +			if (previewp->mFormattedImage->encode(previewp->mPreviewImage, 0)) +			{ +				previewp->mDataSize = previewp->mFormattedImage->getDataSize(); +				// special case BMP to copy instead of decode otherwise decode will crash. +				if(format == LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP) +				{ +					previewp->mPreviewImageEncoded->copy(previewp->mPreviewImage); +				} +				else +				{ +					previewp->mFormattedImage->decode(previewp->mPreviewImageEncoded, 0); +				} +			} +		} + +		LLPointer<LLImageRaw> scaled = new LLImageRaw( +			previewp->mPreviewImageEncoded->getData(), +			previewp->mPreviewImageEncoded->getWidth(), +			previewp->mPreviewImageEncoded->getHeight(), +			previewp->mPreviewImageEncoded->getComponents()); + +		if(!scaled->isBufferInvalid()) +		{ +			// leave original image dimensions, just scale up texture buffer +			if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024) +			{ +				// go ahead and shrink image to appropriate power of 2 for display +				scaled->biasedScaleToPowerOfTwo(1024); +				previewp->setImageScaled(TRUE); +			} +			else +			{ +				// expand image but keep original image data intact +				scaled->expandToPowerOfTwo(1024, FALSE); +			} + +			previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE); +			LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex]; +			gGL.getTexUnit(0)->bind(curr_preview_image); +			if (previewp->getSnapshotType() != SNAPSHOT_TEXTURE) +			{ +				curr_preview_image->setFilteringOption(LLTexUnit::TFO_POINT); +			} +			else +			{ +				curr_preview_image->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); +			} +			curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP); + +			previewp->mSnapshotUpToDate = TRUE; +			previewp->generateThumbnailImage(TRUE) ; + +			previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal(); +			previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame +		} +	} +	previewp->getWindow()->decBusyCount(); +	// only show fullscreen preview when in freeze frame mode +	previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame")); +	previewp->mSnapshotDelayTimer.stop(); +	previewp->mSnapshotActive = FALSE; + +	if(!previewp->getThumbnailUpToDate()) +	{ +		previewp->generateThumbnailImage() ; +	} +	lldebugs << "done creating snapshot" << llendl; +	LLFloaterSnapshot::postUpdate(); +	LLFloaterSocial::postUpdate(); + +	return TRUE; +} + +void LLSnapshotLivePreview::setSize(S32 w, S32 h) +{ +	lldebugs << "setSize(" << w << ", " << h << ")" << llendl; +	setWidth(w); +	setHeight(h); +} + +void LLSnapshotLivePreview::getSize(S32& w, S32& h) const +{ +	w = getWidth(); +	h = getHeight(); +} + +void LLSnapshotLivePreview::saveTexture() +{ +	lldebugs << "saving texture: " << mPreviewImage->getWidth() << "x" << mPreviewImage->getHeight() << llendl; +	// gen a new uuid for this asset +	LLTransactionID tid; +	tid.generate(); +	LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + +	LLPointer<LLImageJ2C> formatted = new LLImageJ2C; +	LLPointer<LLImageRaw> scaled = new LLImageRaw(mPreviewImage->getData(), +		mPreviewImage->getWidth(), +		mPreviewImage->getHeight(), +		mPreviewImage->getComponents()); + +	scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE); +	lldebugs << "scaled texture to " << scaled->getWidth() << "x" << scaled->getHeight() << llendl; + +	if (formatted->encode(scaled, 0.0f)) +	{ +		LLVFile::writeFile(formatted->getData(), formatted->getDataSize(), gVFS, new_asset_id, LLAssetType::AT_TEXTURE); +		std::string pos_string; +		LLAgentUI::buildLocationString(pos_string, LLAgentUI::LOCATION_FORMAT_FULL); +		std::string who_took_it; +		LLAgentUI::buildFullname(who_took_it); +		LLAssetStorage::LLStoreAssetCallback callback = NULL; +		S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); +		void *userdata = NULL; +		upload_new_resource(tid,	// tid +			LLAssetType::AT_TEXTURE, +			"Snapshot : " + pos_string, +			"Taken by " + who_took_it + " at " + pos_string, +			0, +			LLFolderType::FT_SNAPSHOT_CATEGORY, +			LLInventoryType::IT_SNAPSHOT, +			PERM_ALL,  // Note: Snapshots to inventory is a special case of content upload +			LLFloaterPerms::getGroupPerms(), // that is more permissive than other uploads +			LLFloaterPerms::getEveryonePerms(), +			"Snapshot : " + pos_string, +			callback, expected_upload_cost, userdata); +		gViewerWindow->playSnapshotAnimAndSound(); +	} +	else +	{ +		LLNotificationsUtil::add("ErrorEncodingSnapshot"); +		llwarns << "Error encoding snapshot" << llendl; +	} + +	LLViewerStats::getInstance()->incStat(LLViewerStats::ST_SNAPSHOT_COUNT ); + +	mDataSize = 0; +} + +BOOL LLSnapshotLivePreview::saveLocal() +{ +	BOOL success = gViewerWindow->saveImageNumbered(mFormattedImage); + +	if(success) +	{ +		gViewerWindow->playSnapshotAnimAndSound(); +	} +	return success; +} + +void LLSnapshotLivePreview::saveWeb() +{ +	// *FIX: Will break if the window closes because of CloseSnapshotOnKeep! +	// Needs to pass on ownership of the image. +	LLImageJPEG* jpg = dynamic_cast<LLImageJPEG*>(mFormattedImage.get()); +	if(!jpg) +	{ +		llwarns << "Formatted image not a JPEG" << llendl; +		return; +	} + +	LLSD metadata; +	metadata["description"] = getChild<LLLineEditor>("description")->getText(); + +	LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(gAgentCamera.getCameraPositionGlobal(), +		boost::bind(&LLSnapshotLivePreview::regionNameCallback, this, jpg, metadata, _1, _2, _3, _4)); + +	gViewerWindow->playSnapshotAnimAndSound(); +} + +void LLSnapshotLivePreview::regionNameCallback(LLImageJPEG* snapshot, LLSD& metadata, const std::string& name, S32 x, S32 y, S32 z) +{ +	metadata["slurl"] = LLSLURL(name, LLVector3d(x, y, z)).getSLURLString(); + +	LLWebSharing::instance().shareSnapshot(snapshot, metadata); +} diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h new file mode 100644 index 0000000000..fe3d257b02 --- /dev/null +++ b/indra/newview/llsnapshotlivepreview.h @@ -0,0 +1,164 @@ +/**  +* @file   llsnapshotlivepreview.h +* @brief  Header file for llsnapshotlivepreview +* @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_LLSNAPSHOTLIVEPREVIEW_H +#define LL_LLSNAPSHOTLIVEPREVIEW_H + +#include "llpanelsnapshot.h" +#include "llviewerwindow.h" + +class LLImageJPEG; + +///---------------------------------------------------------------------------- +/// Class LLSnapshotLivePreview  +///---------------------------------------------------------------------------- +class LLSnapshotLivePreview : public LLView +{ +	LOG_CLASS(LLSnapshotLivePreview); +public: +	enum ESnapshotType +	{ +		SNAPSHOT_POSTCARD, +		SNAPSHOT_TEXTURE, +		SNAPSHOT_LOCAL, +		SNAPSHOT_WEB +	}; + + +	struct Params : public LLInitParam::Block<Params, LLView::Params> +	{ +		Params() +		{ +			name = "snapshot_live_preview"; +			mouse_opaque = false; +		} +	}; + + +	LLSnapshotLivePreview(const LLSnapshotLivePreview::Params& p); +	~LLSnapshotLivePreview(); + +	/*virtual*/ void draw(); +	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent); + +	void setSize(S32 w, S32 h); +	void setWidth(S32 w) { mWidth[mCurImageIndex] = w; } +	void setHeight(S32 h) { mHeight[mCurImageIndex] = h; } +	void getSize(S32& w, S32& h) const; +	S32 getWidth() const { return mWidth[mCurImageIndex]; } +	S32 getHeight() const { return mHeight[mCurImageIndex]; } +	S32 getDataSize() const { return mDataSize; } +	void setMaxImageSize(S32 size) ; +	S32  getMaxImageSize() {return mMaxImageSize ;} + +	ESnapshotType getSnapshotType() const { return mSnapshotType; } +	LLFloaterSnapshot::ESnapshotFormat getSnapshotFormat() const { return mSnapshotFormat; } +	BOOL getSnapshotUpToDate() const { return mSnapshotUpToDate; } +	BOOL isSnapshotActive() { return mSnapshotActive; } +	LLViewerTexture* getThumbnailImage() const { return mThumbnailImage ; } +	S32  getThumbnailWidth() const { return mThumbnailWidth ; } +	S32  getThumbnailHeight() const { return mThumbnailHeight ; } +	BOOL getThumbnailLock() const { return mThumbnailUpdateLock ; } +	BOOL getThumbnailUpToDate() const { return mThumbnailUpToDate ;} +	LLViewerTexture* getCurrentImage(); +	F32 getImageAspect(); +	F32 getAspect() ; +	const LLRect& getImageRect() const { return mImageRect[mCurImageIndex]; } +	BOOL isImageScaled() const { return mImageScaled[mCurImageIndex]; } +	void setImageScaled(BOOL scaled) { mImageScaled[mCurImageIndex] = scaled; } +	const LLVector3d& getPosTakenGlobal() const { return mPosTakenGlobal; } + +	void setSnapshotType(ESnapshotType type) { mSnapshotType = type; } +	void setSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat type) { mSnapshotFormat = type; } +	void setSnapshotQuality(S32 quality); +	void setSnapshotBufferType(LLViewerWindow::ESnapshotType type) { mSnapshotBufferType = type; } +	void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f); +	void saveWeb(); +	void saveTexture(); +	BOOL saveLocal(); + +	LLPointer<LLImageFormatted>	getFormattedImage() const { return mFormattedImage; } +	LLPointer<LLImageRaw>		getEncodedImage() const { return mPreviewImageEncoded; } + +	/// Sets size of preview thumbnail image and thhe surrounding rect. +	void setThumbnailPlaceholderRect(const LLRect& rect) {mThumbnailPlaceholderRect = rect; } +	BOOL setThumbnailImageSize() ; +	void generateThumbnailImage(BOOL force_update = FALSE) ; +	void resetThumbnailImage() { mThumbnailImage = NULL ; } +	void drawPreviewRect(S32 offset_x, S32 offset_y) ; + +	// Returns TRUE when snapshot generated, FALSE otherwise. +	static BOOL onIdle( void* snapshot_preview ); + +	// callback for region name resolve +	void regionNameCallback(LLImageJPEG* snapshot, LLSD& metadata, const std::string& name, S32 x, S32 y, S32 z); + +private: +	LLColor4					mColor; +	LLPointer<LLViewerTexture>	mViewerImage[2]; //used to represent the scene when the frame is frozen. +	LLRect						mImageRect[2]; +	S32							mWidth[2]; +	S32							mHeight[2]; +	BOOL						mImageScaled[2]; +	S32                         mMaxImageSize ; + +	//thumbnail image +	LLPointer<LLViewerTexture>	mThumbnailImage ; +	S32                         mThumbnailWidth ; +	S32                         mThumbnailHeight ; +	LLRect                      mPreviewRect ; +	BOOL                        mThumbnailUpdateLock ; +	BOOL                        mThumbnailUpToDate ; +	LLRect                      mThumbnailPlaceholderRect; + +	S32							mCurImageIndex; +	LLPointer<LLImageRaw>		mPreviewImage; +	LLPointer<LLImageRaw>		mPreviewImageEncoded; +	LLPointer<LLImageFormatted>	mFormattedImage; +	LLFrameTimer				mSnapshotDelayTimer; +	S32							mShineCountdown; +	LLFrameTimer				mShineAnimTimer; +	F32							mFlashAlpha; +	BOOL						mNeedsFlash; +	LLVector3d					mPosTakenGlobal; +	S32							mSnapshotQuality; +	S32							mDataSize; +	ESnapshotType				mSnapshotType; +	LLFloaterSnapshot::ESnapshotFormat	mSnapshotFormat; +	BOOL						mSnapshotUpToDate; +	LLFrameTimer				mFallAnimTimer; +	LLVector3					mCameraPos; +	LLQuaternion				mCameraRot; +	BOOL						mSnapshotActive; +	LLViewerWindow::ESnapshotType mSnapshotBufferType; + +public: +	static std::set<LLSnapshotLivePreview*> sList; +	BOOL                        mKeepAspectRatio ; +}; + +#endif // LL_LLSNAPSHOTLIVEPREVIEW_H + diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp index 09ab31df36..bdbd8f1f83 100755 --- a/indra/newview/lltoastimpanel.cpp +++ b/indra/newview/lltoastimpanel.cpp @@ -93,7 +93,7 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) :	LLToastPanel(p.notif  	if(!mIsGroupMsg)  	{ -		mAvatarName->setValue(p.from); +	mAvatarName->setValue(p.from);  	}  	mTime->setValue(p.time);  	mSessionID = p.session_id; @@ -164,7 +164,7 @@ void LLToastIMPanel::spawnNameToolTip()  	params.background_visible(false);  	if(!mIsGroupMsg)  	{ -		params.click_callback(boost::bind(&LLFloaterReg::showInstance, "inspect_avatar", LLSD().with("avatar_id", mAvatarID), FALSE)); +	params.click_callback(boost::bind(&LLFloaterReg::showInstance, "inspect_avatar", LLSD().with("avatar_id", mAvatarID), FALSE));  	}  	else  	{ diff --git a/indra/newview/llurlhistory.cpp b/indra/newview/llurlhistory.cpp index dd17068be5..a80b9da13c 100755 --- a/indra/newview/llurlhistory.cpp +++ b/indra/newview/llurlhistory.cpp @@ -103,22 +103,29 @@ LLSD LLURLHistory::getURLHistory(const std::string& collection)  // static  void LLURLHistory::addURL(const std::string& collection, const std::string& url)  { -	if(! url.empty()) +	if(!url.empty())  	{ -		sHistorySD[collection].insert(0, url); +        LLURI u(url); +        std::string simplified_url = u.scheme() + "://" + u.authority() + u.path(); +		sHistorySD[collection].insert(0, simplified_url);  		LLURLHistory::limitSize(collection);  	}  }  // static  void LLURLHistory::removeURL(const std::string& collection, const std::string& url)  { -	for(int index = 0; index < sHistorySD[collection].size(); index++) +	if(!url.empty())  	{ -		if(sHistorySD[collection].get(index).asString() == url) -		{ -			sHistorySD[collection].erase(index); -		} -	} +        LLURI u(url); +        std::string simplified_url = u.scheme() + "://" + u.authority() + u.path(); +        for(int index = 0; index < sHistorySD[collection].size(); index++) +        { +            if(sHistorySD[collection].get(index).asString() == simplified_url) +            { +                sHistorySD[collection].erase(index); +            } +        } +    }  }  // static diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index c6b28b9e5e..4ce049df03 100755 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -103,6 +103,7 @@  #include "llfloatersettingsdebug.h"  #include "llfloatersidepanelcontainer.h"  #include "llfloatersnapshot.h" +#include "llfloatersocial.h"  #include "llfloatersounddevices.h"  #include "llfloaterspellchecksettings.h"  #include "llfloatertelehub.h" @@ -303,6 +304,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater);  	LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>);  	LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>); +	LLFloaterReg::add("social", "floater_social.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSocial>);  	LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>);  	LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>);  	LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>); @@ -311,7 +313,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("my_profile", "floater_my_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create);  	LLFloaterReg::add("profile", "floater_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create);  	LLFloaterReg::add("how_to", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);	 - +	LLFloaterReg::add("fbc_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);  	LLFloaterUIPreviewUtil::registerFloater();  	LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBvhPreview>, "upload"); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 2df028de69..13483790ed 100755 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -2000,7 +2000,12 @@ void LLViewerMediaImpl::loadURI()  										"<>#%"  										";/?:@&=",  										false); -		llinfos << "Asking media source to load URI: " << uri << llendl; +        { +            // Do not log the query parts +            LLURI u(uri); +            std::string sanitized_uri = (u.query().empty() ? uri : u.scheme() + "://" + u.authority() + u.path()); +            llinfos << "Asking media source to load URI: " << sanitized_uri << llendl; +        }  		mMediaSource->loadURI( uri ); @@ -2567,7 +2572,12 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi  	if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)  	{  		// Helpful to have media urls in log file. Shouldn't be spammy. -		llinfos << "NOT LOADING media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl; +        { +            // Do not log the query parts +            LLURI u(url); +            std::string sanitized_url = (u.query().empty() ? url : u.scheme() + "://" + u.authority() + u.path()); +            llinfos << "NOT LOADING media id= " << mTextureId << " url=" << sanitized_url << ", mime_type=" << mime_type << llendl; +        }  		// This impl should not be loaded at this time.  		LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; @@ -2582,7 +2592,12 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi  void LLViewerMediaImpl::navigateInternal()  {  	// Helpful to have media urls in log file. Shouldn't be spammy. -	llinfos << "media id= " << mTextureId << " url=" << mMediaURL << " mime_type=" << mMimeType << llendl; +    { +        // Do not log the query parts +        LLURI u(mMediaURL); +        std::string sanitized_url = (u.query().empty() ? mMediaURL : u.scheme() + "://" + u.authority() + u.path()); +        llinfos << "media id= " << mTextureId << " url=" << sanitized_url << ", mime_type=" << mMimeType << llendl; +    }  	if(mNavigateSuspended)  	{ diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 49eb7dc94a..1c2cb978c7 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -45,6 +45,7 @@  #include "llagent.h"  #include "llagentaccess.h"  #include "llagentcamera.h" +#include "llagentui.h"  #include "llagentwearables.h"  #include "llagentpilot.h"  #include "llcompilequeue.h" @@ -52,6 +53,7 @@  #include "lldaycyclemanager.h"  #include "lldebugview.h"  #include "llenvmanager.h" +#include "llfacebookconnect.h"  #include "llfilepicker.h"  #include "llfirstuse.h"  #include "llfloaterbuy.h" diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index e6fc82f761..0c32782ff6 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/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 641f338f2c..69255af179 100755 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -148,9 +148,6 @@ public:  		LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << llendl;  		LLWebProfile::reportImageUploadStatus(true);  	} - -private: -	LLPointer<LLImageFormatted> mImagep;  }; @@ -172,7 +169,7 @@ public:  			headers["Cookie"] = LLWebProfile::getAuthCookie();  			const std::string& redir_url = content["location"];  			LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << llendl; -			LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); +			LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder(), headers);  		}  		else  		{ 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/icons/map_placeholder.png b/indra/newview/skins/default/textures/icons/map_placeholder.pngBinary files differ new file mode 100644 index 0000000000..31e457aa75 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/map_placeholder.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 54f60f4441..94c187e21a 100755 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -148,6 +148,7 @@ with the same filename but different name    <texture name="Command_Preferences_Icon"  file_name="toolbar_icons/preferences.png"  preload="true" />    <texture name="Command_Profile_Icon"      file_name="toolbar_icons/profile.png"      preload="true" />    <texture name="Command_Search_Icon"       file_name="toolbar_icons/search.png"       preload="true" /> +  <texture name="Command_Social_Icon"       file_name="toolbar_icons/facebook.png"     preload="true" />    <texture name="Command_Snapshot_Icon"     file_name="toolbar_icons/snapshot.png"     preload="true" />    <texture name="Command_Speak_Icon"        file_name="toolbar_icons/speak.png"        preload="true" />    <texture name="Command_View_Icon"         file_name="toolbar_icons/view.png"         preload="true" /> @@ -199,6 +200,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" /> @@ -323,6 +326,8 @@ with the same filename but different name    <texture name="Locked_Icon" file_name="icons/Locked_Icon.png" preload="false" /> +  <texture name="Map_Placeholder_Icon" file_name="icons/map_placeholder.png" preload="true" /> +        <texture name="MarketplaceBtn_Off" file_name="widgets/MarketplaceBtn_Off.png" preload="true" scale.left="30" scale.top="19" scale.right="35" scale.bottom="4" />    <texture name="MarketplaceBtn_Selected" file_name="widgets/MarketplaceBtn_Selected.png" preload="true" scale.left="30" scale.top="19" scale.right="35" scale.bottom="4" /> @@ -565,6 +570,7 @@ with the same filename but different name    <texture name="Snapshot_Email" file_name="snapshot_email.png" preload="false" />    <texture name="Snapshot_Inventory" file_name="toolbar_icons/inventory.png" preload="false" />    <texture name="Snapshot_Profile" file_name="toolbar_icons/profile.png" preload="false" /> +  <texture name="Snapshot_Facebook" file_name="toolbar_icons/facebook.png" preload="false" />    <texture name="startup_logo"  file_name="windows/startup_logo.png" preload="true" /> diff --git a/indra/newview/skins/default/textures/toolbar_icons/facebook.png b/indra/newview/skins/default/textures/toolbar_icons/facebook.pngBinary files differ new file mode 100644 index 0000000000..b960b834dc --- /dev/null +++ b/indra/newview/skins/default/textures/toolbar_icons/facebook.png diff --git a/indra/newview/skins/default/xui/en/floater_fbc_web.xml b/indra/newview/skins/default/xui/en/floater_fbc_web.xml new file mode 100644 index 0000000000..0d35e22a19 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_fbc_web.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater name="floater_fbc_web" +         help_topic="fbc_web" +         width="780" +         height="775" +         save_rect="true" +         single_instance="true" +         reuse_instance="false" +         filename="floater_web_content.xml"/> diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml index 49d64767cc..853c209bca 100755 --- a/indra/newview/skins/default/xui/en/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml @@ -21,7 +21,11 @@          Sending Email      </string>      <string -     name="profile_progress_str"> +        name="facebook_progress_str"> +        Posting to Facebook +    </string> +    <string +        name="profile_progress_str">          Posting      </string>      <string @@ -33,7 +37,11 @@          Saving to Computer      </string>   	<string - 	 name="profile_succeeded_str"> +        name="facebook_succeeded_str"> + 	    Image uploaded + 	</string> + 	<string +        name="profile_succeeded_str">   	    Image uploaded   	</string>   	<string @@ -49,7 +57,11 @@   	    Saved to Computer!   	</string>   	<string - 	 name="profile_failed_str"> +        name="facebook_failed_str"> + 	    Failed to upload image to your Facebook timeline. + 	</string> + 	<string +        name="profile_failed_str">   	    Failed to upload image to your Profile Feed.   	</string>   	<string diff --git a/indra/newview/skins/default/xui/en/floater_social.xml b/indra/newview/skins/default/xui/en/floater_social.xml new file mode 100644 index 0000000000..426c5507e4 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_social.xml @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<floater +  positioning="cascading" +  can_close="true" +  can_resize="false" +  help_topic="social floater" +  layout="topleft" +  name="floater_social" +  save_rect="true" +  single_instance="true" +  reuse_instance="true" +  title="POST TO FACEBOOK" +  height="482" +  width="304"> +  <panel +   height="482" +   width="304" +   visible="true" +   name="background" +   follows="all" +   top="0" +   left="0"> +   <tab_container +     name="tabs" +     tab_group="1" +     tab_min_width="70" +     tab_height="30" +     tab_position="top" +     top="7" +     height="437" +     halign="center"> +     <panel +       filename="panel_social_status.xml" +       class="llsocialstatuspanel" +       follows="all" +       label="STATUS" +       help_topic="panel_social_status" +       name="panel_social_status"/> +     <panel +       filename="panel_social_photo.xml" +       class="llsocialphotopanel" +       follows="all" +       label="PHOTO" +       help_topic="panel_social_photo" +       name="panel_social_photo"/> +     <panel +       filename="panel_social_place.xml" +       class="llsocialcheckinpanel" +       follows="all" +       label="CHECK IN" +       help_topic="panel_social_place" +       name="panel_social_place"/> +     <panel +       filename="panel_social_account.xml" +       class="llsocialaccountpanel" +       follows="all" +       label="ACCOUNT" +       help_topic="panel_social_account" +       name="panel_social_account"/>      +    </tab_container> +    <panel +     name="connection_status_panel" +     follows="left|bottom|right" +     height="24"> +     <text +      name="connection_error_text" +      type="string" +      follows="left|bottom|right" +      top="5" +      left="9" +      width="250" +      height="20" +      wrap="true" +      halign="left" +      valign="center" +      text_color="DrYellow" +      font="SansSerif"> +      Error +     </text> +     <loading_indicator +      follows="left|bottom|right" +      height="24" +      width="24" +      name="connection_loading_indicator" +      top="2" +      left="9" +      visible="true"/> +     <text +      name="connection_loading_text" +      type="string" +      follows="left|bottom|right" +      top="5" +      left_pad="5" +      width="250" +      height="20" +      wrap="true" +      halign="left" +      valign="center" +      text_color="EmphasisColor" +      font="SansSerif"> +      Loading... +    </text> +  </panel> + </panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml index cea10adca8..a80440e844 100755 --- a/indra/newview/skins/default/xui/en/floater_web_content.xml +++ b/indra/newview/skins/default/xui/en/floater_web_content.xml @@ -125,10 +125,10 @@        <icon          name="media_secure_lock_flag"          height="16" -        follows="top|right" +        follows="top|left"          image_name="Lock2"          layout="topleft" -        left_delta="620" +        left_delta="2"          top_delta="2"          visible="false"           tool_tip="Secured Browsing" diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index f253ed3e06..1b0b857c22 100755 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -16,6 +16,14 @@           parameter="agent" />        </menu_item_call>        <menu_item_call +        label="Post to Facebook..." +        name="PostToFacebook"> +        <menu_item_call.on_click +          function="Floater.Toggle" +          parameter="social"/> +      </menu_item_call>       +      <menu_item_separator/> +      <menu_item_call         label="Appearance..."         name="ChangeOutfit">          <menu_item_call.on_click @@ -3030,6 +3038,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 ebd2799ebf..e8d3b85221 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6017,6 +6017,13 @@ Please select at least one type of content to search (General, Moderate, or Adul  [MESSAGE]    </notification> + <notification +  icon="notify.tga" +  name="FacebookConnect" +  type="notifytip"> +[MESSAGE] + </notification> +        <notification     icon="notify.tga"     name="PaymentReceived" diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index ed274d0233..dc0e4a5947 100755 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -365,6 +365,23 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M                           top="0"                           width="307" />                  </accordion_tab> +              <accordion_tab +               layout="topleft" +               height="173" +               name="tab_suggested_friends" +               title="People you may want to friend"> +                <avatar_list +                 ignore_online_status="true" +                 allow_select="true" +                 follows="all" +                 height="173" +                 layout="topleft" +                 left="0" +                 name="suggested_friends" +                 show_permissions_granted="true" +                 top="0" +                 width="307" /> +              </accordion_tab>                            </accordion>              <text               follows="all" diff --git a/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml index 198ccd6e2f..8f90521bb2 100755 --- a/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml +++ b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml @@ -315,7 +315,18 @@  		<line_editor.commit_callback  			function="MediaCtrl.CommitURL"/>  	  </line_editor> -	  <layout_stack +        <icon +        name="media_secure_lock_flag" +        height="16" +        follows="top|left" +        image_name="Lock2" +        layout="topleft" +        left_delta="2" +        top_delta="2" +        visible="false" +        tool_tip="Secured Browsing" +        width="16" /> +        <layout_stack  		  name="media_address_url_icons"  		  animate="false"  		  follows="top|right" @@ -340,19 +351,6 @@  			  tool_tip="White List enabled"  			  width="16" />  		</layout_panel> -		<layout_panel -			layout="topleft" -			width="16" -			mouse_opaque="false" -			auto_resize="false"> -		  <icon -			  name="media_secure_lock_flag" -			  height="16" -			  image_name="Lock2" -			  layout="topleft" -			  tool_tip="Secured Browsing" -			  width="16" /> -		</layout_panel>  	  </layout_stack>  	</layout_panel>  	<layout_panel diff --git a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml index d2f29ade44..61c8c971c2 100755 --- a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml @@ -16,11 +16,11 @@     imgoverlay_label_space="10"     label="Post to My Profile Feed"     layout="topleft" -   left="10" +   left_delta="0"     name="save_to_profile_btn"     pad_left="10"     right="-10" -   top="5"> +   top_pad="10">      <button.commit_callback       function="Snapshot.SaveToProfile" />    </button> diff --git a/indra/newview/skins/default/xui/en/panel_social_account.xml b/indra/newview/skins/default/xui/en/panel_social_account.xml new file mode 100644 index 0000000000..d7235396fe --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_social_account.xml @@ -0,0 +1,75 @@ +<panel +	 height="400" +	 width="304" +	 layout="topleft" +   name="panel_social_account"> +  <string +      name="facebook_connected" +      value="You are connected to Facebook as:" /> +  <string +      name="facebook_disconnected" +      value="Not connected to Facebook" /> +  <text +   layout="topleft" +   length="1" +   follows="top|left" +   font="SansSerif" +   height="16" +   left="9" +   name="account_caption_label" +   top="21" +   type="string"> +    Not connected to Facebook. +  </text> +  <text +   layout="topleft" +   top_pad="2" +   length="1" +   follows="top|left" +   font="SansSerif" +   height="16" +   left="9" +   name="account_name_label" +   parse_urls="true" +   type="string"/> +  <panel +    layout="topleft" +    name="panel_buttons" +    height="345" +    left="9"> +    <button +     layout="topleft" +     follows="left|top" +     top_pad="9" +     visible="true" +     height="23" +     label="Connect..." +     name="connect_btn" +     width="210"> +      <commit_callback function="SocialSharing.Connect"/> +    </button> + +    <button +     layout="topleft" +     follows="left|top" +     top_delta="0" +     height="23" +     label="Disconnect" +     name="disconnect_btn" +     width="210" +     visible="false"> +      <commit_callback function="SocialSharing.Disconnect"/> +    </button> +    <text +      layout="topleft" +      length="1" +      follows="top|left" +      height="16" +      left="0" +      name="account_learn_more_label" +      top_pad="20" +      type="string"> +      [http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share/ta-p/2149711 Learn about posting to Facebook] +    </text> +  </panel> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_social_photo.xml b/indra/newview/skins/default/xui/en/panel_social_photo.xml new file mode 100644 index 0000000000..a55613b52a --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_social_photo.xml @@ -0,0 +1,152 @@ +    <panel +      height="400" +      width="304" +      layout="topleft" +      name="panel_social_photo"> +      <layout_stack +	   layout="topleft" +       border_size="0" +       height="392" +       follows="all" +       orientation="vertical" +       name="stack_photo" +       top="8"> +        <layout_panel	 +         name="snapshot_panel" +         height="367"> +            <combo_box +             control_name="SocialPhotoResolution" +             follows="left|top" +             top="6" +             left="9" +             name="resolution_combobox" +             tool_tip="Image resolution" +             height="21" +             width="135"> +              <combo_box.item +               label="Current Window" +               name="CurrentWindow" +               value="[i0,i0]" /> +              <combo_box.item +               label="640x480" +               name="640x480" +               value="[i640,i480]" /> +              <combo_box.item +               label="800x600" +               name="800x600" +               value="[i800,i600]" /> +              <combo_box.item +               label="1024x768" +               name="1024x768" +               value="[i1024,i768]" /> +            </combo_box> +            <text +             follows="left|top" +             font="SansSerifSmall" +             height="14" +             left="208" +             length="1" +             halign="right" +             name="file_size_label" +             top="9" +             type="string" +             width="50"> +              [SIZE] KB +            </text> +            <panel +                height="150" +                width="250" +                visible="true" +                name="thumbnail_placeholder" +                top="33" +                follows="left|top" +                left="9"> +            </panel> +            <button +             follows="left|top" +             height="23" +             label="Refresh" +             left="9" +             top_pad="5" +             name="new_snapshot_btn" +             tool_tip="Click to refresh" +             visible="true" +             width="100" > +             <button.commit_callback +               function="SocialSharing.RefreshPhoto" /> +            </button> +            <text +                follows="left|top" +                font="SansSerif" +                text_color="EmphasisColor" +                height="14" +                top_pad="-19" +                left_pad="-20" +                length="1" +                halign="center" +                name="working_lbl" +                translate="false" +                type="string" +                visible="true" +                width="150"> +                Refreshing... +            </text> +            <text +             length="1" +             follows="top|left|right" +             font="SansSerif" +             height="16" +             left="9" +             name="caption_label" +             top_pad="20" +             type="string"> +              Comment (optional): +            </text> +            <text_editor +             follows="left|top" +             height="87" +             width="250" +             left="9" +             length="1" +             max_length="700" +             name="photo_caption" +             type="string" +             word_wrap="true"> +            </text_editor> +            <check_box +             follows="left|top" +             initial_value="true" +             label="Include location in posting" +             name="add_location_cb" +              left="9" +              height="16" +             top_pad="8"/> +        </layout_panel> +        <layout_panel +          name="photo_button_panel" +          height="25"> +          <button +           follows="left|top" +           top="0" +           left="9" +           height="23" +           label="Post" +           name="post_photo_btn" +           width="100"> +            <button.commit_callback +             function="SocialSharing.SendPhoto" /> +          </button> +          <button +               follows="left|top" +               height="23" +               label="Cancel" +               name="cancel_photo_btn" +               left_pad="15" +               top_delta="0" +               width="100"> +            <button.commit_callback +             function="SocialSharing.Cancel" /> +          </button>           +        </layout_panel>         +      </layout_stack> +    </panel> diff --git a/indra/newview/skins/default/xui/en/panel_social_place.xml b/indra/newview/skins/default/xui/en/panel_social_place.xml new file mode 100644 index 0000000000..13e94f6998 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_social_place.xml @@ -0,0 +1,132 @@ +    <panel +      height="400" +      width="304" +	  layout="topleft" +      name="panel_social_place"> +      <layout_stack +	    layout="topleft" +        border_size="0" +        height="392" +        follows="all" +        orientation="vertical" +        name="stack_place" +        top="8"> +        <layout_panel +          name="place_detail_panel" +          height="181"> +          <text +            length="1" +            follows="top|left|right" +            font="SansSerif" +            height="16" +            left="9" +            name="place_caption_label" +            top="13" +            type="string"> +            Say something about where you are: +          </text> +          <text_editor +            follows="top|left" +            height="150" +            width="250" +            left="9" +            length="1" +            max_length="700" +            name="place_caption" +            type="string" +            word_wrap="true"> +           </text_editor> +          </layout_panel> +          <layout_panel +            name="place_map_panel" +            height="186"> +              <panel +                  follows="left|top" +                  height="128" +                  width="128" +                  background_visible="true" +                  bg_opaque_color="Black" +                  bg_alpha_color="Black" +                  top="20" +                  left="9" +                  visible="true" +                  name="map_border"> +              </panel> +              <loading_indicator +              follows="left|top" +              height="24" +              width="24" +              name="map_loading_indicator" +              top="77" +              left="61" +              visible="true"/> +              <icon +                follows="left|top" +                height="128" +                width="128" +                image_name="Map_Placeholder_Icon" +                layout="topleft" +                top="20" +                left="9" +                visible="true" +                name="map_placeholder"> +              </icon> +              <icon +                  follows="left|top" +                  height="128" +                  width="128" +                  image_name="Map_Placeholder_Icon" +                  layout="topleft" +                  top="20" +                  left="9" +                  visible="true" +                  name="map_default"> +              </icon> +            <check_box +              follows="left|top" +              initial_value="false" +              top_delta="8" +              width="8" +              label="" +              name="add_place_view_cb" +              left_pad="5"/> +            <text +              follows="left|top" +              font="SansSerif" +              height="32" +              width="130" +              word_wrap="true" +              left_pad="12" +              top_delta="-8" +              type="string"> +              Include overhead view of location +            </text> +          </layout_panel> +          <layout_panel +            name="place_button_panel" +            height="25"> +            <button +              follows="left|top" +              top="0" +              left="9" +              height="23" +              label="Post" +              name="post_place_btn" +              width="100"> +              <button.commit_callback +                 function="SocialSharing.SendCheckin" /> +            </button> +            <button +              follows="left|top" +              height="23" +              label="Cancel" +              name="cancel_place_btn" +              left_pad="15" +              top_delta="0" +              width="100"> +              <button.commit_callback +                  function="SocialSharing.Cancel" /> +            </button> +        </layout_panel> +     </layout_stack> +    </panel> diff --git a/indra/newview/skins/default/xui/en/panel_social_status.xml b/indra/newview/skins/default/xui/en/panel_social_status.xml new file mode 100644 index 0000000000..54cfa3f524 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_social_status.xml @@ -0,0 +1,67 @@ +    <panel +	 height="400" +	 width="304" +	 layout="topleft" +     name="panel_social_status"> +     <layout_stack +      layout="topleft" +      border_size="0" +      height="392" +      follows="all" +      orientation="vertical" +      name="stack_status" +      top="8"> +      <layout_panel +       name="status_detail_panel" +       height="367"> +       <text +        length="1" +        follows="top|left|right" +        font="SansSerif" +        height="16" +        left="9" +        name="status_caption_label" +        top="13" +        type="string"> +        What's on your mind? +       </text> +       <text_editor +        follows="left|top" +        height="150" +        width="250" +        left="9" +        length="1" +        max_length="700" +        name="status_message" +        type="string" +        word_wrap="true"> +       </text_editor> +      </layout_panel> +      <layout_panel +       name="status_button_panel" +       height="25"> +       <button +        follows="left|top" +        top="0" +        left="9" +        height="23" +        label="Post" +        name="post_status_btn" +        width="100"> +        <button.commit_callback +          function="SocialSharing.SendStatus" /> +       </button> +       <button +        follows="left|top" +        height="23" +        label="Cancel" +        name="cancel_status_btn" +        left_pad="15" +        top_delta="0" +        width="100"> +        <button.commit_callback +          function="SocialSharing.Cancel" /> +       </button> +      </layout_panel> +     </layout_stack> +    </panel> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 73601ecb9f..518393f778 100755 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -148,6 +148,14 @@ Please try logging in again in a minute.</string>  	<string name="SentToInvalidRegion">You were sent to an invalid region.</string>  	<string name="TestingDisconnect">Testing viewer disconnect</string> +	<!-- Facebook Connect and, eventually, other Social Network --> +	<string name="SocialFacebookConnecting">Connecting to Facebook...</string> +	<string name="SocialFacebookPosting">Posting...</string> +	<string name="SocialFacebookDisconnecting">Disconnecting from Facebook...</string> +	<string name="SocialFacebookErrorConnecting">Problem connecting to Facebook</string> +	<string name="SocialFacebookErrorPosting">Problem posting to Facebook</string> +	<string name="SocialFacebookErrorDisconnecting">Problem disconnecting from Facebook</string> +      	<!-- Tooltip -->  	<string name="TooltipPerson">Person</string><!-- Object under mouse pointer is an avatar -->  	<string name="TooltipNoName">(no name)</string> <!-- No name on an object --> @@ -3424,6 +3432,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE].      Drag items from inventory here    </string> +  <string name="facebook_post_success"> +    You posted to Facebook. +  </string>    <string name="no_session_message">      (IM Session Doesn't Exist) @@ -3856,6 +3867,7 @@ Try enclosing path to the editor with double quotes.    <string name="Command_Profile_Label">Profile</string>    <string name="Command_Search_Label">Search</string>    <string name="Command_Snapshot_Label">Snapshot</string> +  <string name="Command_Social_Label">Facebook</string>    <string name="Command_Speak_Label">Speak</string>    <string name="Command_View_Label">Camera controls</string>    <string name="Command_Voice_Label">Voice settings</string> @@ -3883,6 +3895,7 @@ Try enclosing path to the editor with double quotes.    <string name="Command_Profile_Tooltip">Edit or view your profile</string>    <string name="Command_Search_Tooltip">Find places, events, people</string>    <string name="Command_Snapshot_Tooltip">Take a picture</string> +  <string name="Command_Social_Tooltip">Post to Facebook</string>    <string name="Command_Speak_Tooltip">Speak with people nearby using your microphone</string>    <string name="Command_View_Tooltip">Changing camera angle</string>    <string name="Command_Voice_Tooltip">Volume controls for calls and people near you in world</string> 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) {} | 
