diff options
Diffstat (limited to 'indra')
34 files changed, 3808 insertions, 78 deletions
| diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 1fea6dea9f..746991a6f0 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -199,6 +199,7 @@ set(viewer_SOURCE_FILES      llfilteredwearablelist.cpp      llfirstuse.cpp      llflexibleobject.cpp +    llflickrconnect.cpp      llfloaterabout.cpp      llfloaterbvhpreview.cpp      llfloaterauction.cpp @@ -228,6 +229,7 @@ set(viewer_SOURCE_FILES      llfloatereditwater.cpp      llfloaterenvironmentsettings.cpp      llfloaterevent.cpp +    llfloaterflickr.cpp      llfloaterfonttest.cpp      llfloatergesture.cpp      llfloatergodtools.cpp @@ -286,6 +288,7 @@ set(viewer_SOURCE_FILES      llfloatertos.cpp      llfloatertoybox.cpp      llfloatertranslationsettings.cpp +    llfloatertwitter.cpp      llfloateruipreview.cpp      llfloaterurlentry.cpp      llfloatervoiceeffect.cpp @@ -567,6 +570,7 @@ set(viewer_SOURCE_FILES      lltransientdockablefloater.cpp      lltransientfloatermgr.cpp      lltranslate.cpp +    lltwitterconnect.cpp      lluilistener.cpp      lluploaddialog.cpp      lluploadfloaterobservers.cpp @@ -787,6 +791,7 @@ set(viewer_HEADER_FILES      llfilteredwearablelist.h      llfirstuse.h      llflexibleobject.h +    llflickrconnect.h      llfloaterabout.h      llfloaterbvhpreview.h      llfloaterauction.h @@ -816,6 +821,7 @@ set(viewer_HEADER_FILES      llfloatereditwater.h      llfloaterenvironmentsettings.h      llfloaterevent.h +    llfloaterflickr.h      llfloaterfonttest.h      llfloatergesture.h      llfloatergodtools.h @@ -874,6 +880,7 @@ set(viewer_HEADER_FILES      llfloatertos.h      llfloatertoybox.h      llfloatertranslationsettings.h +    llfloatertwitter.h      llfloateruipreview.h      llfloaterurlentry.h      llfloatervoiceeffect.h @@ -1145,6 +1152,7 @@ set(viewer_HEADER_FILES      lltransientdockablefloater.h      lltransientfloatermgr.h      lltranslate.h +    lltwitterconnect.h      lluiconstants.h      lluilistener.h      lluploaddialog.h diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index 60c942094a..f4e9cc0136 100755 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -226,6 +226,26 @@             is_running_function="Floater.IsOpen"             is_running_parameters="social"             /> +  <command name="flickr" +           available_in_toybox="true" +           icon="Command_Flickr_Icon" +           label_ref="Command_Flickr_Label" +           tooltip_ref="Command_Flickr_Tooltip" +           execute_function="Floater.ToggleOrBringToFront" +           execute_parameters="flickr" +           is_running_function="Floater.IsOpen" +           is_running_parameters="flickr" +           /> +  <command name="twitter" +           available_in_toybox="true" +           icon="Command_Twitter_Icon" +           label_ref="Command_Twitter_Label" +           tooltip_ref="Command_Twitter_Tooltip" +           execute_function="Floater.ToggleOrBringToFront" +           execute_parameters="twitter" +           is_running_function="Floater.IsOpen" +           is_running_parameters="twitter" +           />    <command name="speak"             available_in_toybox="true"             icon="Command_Speak_Icon" diff --git a/indra/newview/app_settings/toolbars.xml b/indra/newview/app_settings/toolbars.xml index 86f9912815..c65b79affb 100755 --- a/indra/newview/app_settings/toolbars.xml +++ b/indra/newview/app_settings/toolbars.xml @@ -6,7 +6,6 @@      <command name="speak"/>      <command name="destinations"/>      <command name="people"/> -    <command name="social"/>      <command name="profile"/>      <command name="move"/>      <command name="view"/> @@ -22,5 +21,6 @@      <command name="voice"/>      <command name="minimap"/>      <command name="snapshot"/> +    <command name="social"/>    </left_toolbar>  </toolbars> diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp index f82c5a05a0..0a662b4671 100644 --- a/indra/newview/llfacebookconnect.cpp +++ b/indra/newview/llfacebookconnect.cpp @@ -28,6 +28,8 @@  #include "llviewerprecompiledheaders.h"  #include "llfacebookconnect.h" +#include "llflickrconnect.h" +#include "lltwitterconnect.h"  #include "llagent.h"  #include "llcallingcard.h"			// for LLAvatarTracker @@ -58,7 +60,7 @@ void log_facebook_connect_error(const std::string& request, U32 status, const st      }  } -void toast_user_for_success() +void toast_user_for_facebook_success()  {  	LLSD args;      args["MESSAGE"] = LLTrans::getString("facebook_post_success"); @@ -74,23 +76,58 @@ public:  	bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)  	{ -		if (tokens.size() > 0) +		if (tokens.size() >= 1)  		{  			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) +				if (tokens.size() >= 2 && tokens[1].asString() == "flickr")  				{ -					fbc_web->closeFloater(); +					// this command probably came from the flickr_web browser, so close it +					LLFloater* flickr_web = LLFloaterReg::getInstance("flickr_web"); +					if (flickr_web) +					{ +						flickr_web->closeFloater(); +					} + +					// connect to flickr +					if (query_map.has("oauth_token")) +					{ +						LLFlickrConnect::instance().connectToFlickr(query_map["oauth_token"], query_map.get("oauth_verifier")); +					} +					return true;  				} - -				// connect to facebook -				if (query_map.has("code")) +				else if (tokens.size() >= 2 && tokens[1].asString() == "twitter") +				{ +					// this command probably came from the twitter_web browser, so close it +					LLFloater* twitter_web = LLFloaterReg::getInstance("twitter_web"); +					if (twitter_web) +					{ +						twitter_web->closeFloater(); +					} + +					// connect to twitter +					if (query_map.has("oauth_token")) +					{ +						LLTwitterConnect::instance().connectToTwitter(query_map["oauth_token"], query_map.get("oauth_verifier")); +					} +					return true; +				} +				else //if (tokens.size() >= 2 && tokens[1].asString() == "facebook")  				{ -                    LLFacebookConnect::instance().connectToFacebook(query_map["code"], query_map.get("state")); +					// 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 true;  			}  		}  		return false; @@ -150,7 +187,7 @@ public:  	{  		if (isGoodStatus(status))  		{ -            toast_user_for_success(); +            toast_user_for_facebook_success();  			LL_DEBUGS("FacebookConnect") << "Post successful. content: " << content << LL_ENDL;  			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED); @@ -371,40 +408,6 @@ std::string LLFacebookConnect::getFacebookConnectURL(const std::string& route, b  	return url;  } -std::string LLFacebookConnect::getFlickrConnectURL(const std::string& route, bool include_read_from_master) -{ -    std::string url(""); -    LLViewerRegion *regionp = gAgent.getRegion(); -    if (regionp) -    { -        url = regionp->getCapability("FlickrConnect"); -        url += route; -     -        if (include_read_from_master && mReadFromMaster) -        { -            url += "?read_from_master=true"; -        } -    } -	return url; -} - -std::string LLFacebookConnect::getTwitterConnectURL(const std::string& route, bool include_read_from_master) -{ -    std::string url(""); -    LLViewerRegion *regionp = gAgent.getRegion(); -    if (regionp) -    { -        url = regionp->getCapability("TwitterConnect"); -        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; @@ -431,11 +434,6 @@ void LLFacebookConnect::checkConnectionToFacebook(bool auto_connect)  	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;  	LLHTTPClient::get(getFacebookConnectURL("/connection", true), new LLFacebookConnectedResponder(auto_connect),  						LLSD(), timeout, follow_redirects); -	 -	// TEMPORARY FOR TESTING - CHO -	llinfos << "FlickrConnect URL: " << getFlickrConnectURL() << LL_ENDL; -	llinfos << "TwitterConnect URL: " << getTwitterConnectURL() << LL_ENDL; -  }  void LLFacebookConnect::loadFacebookInfo() diff --git a/indra/newview/llfacebookconnect.h b/indra/newview/llfacebookconnect.h index c4117174c1..c157db2178 100644 --- a/indra/newview/llfacebookconnect.h +++ b/indra/newview/llfacebookconnect.h @@ -90,10 +90,6 @@ private:  	~LLFacebookConnect() {};   	std::string getFacebookConnectURL(const std::string& route = "", bool include_read_from_master = false); -	// TEMPORARY FOR TESTING - CHO - 	std::string getFlickrConnectURL(const std::string& route = "", bool include_read_from_master = false); - 	std::string getTwitterConnectURL(const std::string& route = "", bool include_read_from_master = false); -         EConnectionState mConnectionState;  	BOOL mConnected;  	LLSD mInfo; diff --git a/indra/newview/llflickrconnect.cpp b/indra/newview/llflickrconnect.cpp new file mode 100644 index 0000000000..3a21933b63 --- /dev/null +++ b/indra/newview/llflickrconnect.cpp @@ -0,0 +1,477 @@ +/**  + * @file llflickrconnect.h + * @author Merov, Cho + * @brief Connection to Flickr 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 "llflickrconnect.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> LLFlickrConnect::sStateWatcher(new LLEventStream("FlickrConnectState")); +boost::scoped_ptr<LLEventPump> LLFlickrConnect::sInfoWatcher(new LLEventStream("FlickrConnectInfo")); +boost::scoped_ptr<LLEventPump> LLFlickrConnect::sContentWatcher(new LLEventStream("FlickrConnectContent")); + +// Local functions +void log_flickr_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("FlickrConnect") << request << " request failed with a " << status << " " << reason << ". Reason: " << code << " (" << description << ")" << LL_ENDL; +    } +} + +void toast_user_for_flickr_success() +{ +	LLSD args; +    args["MESSAGE"] = LLTrans::getString("flickr_post_success"); +    LLNotificationsUtil::add("FlickrConnect", args); +} + +/////////////////////////////////////////////////////////////////////////////// +// +class LLFlickrConnectResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLFlickrConnectResponder); +public: +	 +    LLFlickrConnectResponder() +    { +        LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS); +    } +     +	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (isGoodStatus(status)) +		{ +			LL_DEBUGS("FlickrConnect") << "Connect successful. content: " << content << LL_ENDL; +			 +            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTED); +		} +		else if (status != 302) +		{ +            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); +            log_flickr_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) +        { +            LLFlickrConnect::instance().openFlickrWeb(content["location"]); +        } +    } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +class LLFlickrShareResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLFlickrShareResponder); +public: +     +	LLFlickrShareResponder() +	{ +		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POSTING); +	} +	 +	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (isGoodStatus(status)) +		{ +            toast_user_for_flickr_success(); +			LL_DEBUGS("FlickrConnect") << "Post successful. content: " << content << LL_ENDL; +			 +			LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POSTED); +		} +		else if (status == 404) +		{ +			LLFlickrConnect::instance().connectToFlickr(); +		} +		else +		{ +            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POST_FAILED); +            log_flickr_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) +        { +            LLFlickrConnect::instance().openFlickrWeb(content["location"]); +        } +    } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +class LLFlickrDisconnectResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLFlickrDisconnectResponder); +public: +  +	LLFlickrDisconnectResponder() +	{ +		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_DISCONNECTING); +	} + +	void setUserDisconnected() +	{ +		// Clear data +		LLFlickrConnect::instance().clearInfo(); + +		//Notify state change +		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED); +	} + +	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (isGoodStatus(status))  +		{ +			LL_DEBUGS("FlickrConnect") << "Disconnect successful. content: " << content << LL_ENDL; +			setUserDisconnected(); + +		} +		//User not found so already disconnected +		else if(status == 404) +		{ +			LL_DEBUGS("FlickrConnect") << "Already disconnected. content: " << content << LL_ENDL; +			setUserDisconnected(); +		} +		else +		{ +			LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_DISCONNECT_FAILED); +            log_flickr_connect_error("Disconnect", status, reason, content.get("error_code"), content.get("error_description")); +		} +	} +}; + +/////////////////////////////////////////////////////////////////////////////// +// +class LLFlickrConnectedResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLFlickrConnectedResponder); +public: +     +	LLFlickrConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect) +    { +		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS); +    } +     +	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (isGoodStatus(status)) +		{ +			LL_DEBUGS("FlickrConnect") << "Connect successful. content: " << content << LL_ENDL; +             +            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTED); +		} +		else +		{ +			// show the flickr login page if not connected yet +			if (status == 404) +			{ +				if (mAutoConnect) +				{ +					LLFlickrConnect::instance().connectToFlickr(); +				} +				else +				{ +					LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED); +				} +			} +            else +            { +                LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); +				log_flickr_connect_error("Connected", status, reason, content.get("error_code"), content.get("error_description")); +            } +		} +	} +     +private: +	bool mAutoConnect; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +class LLFlickrInfoResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLFlickrInfoResponder); +public: + +	virtual void completed(U32 status, const std::string& reason, const LLSD& info) +	{ +		if (isGoodStatus(status)) +		{ +			llinfos << "Flickr: Info received" << llendl; +			LL_DEBUGS("FlickrConnect") << "Getting Flickr info successful. info: " << info << LL_ENDL; +			LLFlickrConnect::instance().storeInfo(info); +		} +		else +		{ +			log_flickr_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) +		{ +			LLFlickrConnect::instance().openFlickrWeb(content["location"]); +		} +	} +}; + +/////////////////////////////////////////////////////////////////////////////// +// +LLFlickrConnect::LLFlickrConnect() +:	mConnectionState(FLICKR_NOT_CONNECTED), +	mConnected(false), +	mInfo(), +	mRefreshInfo(false), +	mReadFromMaster(false) +{ +} + +void LLFlickrConnect::openFlickrWeb(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("flickr_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 "flickr_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. +	//flickr_web floater contains the "webbrowser" panel.    JIRA: ACME-744 +	gFocusMgr.setKeyboardFocus( floater ); + +	//LLUrlAction::openURLExternal(url); +} + +std::string LLFlickrConnect::getFlickrConnectURL(const std::string& route, bool include_read_from_master) +{ +    std::string url(""); +    LLViewerRegion *regionp = gAgent.getRegion(); +    if (regionp) +    { +		//url = "http://pdp15.lindenlab.com/flickr/agent/" + gAgentID.asString(); // TEMPORARY FOR TESTING - CHO +        url = regionp->getCapability("FlickrConnect"); +        url += route; +     +        if (include_read_from_master && mReadFromMaster) +        { +            url += "?read_from_master=true"; +        } +    } +	return url; +} + +void LLFlickrConnect::connectToFlickr(const std::string& request_token, const std::string& oauth_verifier) +{ +	LLSD body; +	if (!request_token.empty()) +		body["request_token"] = request_token; +	if (!oauth_verifier.empty()) +		body["oauth_verifier"] = oauth_verifier; +     +	LLHTTPClient::put(getFlickrConnectURL("/connection"), body, new LLFlickrConnectResponder()); +} + +void LLFlickrConnect::disconnectFromFlickr() +{ +	LLHTTPClient::del(getFlickrConnectURL("/connection"), new LLFlickrDisconnectResponder()); +} + +void LLFlickrConnect::checkConnectionToFlickr(bool auto_connect) +{ +	const bool follow_redirects = false; +	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	LLHTTPClient::get(getFlickrConnectURL("/connection", true), new LLFlickrConnectedResponder(auto_connect), +						LLSD(), timeout, follow_redirects); +} + +void LLFlickrConnect::loadFlickrInfo() +{ +	if(mRefreshInfo) +	{ +		const bool follow_redirects = false; +		const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +		LLHTTPClient::get(getFlickrConnectURL("/info", true), new LLFlickrInfoResponder(), +			LLSD(), timeout, follow_redirects); +	} +} + +void LLFlickrConnect::uploadPhoto(const std::string& image_url, const std::string& title, const std::string& description, const std::string& tags, int safety_level) +{ +	LLSD body; +	body["image"] = image_url; +	body["title"] = title; +	body["description"] = description; +	body["tags"] = tags; +	body["safety_level"] = safety_level; +	 +    // Note: we can use that route for different publish action. We should be able to use the same responder. +	LLHTTPClient::post(getFlickrConnectURL("/share/photo", true), body, new LLFlickrShareResponder()); +} + +void LLFlickrConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& title, const std::string& description, const std::string& tags, int safety_level) +{ +	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=\"title\"\r\n\r\n" +			<< title << "\r\n"; + +	body	<< "--" << boundary << "\r\n" +			<< "Content-Disposition: form-data; name=\"description\"\r\n\r\n" +			<< description << "\r\n"; + +	body	<< "--" << boundary << "\r\n" +			<< "Content-Disposition: form-data; name=\"tags\"\r\n\r\n" +			<< tags << "\r\n"; + +	body	<< "--" << boundary << "\r\n" +			<< "Content-Disposition: form-data; name=\"safety_level\"\r\n\r\n" +			<< safety_level << "\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(getFlickrConnectURL("/share/photo", true), data, size, new LLFlickrShareResponder(), headers); +} + +void LLFlickrConnect::storeInfo(const LLSD& info) +{ +	mInfo = info; +	mRefreshInfo = false; + +	sInfoWatcher->post(info); +} + +const LLSD& LLFlickrConnect::getInfo() const +{ +	return mInfo; +} + +void LLFlickrConnect::clearInfo() +{ +	mInfo = LLSD(); +} + +void LLFlickrConnect::setDataDirty() +{ +	mRefreshInfo = true; +} + +void LLFlickrConnect::setConnectionState(LLFlickrConnect::EConnectionState connection_state) +{ +	if(connection_state == FLICKR_CONNECTED) +	{ +		mReadFromMaster = true; +		setConnected(true); +		setDataDirty(); +	} +	else if(connection_state == FLICKR_NOT_CONNECTED) +	{ +		setConnected(false); +	} +	else if(connection_state == FLICKR_POSTED) +	{ +		mReadFromMaster = false; +	} + +	if (mConnectionState != connection_state) +	{ +		LLSD state_info; +		state_info["enum"] = connection_state; +		sStateWatcher->post(state_info); +	} +	 +	mConnectionState = connection_state; +} + +void LLFlickrConnect::setConnected(bool connected) +{ +	mConnected = connected; +} diff --git a/indra/newview/llflickrconnect.h b/indra/newview/llflickrconnect.h new file mode 100644 index 0000000000..b127e6e104 --- /dev/null +++ b/indra/newview/llflickrconnect.h @@ -0,0 +1,98 @@ +/**  + * @file llflickrconnect.h + * @author Merov, Cho + * @brief Connection to Flickr 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_LLFLICKRCONNECT_H +#define LL_LLFLICKRCONNECT_H + +#include "llsingleton.h" +#include "llimage.h" + +class LLEventPump; + +/** + * @class LLFlickrConnect + * + * Manages authentication to, and interaction with, a web service allowing the + * the viewer to upload photos to Flickr. + */ +class LLFlickrConnect : public LLSingleton<LLFlickrConnect> +{ +	LOG_CLASS(LLFlickrConnect); +public: +    enum EConnectionState +	{ +		FLICKR_NOT_CONNECTED = 0, +		FLICKR_CONNECTION_IN_PROGRESS = 1, +		FLICKR_CONNECTED = 2, +		FLICKR_CONNECTION_FAILED = 3, +		FLICKR_POSTING = 4, +		FLICKR_POSTED = 5, +		FLICKR_POST_FAILED = 6, +		FLICKR_DISCONNECTING = 7, +		FLICKR_DISCONNECT_FAILED = 8 +	}; +	 +	void connectToFlickr(const std::string& request_token = "", const std::string& oauth_verifier = "");	// Initiate the complete Flickr connection. Please use checkConnectionToFlickr() in normal use. +	void disconnectFromFlickr();																			// Disconnect from the Flickr service. +    void checkConnectionToFlickr(bool auto_connect = false);												// Check if an access token is available on the Flickr service. If not, call connectToFlickr(). +     +	void loadFlickrInfo(); +	void uploadPhoto(const std::string& image_url, const std::string& title, const std::string& description, const std::string& tags, int safety_level); +	void uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& title, const std::string& description, const std::string& tags, int safety_level); +	 +	void storeInfo(const LLSD& info); +	const LLSD& getInfo() const; +	void clearInfo(); +	void setDataDirty(); +     +    void setConnectionState(EConnectionState connection_state); +	void setConnected(bool connected); +	bool isConnected() { return mConnected; } +	bool isTransactionOngoing() { return ((mConnectionState == FLICKR_CONNECTION_IN_PROGRESS) || (mConnectionState == FLICKR_POSTING) || (mConnectionState == FLICKR_DISCONNECTING)); } +    EConnectionState getConnectionState() { return mConnectionState; } +     +    void openFlickrWeb(std::string url); + +private: +	friend class LLSingleton<LLFlickrConnect>; + +	LLFlickrConnect(); +	~LLFlickrConnect() {}; + 	std::string getFlickrConnectURL(const std::string& route = "", bool include_read_from_master = false); + +    EConnectionState mConnectionState; +	BOOL mConnected; +	LLSD mInfo; +	bool mRefreshInfo; +	bool mReadFromMaster; +	 +	static boost::scoped_ptr<LLEventPump> sStateWatcher; +	static boost::scoped_ptr<LLEventPump> sInfoWatcher; +	static boost::scoped_ptr<LLEventPump> sContentWatcher; +}; + +#endif // LL_LLFLICKRCONNECT_H diff --git a/indra/newview/llfloaterflickr.cpp b/indra/newview/llfloaterflickr.cpp new file mode 100644 index 0000000000..61ebe563a3 --- /dev/null +++ b/indra/newview/llfloaterflickr.cpp @@ -0,0 +1,703 @@ +/**  +* @file llfloaterflickr.cpp +* @brief Implementation of llfloaterflickr +* @author cho@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 "llfloaterflickr.h" + +#include "llagent.h" +#include "llagentui.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llflickrconnect.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" +#include "lltabcontainer.h" + +static LLRegisterPanelClassWrapper<LLFlickrPhotoPanel> t_panel_photo("llflickrphotopanel"); +static LLRegisterPanelClassWrapper<LLFlickrAccountPanel> t_panel_account("llflickraccountpanel"); + +const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte +const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=flickr&utm_medium=photo&utm_campaign=slshare"; +const std::string DEFAULT_PHOTO_LINK_TEXT = "Visit this location now"; +const std::string DEFAULT_TAG_TEXT = "secondlife "; + +/////////////////////////// +//LLFlickrPhotoPanel/////// +/////////////////////////// + +LLFlickrPhotoPanel::LLFlickrPhotoPanel() : +mSnapshotPanel(NULL), +mResolutionComboBox(NULL), +mRefreshBtn(NULL), +mWorkingLabel(NULL), +mThumbnailPlaceholder(NULL), +mTitleTextBox(NULL), +mDescriptionTextBox(NULL), +mLocationCheckbox(NULL), +mTagsTextBox(NULL), +mRatingComboBox(NULL), +mPostButton(NULL) +{ +	mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLFlickrPhotoPanel::onSend, this)); +	mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLFlickrPhotoPanel::onClickNewSnapshot, this)); +} + +LLFlickrPhotoPanel::~LLFlickrPhotoPanel() +{ +	if(mPreviewHandle.get()) +	{ +		mPreviewHandle.get()->die(); +	} +} + +BOOL LLFlickrPhotoPanel::postBuild() +{ +	setVisibleCallback(boost::bind(&LLFlickrPhotoPanel::onVisibilityChange, this, _2)); +	 +	mSnapshotPanel = getChild<LLUICtrl>("snapshot_panel"); +	mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox"); +	mResolutionComboBox->setCommitCallback(boost::bind(&LLFlickrPhotoPanel::updateResolution, this, TRUE)); +	mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn"); +    mWorkingLabel = getChild<LLUICtrl>("working_lbl"); +	mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder"); +	mTitleTextBox = getChild<LLUICtrl>("photo_title"); +	mDescriptionTextBox = getChild<LLUICtrl>("photo_description"); +	mLocationCheckbox = getChild<LLUICtrl>("add_location_cb"); +	mTagsTextBox = getChild<LLUICtrl>("photo_tags"); +	mTagsTextBox->setValue(DEFAULT_TAG_TEXT); +	mRatingComboBox = getChild<LLUICtrl>("rating_combobox"); +	mPostButton = getChild<LLUICtrl>("post_photo_btn"); +	mCancelButton = getChild<LLUICtrl>("cancel_photo_btn"); + +	return LLPanel::postBuild(); +} + +void LLFlickrPhotoPanel::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 = !(LLFlickrConnect::instance().isTransactionOngoing()); +    mCancelButton->setEnabled(no_ongoing_connection); +    mTitleTextBox->setEnabled(no_ongoing_connection); +    mDescriptionTextBox->setEnabled(no_ongoing_connection); +    mTagsTextBox->setEnabled(no_ongoing_connection); +    mRatingComboBox->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()) && (mRatingComboBox && mRatingComboBox->getValue().isDefined())); +     +    // Draw the rest of the panel on top of it +	LLPanel::draw(); +} + +LLSnapshotLivePreview* LLFlickrPhotoPanel::getPreviewView() +{ +	LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get(); +	return previewp; +} + +void LLFlickrPhotoPanel::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 LLFlickrPhotoPanel::onClickNewSnapshot() +{ +	LLSnapshotLivePreview* previewp = getPreviewView(); +	if (previewp) +	{ +		//setStatus(Impl::STATUS_READY); +		lldebugs << "updating snapshot" << llendl; +		previewp->updateSnapshot(TRUE); +	} +} + +void LLFlickrPhotoPanel::onSend() +{ +	LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrPhotoPanel"); // just in case it is already listening +	LLEventPumps::instance().obtain("FlickrConnectState").listen("LLFlickrPhotoPanel", boost::bind(&LLFlickrPhotoPanel::onFlickrConnectStateChange, this, _1)); +	 +	// Connect to Flickr if necessary and then post +	if (LLFlickrConnect::instance().isConnected()) +	{ +		sendPhoto(); +	} +	else +	{ +		LLFlickrConnect::instance().checkConnectionToFlickr(true); +	} +} + +bool LLFlickrPhotoPanel::onFlickrConnectStateChange(const LLSD& data) +{ +	switch (data.get("enum").asInteger()) +	{ +		case LLFlickrConnect::FLICKR_CONNECTED: +			sendPhoto(); +			break; + +		case LLFlickrConnect::FLICKR_POSTED: +			LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrPhotoPanel"); +			clearAndClose(); +			break; +	} + +	return false; +} + +void LLFlickrPhotoPanel::sendPhoto() +{ +	// Get the title, description, and tags +	std::string title = mTitleTextBox->getValue().asString(); +	std::string description = mDescriptionTextBox->getValue().asString(); +	std::string tags = mTagsTextBox->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; + +		slurl_string = "<a href=\"" + slurl_string + "\">" + DEFAULT_PHOTO_LINK_TEXT + "</a>"; + +		// Add it to the description (pretty crude, but we don't have a better option with photos) +		if (description.empty()) +			description = slurl_string; +		else +			description = description + "\n\n" + slurl_string; +	} + +	// Get the content rating +	int content_rating = mRatingComboBox->getValue().asInteger(); + +	// Get the image +	LLSnapshotLivePreview* previewp = getPreviewView(); +	 +	// Post to Flickr +	LLFlickrConnect::instance().uploadPhoto(previewp->getFormattedImage(), title, description, tags, content_rating); + +	updateControls(); +} + +void LLFlickrPhotoPanel::clearAndClose() +{ +	mTitleTextBox->setValue(""); +	mDescriptionTextBox->setValue(""); +	mTagsTextBox->setValue(DEFAULT_TAG_TEXT); + +	LLFloater* floater = getParentByType<LLFloater>(); +	if (floater) +	{ +		floater->closeFloater(); +	} +} + +void LLFlickrPhotoPanel::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 LLFlickrPhotoPanel::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(); +                LLFlickrPhotoPanel::onClickNewSnapshot(); +			} +		} +		 +	} +} + +void LLFlickrPhotoPanel::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* LLFlickrPhotoPanel::getRefreshBtn() +{ +	return mRefreshBtn; +} + +/////////////////////////// +//LLFlickrAccountPanel////// +/////////////////////////// + +LLFlickrAccountPanel::LLFlickrAccountPanel() :  +mAccountCaptionLabel(NULL), +mAccountNameLabel(NULL), +mPanelButtons(NULL), +mConnectButton(NULL), +mDisconnectButton(NULL) +{ +	mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLFlickrAccountPanel::onConnect, this)); +	mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLFlickrAccountPanel::onDisconnect, this)); + +	setVisibleCallback(boost::bind(&LLFlickrAccountPanel::onVisibilityChange, this, _2)); +} + +BOOL LLFlickrAccountPanel::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 LLFlickrAccountPanel::draw() +{ +	LLFlickrConnect::EConnectionState connection_state = LLFlickrConnect::instance().getConnectionState(); + +	//Disable the 'disconnect' button and the 'use another account' button when disconnecting in progress +	bool disconnecting = connection_state == LLFlickrConnect::FLICKR_DISCONNECTING; +	mDisconnectButton->setEnabled(!disconnecting); + +	//Disable the 'connect' button when a connection is in progress +	bool connecting = connection_state == LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS; +	mConnectButton->setEnabled(!connecting); + +	LLPanel::draw(); +} + +void LLFlickrAccountPanel::onVisibilityChange(const LLSD& new_visibility) +{ +	bool visible = new_visibility.asBoolean(); + +	if(visible) +	{ +		LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrAccountPanel"); +		LLEventPumps::instance().obtain("FlickrConnectState").listen("LLFlickrAccountPanel", boost::bind(&LLFlickrAccountPanel::onFlickrConnectStateChange, this, _1)); + +		LLEventPumps::instance().obtain("FlickrConnectInfo").stopListening("LLFlickrAccountPanel"); +		LLEventPumps::instance().obtain("FlickrConnectInfo").listen("LLFlickrAccountPanel", boost::bind(&LLFlickrAccountPanel::onFlickrConnectInfoChange, this)); + +		//Connected +		if(LLFlickrConnect::instance().isConnected()) +		{ +			showConnectedLayout(); +		} +		//Check if connected (show disconnected layout in meantime) +		else +		{ +			showDisconnectedLayout(); +		} +        if ((LLFlickrConnect::instance().getConnectionState() == LLFlickrConnect::FLICKR_NOT_CONNECTED) || +            (LLFlickrConnect::instance().getConnectionState() == LLFlickrConnect::FLICKR_CONNECTION_FAILED)) +        { +            LLFlickrConnect::instance().checkConnectionToFlickr(); +        } +	} +	else +	{ +		LLEventPumps::instance().obtain("FlickrConnectState").stopListening("LLFlickrAccountPanel"); +		LLEventPumps::instance().obtain("FlickrConnectInfo").stopListening("LLFlickrAccountPanel"); +	} +} + +bool LLFlickrAccountPanel::onFlickrConnectStateChange(const LLSD& data) +{ +	if(LLFlickrConnect::instance().isConnected()) +	{ +		//In process of disconnecting so leave the layout as is +		if(data.get("enum").asInteger() != LLFlickrConnect::FLICKR_DISCONNECTING) +		{ +			showConnectedLayout(); +		} +	} +	else +	{ +		showDisconnectedLayout(); +	} + +	return false; +} + +bool LLFlickrAccountPanel::onFlickrConnectInfoChange() +{ +	LLSD info = LLFlickrConnect::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 LLFlickrAccountPanel::showConnectButton() +{ +	if(!mConnectButton->getVisible()) +	{ +		mConnectButton->setVisible(TRUE); +		mDisconnectButton->setVisible(FALSE); +	} +} + +void LLFlickrAccountPanel::hideConnectButton() +{ +	if(mConnectButton->getVisible()) +	{ +		mConnectButton->setVisible(FALSE); +		mDisconnectButton->setVisible(TRUE); +	} +} + +void LLFlickrAccountPanel::showDisconnectedLayout() +{ +	mAccountCaptionLabel->setText(getString("flickr_disconnected")); +	mAccountNameLabel->setText(std::string("")); +	showConnectButton(); +} + +void LLFlickrAccountPanel::showConnectedLayout() +{ +	LLFlickrConnect::instance().loadFlickrInfo(); + +	mAccountCaptionLabel->setText(getString("flickr_connected")); +	hideConnectButton(); +} + +void LLFlickrAccountPanel::onConnect() +{ +	LLFlickrConnect::instance().checkConnectionToFlickr(true); + +	//Clear only the flickr browser cookies so that the flickr login screen appears +	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".flickr.com");  +} + +void LLFlickrAccountPanel::onDisconnect() +{ +	LLFlickrConnect::instance().disconnectFromFlickr(); + +	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".flickr.com");  +} + +//////////////////////// +//LLFloaterFlickr/////// +//////////////////////// + +LLFloaterFlickr::LLFloaterFlickr(const LLSD& key) : LLFloater(key), +    mSocialPhotoPanel(NULL), +    mStatusErrorText(NULL), +    mStatusLoadingText(NULL), +    mStatusLoadingIndicator(NULL) +{ +	mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterFlickr::onCancel, this)); +} + +void LLFloaterFlickr::onCancel() +{ +    closeFloater(); +} + +BOOL LLFloaterFlickr::postBuild() +{ +    // Keep tab of the Photo Panel +	mSocialPhotoPanel = static_cast<LLFlickrPhotoPanel*>(getChild<LLUICtrl>("panel_flickr_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(); +} + +void LLFloaterFlickr::showPhotoPanel() +{ +	LLTabContainer* parent = dynamic_cast<LLTabContainer*>(mSocialPhotoPanel->getParent()); +	if (!parent) +	{ +		llwarns << "Cannot find panel container" << llendl; +		return; +	} + +	parent->selectTabPanel(mSocialPhotoPanel); +} + +// static +void LLFloaterFlickr::preUpdate() +{ +	LLFloaterFlickr* instance = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr"); +	if (instance) +	{ +		//Will set file size text to 'unknown' +		instance->mSocialPhotoPanel->updateControls(); +	} +} + +// static +void LLFloaterFlickr::postUpdate() +{ +	LLFloaterFlickr* instance = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr"); +	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 LLFloaterFlickr::draw() +{ +    if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator) +    { +        mStatusErrorText->setVisible(false); +        mStatusLoadingText->setVisible(false); +        mStatusLoadingIndicator->setVisible(false); +        LLFlickrConnect::EConnectionState connection_state = LLFlickrConnect::instance().getConnectionState(); +        std::string status_text; +         +        switch (connection_state) +        { +        case LLFlickrConnect::FLICKR_NOT_CONNECTED: +            // No status displayed when first opening the panel and no connection done +        case LLFlickrConnect::FLICKR_CONNECTED: +            // When successfully connected, no message is displayed +        case LLFlickrConnect::FLICKR_POSTED: +            // No success message to show since we actually close the floater after successful posting completion +            break; +        case LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS: +            // Connection loading indicator +            mStatusLoadingText->setVisible(true); +            status_text = LLTrans::getString("SocialFlickrConnecting"); +            mStatusLoadingText->setValue(status_text); +            mStatusLoadingIndicator->setVisible(true); +            break; +        case LLFlickrConnect::FLICKR_POSTING: +            // Posting indicator +            mStatusLoadingText->setVisible(true); +            status_text = LLTrans::getString("SocialFlickrPosting"); +            mStatusLoadingText->setValue(status_text); +            mStatusLoadingIndicator->setVisible(true); +			break; +        case LLFlickrConnect::FLICKR_CONNECTION_FAILED: +            // Error connecting to the service +            mStatusErrorText->setVisible(true); +            status_text = LLTrans::getString("SocialFlickrErrorConnecting"); +            mStatusErrorText->setValue(status_text); +            break; +        case LLFlickrConnect::FLICKR_POST_FAILED: +            // Error posting to the service +            mStatusErrorText->setVisible(true); +            status_text = LLTrans::getString("SocialFlickrErrorPosting"); +            mStatusErrorText->setValue(status_text); +            break; +		case LLFlickrConnect::FLICKR_DISCONNECTING: +			// Disconnecting loading indicator +			mStatusLoadingText->setVisible(true); +			status_text = LLTrans::getString("SocialFlickrDisconnecting"); +			mStatusLoadingText->setValue(status_text); +			mStatusLoadingIndicator->setVisible(true); +			break; +		case LLFlickrConnect::FLICKR_DISCONNECT_FAILED: +			// Error disconnecting from the service +			mStatusErrorText->setVisible(true); +			status_text = LLTrans::getString("SocialFlickrErrorDisconnecting"); +			mStatusErrorText->setValue(status_text); +			break; +        } +    } +	LLFloater::draw(); +} + diff --git a/indra/newview/llfloaterflickr.h b/indra/newview/llfloaterflickr.h new file mode 100644 index 0000000000..e9005444d8 --- /dev/null +++ b/indra/newview/llfloaterflickr.h @@ -0,0 +1,127 @@ +/**  +* @file   llfloaterflickr.h +* @brief  Header file for llfloaterflickr +* @author cho@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_LLFLOATERFLICKR_H +#define LL_LLFLOATERFLICKR_H + +#include "llfloater.h" +#include "lltextbox.h" +#include "llviewertexture.h" + +class LLIconCtrl; +class LLCheckBoxCtrl; +class LLSnapshotLivePreview; + +class LLFlickrPhotoPanel : public LLPanel +{ +public: +	LLFlickrPhotoPanel(); +	~LLFlickrPhotoPanel(); + +	BOOL postBuild(); +	void draw(); + +	LLSnapshotLivePreview* getPreviewView(); +	void onVisibilityChange(const LLSD& new_visibility); +	void onClickNewSnapshot(); +	void onSend(); +	bool onFlickrConnectStateChange(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 * mTitleTextBox; +	LLUICtrl * mDescriptionTextBox; +	LLUICtrl * mLocationCheckbox; +	LLUICtrl * mTagsTextBox; +	LLUICtrl * mRatingComboBox; +	LLUICtrl * mPostButton; +	LLUICtrl* mCancelButton; +}; + +class LLFlickrAccountPanel : public LLPanel +{ +public: +	LLFlickrAccountPanel(); +	BOOL postBuild(); +	void draw(); + +private: +	void onVisibilityChange(const LLSD& new_visibility); +	bool onFlickrConnectStateChange(const LLSD& data); +	bool onFlickrConnectInfoChange(); +	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 LLFloaterFlickr : public LLFloater +{ +public: +	LLFloaterFlickr(const LLSD& key); +	BOOL postBuild(); +	void draw(); +	void onCancel(); +	 +	void showPhotoPanel(); + +	static void preUpdate(); +	static void postUpdate(); + +private: +	LLFlickrPhotoPanel* mSocialPhotoPanel; +    LLTextBox* mStatusErrorText; +    LLTextBox* mStatusLoadingText; +    LLUICtrl*  mStatusLoadingIndicator; +}; + +#endif // LL_LLFLOATERFLICKR_H + diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index ea385d7baf..4701e128d3 100755 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -32,6 +32,8 @@  #include "llfacebookconnect.h"  #include "llfloaterreg.h"  #include "llfloatersocial.h" +#include "llfloaterflickr.h" +#include "llfloatertwitter.h"  #include "llcheckboxctrl.h"  #include "llcombobox.h"  #include "llpostcard.h" @@ -1264,9 +1266,11 @@ S32 LLFloaterSnapshot::notify(const LLSD& info)  void LLFloaterSnapshot::update()  {  	LLFloaterSnapshot* inst = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); -	LLFloaterSocial* floater_social  = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social");  +	LLFloaterSocial* floater_social = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social");  +	LLFloaterFlickr* floater_flickr = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr");  +	LLFloaterTwitter* floater_twitter = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter");  -	if (!inst && !floater_social) +	if (!inst && !floater_social && !floater_flickr && !floater_twitter)  		return;  	BOOL changed = FALSE; diff --git a/indra/newview/llfloatersocial.cpp b/indra/newview/llfloatersocial.cpp index 2a74c8e3ea..31404da7d3 100644 --- a/indra/newview/llfloatersocial.cpp +++ b/indra/newview/llfloatersocial.cpp @@ -46,6 +46,7 @@  #include "llviewerregion.h"  #include "llviewercontrol.h"  #include "llviewermedia.h" +#include "lltabcontainer.h"  static LLRegisterPanelClassWrapper<LLSocialStatusPanel> t_panel_status("llsocialstatuspanel");  static LLRegisterPanelClassWrapper<LLSocialPhotoPanel> t_panel_photo("llsocialphotopanel"); @@ -823,6 +824,18 @@ BOOL LLFloaterSocial::postBuild()  	return LLFloater::postBuild();  } +void LLFloaterSocial::showPhotoPanel() +{ +	LLTabContainer* parent = dynamic_cast<LLTabContainer*>(mSocialPhotoPanel->getParent()); +	if (!parent) +	{ +		llwarns << "Cannot find panel container" << llendl; +		return; +	} + +	parent->selectTabPanel(mSocialPhotoPanel); +} +  // static  void LLFloaterSocial::preUpdate()  { diff --git a/indra/newview/llfloatersocial.h b/indra/newview/llfloatersocial.h index bbe07c9704..041ae8a268 100644 --- a/indra/newview/llfloatersocial.h +++ b/indra/newview/llfloatersocial.h @@ -150,6 +150,8 @@ public:  	BOOL postBuild();  	void draw();  	void onCancel(); +	 +	void showPhotoPanel();  	static void preUpdate();  	static void postUpdate(); diff --git a/indra/newview/llfloatertwitter.cpp b/indra/newview/llfloatertwitter.cpp new file mode 100644 index 0000000000..06d0fb5542 --- /dev/null +++ b/indra/newview/llfloatertwitter.cpp @@ -0,0 +1,697 @@ +/**  +* @file llfloatertwitter.cpp +* @brief Implementation of llfloatertwitter +* @author cho@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 "llfloatertwitter.h" + +#include "llagent.h" +#include "llagentui.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "lltwitterconnect.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" +#include "lltabcontainer.h" +#include "lltexteditor.h" + +static LLRegisterPanelClassWrapper<LLTwitterPhotoPanel> t_panel_photo("lltwitterphotopanel"); +static LLRegisterPanelClassWrapper<LLTwitterAccountPanel> t_panel_account("lltwitteraccountpanel"); + +const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte +const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=twitter&utm_medium=photo&utm_campaign=slshare"; + +/////////////////////////// +//LLTwitterPhotoPanel/////// +/////////////////////////// + +LLTwitterPhotoPanel::LLTwitterPhotoPanel() : +mSnapshotPanel(NULL), +mResolutionComboBox(NULL), +mRefreshBtn(NULL), +mWorkingLabel(NULL), +mThumbnailPlaceholder(NULL), +mStatusTextBox(NULL), +mPhotoCheckbox(NULL), +mPostButton(NULL) +{ +	mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLTwitterPhotoPanel::onSend, this)); +	mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLTwitterPhotoPanel::onClickNewSnapshot, this)); +} + +LLTwitterPhotoPanel::~LLTwitterPhotoPanel() +{ +	if(mPreviewHandle.get()) +	{ +		mPreviewHandle.get()->die(); +	} +} + +BOOL LLTwitterPhotoPanel::postBuild() +{ +	setVisibleCallback(boost::bind(&LLTwitterPhotoPanel::onVisibilityChange, this, _2)); +	 +	mSnapshotPanel = getChild<LLUICtrl>("snapshot_panel"); +	mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox"); +	mResolutionComboBox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::updateResolution, this, TRUE)); +	mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn"); +    mWorkingLabel = getChild<LLUICtrl>("working_lbl"); +	mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder"); +	mStatusTextBox = getChild<LLUICtrl>("photo_status"); +	mPhotoCheckbox = getChild<LLUICtrl>("add_photo_cb"); +	mPostButton = getChild<LLUICtrl>("post_photo_btn"); +	mCancelButton = getChild<LLUICtrl>("cancel_photo_btn"); + +	return LLPanel::postBuild(); +} + +void LLTwitterPhotoPanel::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 = !(LLTwitterConnect::instance().isTransactionOngoing()); +    mCancelButton->setEnabled(no_ongoing_connection); +    mStatusTextBox->setEnabled(no_ongoing_connection); +    mResolutionComboBox->setEnabled(no_ongoing_connection && mPhotoCheckbox->getValue().asBoolean()); +    mRefreshBtn->setEnabled(no_ongoing_connection && mPhotoCheckbox->getValue().asBoolean()); +    mPhotoCheckbox->setEnabled(no_ongoing_connection); + +	bool add_photo = mPhotoCheckbox->getValue().asBoolean(); + +	// Restrict the status text length to Twitter's character limit +	LLTextEditor* status_text_box = dynamic_cast<LLTextEditor*>(mStatusTextBox); +	if (status_text_box) +	{ +		int max_status_length = add_photo ? 100 : 140; +		status_text_box->setMaxTextLength(max_status_length); +		if (!add_photo) +		{ +			if (mOldStatusText.length() > status_text_box->getText().length() && status_text_box->getText() == mOldStatusText.substr(0, status_text_box->getText().length())) +			{ +				status_text_box->setText(mOldStatusText); +			} +			mOldStatusText = ""; +		} +		if (status_text_box->getText().length() > max_status_length) +		{ +			mOldStatusText = status_text_box->getText(); +			status_text_box->setText(mOldStatusText.substr(0, max_status_length)); +		} +	} + +    // 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 = (add_photo ? (getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency()) : 0.5f); +		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 && ((add_photo && previewp && previewp->getSnapshotUpToDate()) || !mStatusTextBox->getValue().asString().empty())); +     +    // Draw the rest of the panel on top of it +	LLPanel::draw(); +} + +LLSnapshotLivePreview* LLTwitterPhotoPanel::getPreviewView() +{ +	LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get(); +	return previewp; +} + +void LLTwitterPhotoPanel::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 LLTwitterPhotoPanel::onClickNewSnapshot() +{ +	LLSnapshotLivePreview* previewp = getPreviewView(); +	if (previewp) +	{ +		//setStatus(Impl::STATUS_READY); +		lldebugs << "updating snapshot" << llendl; +		previewp->updateSnapshot(TRUE); +	} +} + +void LLTwitterPhotoPanel::onSend() +{ +	LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterPhotoPanel"); // just in case it is already listening +	LLEventPumps::instance().obtain("TwitterConnectState").listen("LLTwitterPhotoPanel", boost::bind(&LLTwitterPhotoPanel::onTwitterConnectStateChange, this, _1)); +	 +	// Connect to Twitter if necessary and then post +	if (LLTwitterConnect::instance().isConnected()) +	{ +		sendPhoto(); +	} +	else +	{ +		LLTwitterConnect::instance().checkConnectionToTwitter(true); +	} +} + +bool LLTwitterPhotoPanel::onTwitterConnectStateChange(const LLSD& data) +{ +	switch (data.get("enum").asInteger()) +	{ +		case LLTwitterConnect::TWITTER_CONNECTED: +			sendPhoto(); +			break; + +		case LLTwitterConnect::TWITTER_POSTED: +			LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterPhotoPanel"); +			clearAndClose(); +			break; +	} + +	return false; +} + +void LLTwitterPhotoPanel::sendPhoto() +{ +	// Get the status text +	std::string status = mStatusTextBox->getValue().asString(); + +	// Add the photo if required +	bool add_photo = mPhotoCheckbox->getValue().asBoolean(); +	if (add_photo) +	{ +		// Get the image +		LLSnapshotLivePreview* previewp = getPreviewView(); +	 +		// Post to Twitter +		LLTwitterConnect::instance().uploadPhoto(previewp->getFormattedImage(), status); +	} +	else +	{ +		// Just post the status to Twitter +		LLTwitterConnect::instance().updateStatus(status); +	} + +	updateControls(); +} + +void LLTwitterPhotoPanel::clearAndClose() +{ +	mStatusTextBox->setValue(""); + +	LLFloater* floater = getParentByType<LLFloater>(); +	if (floater) +	{ +		floater->closeFloater(); +	} +} + +void LLTwitterPhotoPanel::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 LLTwitterPhotoPanel::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(); +                LLTwitterPhotoPanel::onClickNewSnapshot(); +			} +		} +		 +	} +} + +void LLTwitterPhotoPanel::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* LLTwitterPhotoPanel::getRefreshBtn() +{ +	return mRefreshBtn; +} + +/////////////////////////// +//LLTwitterAccountPanel////// +/////////////////////////// + +LLTwitterAccountPanel::LLTwitterAccountPanel() :  +mAccountCaptionLabel(NULL), +mAccountNameLabel(NULL), +mPanelButtons(NULL), +mConnectButton(NULL), +mDisconnectButton(NULL) +{ +	mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLTwitterAccountPanel::onConnect, this)); +	mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLTwitterAccountPanel::onDisconnect, this)); + +	setVisibleCallback(boost::bind(&LLTwitterAccountPanel::onVisibilityChange, this, _2)); +} + +BOOL LLTwitterAccountPanel::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 LLTwitterAccountPanel::draw() +{ +	LLTwitterConnect::EConnectionState connection_state = LLTwitterConnect::instance().getConnectionState(); + +	//Disable the 'disconnect' button and the 'use another account' button when disconnecting in progress +	bool disconnecting = connection_state == LLTwitterConnect::TWITTER_DISCONNECTING; +	mDisconnectButton->setEnabled(!disconnecting); + +	//Disable the 'connect' button when a connection is in progress +	bool connecting = connection_state == LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS; +	mConnectButton->setEnabled(!connecting); + +	LLPanel::draw(); +} + +void LLTwitterAccountPanel::onVisibilityChange(const LLSD& new_visibility) +{ +	bool visible = new_visibility.asBoolean(); + +	if(visible) +	{ +		LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterAccountPanel"); +		LLEventPumps::instance().obtain("TwitterConnectState").listen("LLTwitterAccountPanel", boost::bind(&LLTwitterAccountPanel::onTwitterConnectStateChange, this, _1)); + +		LLEventPumps::instance().obtain("TwitterConnectInfo").stopListening("LLTwitterAccountPanel"); +		LLEventPumps::instance().obtain("TwitterConnectInfo").listen("LLTwitterAccountPanel", boost::bind(&LLTwitterAccountPanel::onTwitterConnectInfoChange, this)); + +		//Connected +		if(LLTwitterConnect::instance().isConnected()) +		{ +			showConnectedLayout(); +		} +		//Check if connected (show disconnected layout in meantime) +		else +		{ +			showDisconnectedLayout(); +		} +        if ((LLTwitterConnect::instance().getConnectionState() == LLTwitterConnect::TWITTER_NOT_CONNECTED) || +            (LLTwitterConnect::instance().getConnectionState() == LLTwitterConnect::TWITTER_CONNECTION_FAILED)) +        { +            LLTwitterConnect::instance().checkConnectionToTwitter(); +        } +	} +	else +	{ +		LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterAccountPanel"); +		LLEventPumps::instance().obtain("TwitterConnectInfo").stopListening("LLTwitterAccountPanel"); +	} +} + +bool LLTwitterAccountPanel::onTwitterConnectStateChange(const LLSD& data) +{ +	if(LLTwitterConnect::instance().isConnected()) +	{ +		//In process of disconnecting so leave the layout as is +		if(data.get("enum").asInteger() != LLTwitterConnect::TWITTER_DISCONNECTING) +		{ +			showConnectedLayout(); +		} +	} +	else +	{ +		showDisconnectedLayout(); +	} + +	return false; +} + +bool LLTwitterAccountPanel::onTwitterConnectInfoChange() +{ +	LLSD info = LLTwitterConnect::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 LLTwitterAccountPanel::showConnectButton() +{ +	if(!mConnectButton->getVisible()) +	{ +		mConnectButton->setVisible(TRUE); +		mDisconnectButton->setVisible(FALSE); +	} +} + +void LLTwitterAccountPanel::hideConnectButton() +{ +	if(mConnectButton->getVisible()) +	{ +		mConnectButton->setVisible(FALSE); +		mDisconnectButton->setVisible(TRUE); +	} +} + +void LLTwitterAccountPanel::showDisconnectedLayout() +{ +	mAccountCaptionLabel->setText(getString("twitter_disconnected")); +	mAccountNameLabel->setText(std::string("")); +	showConnectButton(); +} + +void LLTwitterAccountPanel::showConnectedLayout() +{ +	LLTwitterConnect::instance().loadTwitterInfo(); + +	mAccountCaptionLabel->setText(getString("twitter_connected")); +	hideConnectButton(); +} + +void LLTwitterAccountPanel::onConnect() +{ +	LLTwitterConnect::instance().checkConnectionToTwitter(true); + +	//Clear only the twitter browser cookies so that the twitter login screen appears +	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".twitter.com");  +} + +void LLTwitterAccountPanel::onDisconnect() +{ +	LLTwitterConnect::instance().disconnectFromTwitter(); + +	LLViewerMedia::getCookieStore()->removeCookiesByDomain(".twitter.com");  +} + +//////////////////////// +//LLFloaterTwitter/////// +//////////////////////// + +LLFloaterTwitter::LLFloaterTwitter(const LLSD& key) : LLFloater(key), +    mSocialPhotoPanel(NULL), +    mStatusErrorText(NULL), +    mStatusLoadingText(NULL), +    mStatusLoadingIndicator(NULL) +{ +	mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterTwitter::onCancel, this)); +} + +void LLFloaterTwitter::onCancel() +{ +    closeFloater(); +} + +BOOL LLFloaterTwitter::postBuild() +{ +    // Keep tab of the Photo Panel +	mSocialPhotoPanel = static_cast<LLTwitterPhotoPanel*>(getChild<LLUICtrl>("panel_twitter_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(); +} + +void LLFloaterTwitter::showPhotoPanel() +{ +	LLTabContainer* parent = dynamic_cast<LLTabContainer*>(mSocialPhotoPanel->getParent()); +	if (!parent) +	{ +		llwarns << "Cannot find panel container" << llendl; +		return; +	} + +	parent->selectTabPanel(mSocialPhotoPanel); +} + +// static +void LLFloaterTwitter::preUpdate() +{ +	LLFloaterTwitter* instance = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter"); +	if (instance) +	{ +		//Will set file size text to 'unknown' +		instance->mSocialPhotoPanel->updateControls(); +	} +} + +// static +void LLFloaterTwitter::postUpdate() +{ +	LLFloaterTwitter* instance = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter"); +	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 LLFloaterTwitter::draw() +{ +    if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator) +    { +        mStatusErrorText->setVisible(false); +        mStatusLoadingText->setVisible(false); +        mStatusLoadingIndicator->setVisible(false); +        LLTwitterConnect::EConnectionState connection_state = LLTwitterConnect::instance().getConnectionState(); +        std::string status_text; +         +        switch (connection_state) +        { +        case LLTwitterConnect::TWITTER_NOT_CONNECTED: +            // No status displayed when first opening the panel and no connection done +        case LLTwitterConnect::TWITTER_CONNECTED: +            // When successfully connected, no message is displayed +        case LLTwitterConnect::TWITTER_POSTED: +            // No success message to show since we actually close the floater after successful posting completion +            break; +        case LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS: +            // Connection loading indicator +            mStatusLoadingText->setVisible(true); +            status_text = LLTrans::getString("SocialTwitterConnecting"); +            mStatusLoadingText->setValue(status_text); +            mStatusLoadingIndicator->setVisible(true); +            break; +        case LLTwitterConnect::TWITTER_POSTING: +            // Posting indicator +            mStatusLoadingText->setVisible(true); +            status_text = LLTrans::getString("SocialTwitterPosting"); +            mStatusLoadingText->setValue(status_text); +            mStatusLoadingIndicator->setVisible(true); +			break; +        case LLTwitterConnect::TWITTER_CONNECTION_FAILED: +            // Error connecting to the service +            mStatusErrorText->setVisible(true); +            status_text = LLTrans::getString("SocialTwitterErrorConnecting"); +            mStatusErrorText->setValue(status_text); +            break; +        case LLTwitterConnect::TWITTER_POST_FAILED: +            // Error posting to the service +            mStatusErrorText->setVisible(true); +            status_text = LLTrans::getString("SocialTwitterErrorPosting"); +            mStatusErrorText->setValue(status_text); +            break; +		case LLTwitterConnect::TWITTER_DISCONNECTING: +			// Disconnecting loading indicator +			mStatusLoadingText->setVisible(true); +			status_text = LLTrans::getString("SocialTwitterDisconnecting"); +			mStatusLoadingText->setValue(status_text); +			mStatusLoadingIndicator->setVisible(true); +			break; +		case LLTwitterConnect::TWITTER_DISCONNECT_FAILED: +			// Error disconnecting from the service +			mStatusErrorText->setVisible(true); +			status_text = LLTrans::getString("SocialTwitterErrorDisconnecting"); +			mStatusErrorText->setValue(status_text); +			break; +        } +    } +	LLFloater::draw(); +} + diff --git a/indra/newview/llfloatertwitter.h b/indra/newview/llfloatertwitter.h new file mode 100644 index 0000000000..686e167b1f --- /dev/null +++ b/indra/newview/llfloatertwitter.h @@ -0,0 +1,126 @@ +/**  +* @file   llfloatertwitter.h +* @brief  Header file for llfloatertwitter +* @author cho@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_LLFLOATERTWITTER_H +#define LL_LLFLOATERTWITTER_H + +#include "llfloater.h" +#include "lltextbox.h" +#include "llviewertexture.h" + +class LLIconCtrl; +class LLCheckBoxCtrl; +class LLSnapshotLivePreview; + +class LLTwitterPhotoPanel : public LLPanel +{ +public: +	LLTwitterPhotoPanel(); +	~LLTwitterPhotoPanel(); + +	BOOL postBuild(); +	void draw(); + +	LLSnapshotLivePreview* getPreviewView(); +	void onVisibilityChange(const LLSD& new_visibility); +	void onClickNewSnapshot(); +	void onSend(); +	bool onTwitterConnectStateChange(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 * mStatusTextBox; +	LLUICtrl * mPhotoCheckbox; +	LLUICtrl * mPostButton; +	LLUICtrl* mCancelButton; + +	std::string mOldStatusText; +}; + +class LLTwitterAccountPanel : public LLPanel +{ +public: +	LLTwitterAccountPanel(); +	BOOL postBuild(); +	void draw(); + +private: +	void onVisibilityChange(const LLSD& new_visibility); +	bool onTwitterConnectStateChange(const LLSD& data); +	bool onTwitterConnectInfoChange(); +	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 LLFloaterTwitter : public LLFloater +{ +public: +	LLFloaterTwitter(const LLSD& key); +	BOOL postBuild(); +	void draw(); +	void onCancel(); + +	void showPhotoPanel(); + +	static void preUpdate(); +	static void postUpdate(); + +private: +	LLTwitterPhotoPanel* mSocialPhotoPanel; +    LLTextBox* mStatusErrorText; +    LLTextBox* mStatusLoadingText; +    LLUICtrl*  mStatusLoadingIndicator; +}; + +#endif // LL_LLFLOATERTWITTER_H + diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index 5c569b9bf0..814c91ef6c 100755 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -30,6 +30,8 @@  #include "lliconctrl.h"  #include "llfloaterreg.h"  #include "llfacebookconnect.h" +#include "llflickrconnect.h" +#include "lltwitterconnect.h"  #include "lllayoutstack.h"  #include "llpluginclassmedia.h"  #include "llprogressbar.h" @@ -298,7 +300,24 @@ void LLFloaterWebContent::onClose(bool app_quitting)              LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED);          }      } -     +	// Same with Flickr +	LLFloater* flickr_web = LLFloaterReg::getInstance("flickr_web"); +    if (flickr_web == this) +    { +        if (!LLFlickrConnect::instance().isConnected()) +        { +            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); +        } +    } +	// And Twitter +	LLFloater* twitter_web = LLFloaterReg::getInstance("twitter_web"); +    if (twitter_web == this) +    { +        if (!LLTwitterConnect::instance().isConnected()) +        { +            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); +        } +    }  	LLViewerMedia::proxyWindowClosed(mUUID);  	destroy();  } diff --git a/indra/newview/llpanelsnapshotoptions.cpp b/indra/newview/llpanelsnapshotoptions.cpp index 554fabe5b3..4cadd837d1 100755 --- a/indra/newview/llpanelsnapshotoptions.cpp +++ b/indra/newview/llpanelsnapshotoptions.cpp @@ -31,6 +31,10 @@  #include "llsidetraypanelcontainer.h"  #include "llfloatersnapshot.h" // FIXME: create a snapshot model +#include "llfloaterreg.h" +#include "llfloatersocial.h" +#include "llfloaterflickr.h" +#include "llfloatertwitter.h"  /**   * Provides several ways to save a snapshot. @@ -44,6 +48,7 @@ class LLPanelSnapshotOptions  public:  	LLPanelSnapshotOptions();  	~LLPanelSnapshotOptions(); +	/*virtual*/ BOOL postBuild();  	/*virtual*/ void onOpen(const LLSD& key);  	/*virtual*/ void onEconomyDataChange() { updateUploadCost(); } @@ -54,6 +59,9 @@ private:  	void onSaveToEmail();  	void onSaveToInventory();  	void onSaveToComputer(); +	void onSendToFacebook(); +	void onSendToTwitter(); +	void onSendToFlickr();  };  static LLRegisterPanelClassWrapper<LLPanelSnapshotOptions> panel_class("llpanelsnapshotoptions"); @@ -74,6 +82,19 @@ LLPanelSnapshotOptions::~LLPanelSnapshotOptions()  }  // virtual +BOOL LLPanelSnapshotOptions::postBuild() +{ +    LLTextBox* sendToFacebookTextBox = getChild<LLTextBox>("send_to_facebook_textbox"); +    sendToFacebookTextBox->setURLClickedCallback(boost::bind(&LLPanelSnapshotOptions::onSendToFacebook, this)); +    LLTextBox* sendToTwitterTextBox = getChild<LLTextBox>("send_to_twitter_textbox"); +    sendToTwitterTextBox->setURLClickedCallback(boost::bind(&LLPanelSnapshotOptions::onSendToTwitter, this)); +    LLTextBox* sendToFlickrTextBox = getChild<LLTextBox>("send_to_flickr_textbox"); +    sendToFlickrTextBox->setURLClickedCallback(boost::bind(&LLPanelSnapshotOptions::onSendToFlickr, this)); + +	return LLPanel::postBuild(); +} + +// virtual  void LLPanelSnapshotOptions::onOpen(const LLSD& key)  {  	updateUploadCost(); @@ -118,3 +139,39 @@ void LLPanelSnapshotOptions::onSaveToComputer()  {  	openPanel("panel_snapshot_local");  } + +void LLPanelSnapshotOptions::onSendToFacebook() +{ +	LLFloaterReg::hideInstance("snapshot"); + +	LLFloaterSocial* social_floater = dynamic_cast<LLFloaterSocial*>(LLFloaterReg::getInstance("social")); +	if (social_floater) +	{ +		social_floater->showPhotoPanel(); +	} +	LLFloaterReg::showInstance("social"); +} + +void LLPanelSnapshotOptions::onSendToTwitter() +{ +	LLFloaterReg::hideInstance("snapshot"); + +	LLFloaterTwitter* twitter_floater = dynamic_cast<LLFloaterTwitter*>(LLFloaterReg::getInstance("twitter")); +	if (twitter_floater) +	{ +		twitter_floater->showPhotoPanel(); +	} +	LLFloaterReg::showInstance("twitter"); +} + +void LLPanelSnapshotOptions::onSendToFlickr() +{ +	LLFloaterReg::hideInstance("snapshot"); + +	LLFloaterFlickr* flickr_floater = dynamic_cast<LLFloaterFlickr*>(LLFloaterReg::getInstance("flickr")); +	if (flickr_floater) +	{ +		flickr_floater->showPhotoPanel(); +	} +	LLFloaterReg::showInstance("flickr"); +} diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 7532ebfc57..67952f83c7 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -35,6 +35,8 @@  #include "llfloaterperms.h"  #include "llfloaterreg.h"  #include "llfloatersocial.h" +#include "llfloaterflickr.h" +#include "llfloatertwitter.h"  #include "llimagebmp.h"  #include "llimagej2c.h"  #include "llimagejpeg.h" @@ -209,6 +211,8 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail  		mSnapshotDelayTimer.setTimerExpirySec(delay);  		LLFloaterSnapshot::preUpdate();  		LLFloaterSocial::preUpdate(); +		LLFloaterFlickr::preUpdate(); +		LLFloaterTwitter::preUpdate();  	}  	// Update thumbnail if requested. @@ -766,6 +770,8 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )  	lldebugs << "done creating snapshot" << llendl;  	LLFloaterSnapshot::postUpdate();  	LLFloaterSocial::postUpdate(); +	LLFloaterFlickr::postUpdate(); +	LLFloaterTwitter::postUpdate();  	return TRUE;  } diff --git a/indra/newview/lltwitterconnect.cpp b/indra/newview/lltwitterconnect.cpp new file mode 100644 index 0000000000..e015867df2 --- /dev/null +++ b/indra/newview/lltwitterconnect.cpp @@ -0,0 +1,471 @@ +/**  + * @file lltwitterconnect.h + * @author Merov, Cho + * @brief Connection to Twitter 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 "lltwitterconnect.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> LLTwitterConnect::sStateWatcher(new LLEventStream("TwitterConnectState")); +boost::scoped_ptr<LLEventPump> LLTwitterConnect::sInfoWatcher(new LLEventStream("TwitterConnectInfo")); +boost::scoped_ptr<LLEventPump> LLTwitterConnect::sContentWatcher(new LLEventStream("TwitterConnectContent")); + +// Local functions +void log_twitter_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("TwitterConnect") << request << " request failed with a " << status << " " << reason << ". Reason: " << code << " (" << description << ")" << LL_ENDL; +    } +} + +void toast_user_for_twitter_success() +{ +	LLSD args; +    args["MESSAGE"] = LLTrans::getString("twitter_post_success"); +    LLNotificationsUtil::add("TwitterConnect", args); +} + +/////////////////////////////////////////////////////////////////////////////// +// +class LLTwitterConnectResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLTwitterConnectResponder); +public: +	 +    LLTwitterConnectResponder() +    { +        LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS); +    } +     +	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (isGoodStatus(status)) +		{ +			LL_DEBUGS("TwitterConnect") << "Connect successful. content: " << content << LL_ENDL; +			 +            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTED); +		} +		else if (status != 302) +		{ +            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); +            log_twitter_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) +        { +            LLTwitterConnect::instance().openTwitterWeb(content["location"]); +        } +    } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +class LLTwitterShareResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLTwitterShareResponder); +public: +     +	LLTwitterShareResponder() +	{ +		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POSTING); +	} +	 +	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (isGoodStatus(status)) +		{ +            toast_user_for_twitter_success(); +			LL_DEBUGS("TwitterConnect") << "Post successful. content: " << content << LL_ENDL; +			 +			LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POSTED); +		} +		else if (status == 404) +		{ +			LLTwitterConnect::instance().connectToTwitter(); +		} +		else +		{ +            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POST_FAILED); +            log_twitter_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) +        { +            LLTwitterConnect::instance().openTwitterWeb(content["location"]); +        } +    } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +class LLTwitterDisconnectResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLTwitterDisconnectResponder); +public: +  +	LLTwitterDisconnectResponder() +	{ +		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_DISCONNECTING); +	} + +	void setUserDisconnected() +	{ +		// Clear data +		LLTwitterConnect::instance().clearInfo(); + +		//Notify state change +		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED); +	} + +	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (isGoodStatus(status))  +		{ +			LL_DEBUGS("TwitterConnect") << "Disconnect successful. content: " << content << LL_ENDL; +			setUserDisconnected(); + +		} +		//User not found so already disconnected +		else if(status == 404) +		{ +			LL_DEBUGS("TwitterConnect") << "Already disconnected. content: " << content << LL_ENDL; +			setUserDisconnected(); +		} +		else +		{ +			LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_DISCONNECT_FAILED); +            log_twitter_connect_error("Disconnect", status, reason, content.get("error_code"), content.get("error_description")); +		} +	} +}; + +/////////////////////////////////////////////////////////////////////////////// +// +class LLTwitterConnectedResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLTwitterConnectedResponder); +public: +     +	LLTwitterConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect) +    { +		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS); +    } +     +	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		if (isGoodStatus(status)) +		{ +			LL_DEBUGS("TwitterConnect") << "Connect successful. content: " << content << LL_ENDL; +             +            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTED); +		} +		else +		{ +			// show the twitter login page if not connected yet +			if (status == 404) +			{ +				if (mAutoConnect) +				{ +					LLTwitterConnect::instance().connectToTwitter(); +				} +				else +				{ +					LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED); +				} +			} +            else +            { +                LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); +				log_twitter_connect_error("Connected", status, reason, content.get("error_code"), content.get("error_description")); +            } +		} +	} +     +private: +	bool mAutoConnect; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +class LLTwitterInfoResponder : public LLHTTPClient::Responder +{ +	LOG_CLASS(LLTwitterInfoResponder); +public: + +	virtual void completed(U32 status, const std::string& reason, const LLSD& info) +	{ +		if (isGoodStatus(status)) +		{ +			llinfos << "Twitter: Info received" << llendl; +			LL_DEBUGS("TwitterConnect") << "Getting Twitter info successful. info: " << info << LL_ENDL; +			LLTwitterConnect::instance().storeInfo(info); +		} +		else +		{ +			log_twitter_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) +		{ +			LLTwitterConnect::instance().openTwitterWeb(content["location"]); +		} +	} +}; + +/////////////////////////////////////////////////////////////////////////////// +// +LLTwitterConnect::LLTwitterConnect() +:	mConnectionState(TWITTER_NOT_CONNECTED), +	mConnected(false), +	mInfo(), +	mRefreshInfo(false), +	mReadFromMaster(false) +{ +} + +void LLTwitterConnect::openTwitterWeb(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("twitter_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 "twitter_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. +	//twitter_web floater contains the "webbrowser" panel.    JIRA: ACME-744 +	gFocusMgr.setKeyboardFocus( floater ); + +	//LLUrlAction::openURLExternal(url); +} + +std::string LLTwitterConnect::getTwitterConnectURL(const std::string& route, bool include_read_from_master) +{ +    std::string url(""); +    LLViewerRegion *regionp = gAgent.getRegion(); +    if (regionp) +    { +		//url = "http://pdp15.lindenlab.com/twitter/agent/" + gAgentID.asString(); // TEMPORARY FOR TESTING - CHO +        url = regionp->getCapability("TwitterConnect"); +        url += route; +     +        if (include_read_from_master && mReadFromMaster) +        { +            url += "?read_from_master=true"; +        } +    } +	return url; +} + +void LLTwitterConnect::connectToTwitter(const std::string& request_token, const std::string& oauth_verifier) +{ +	LLSD body; +	if (!request_token.empty()) +		body["request_token"] = request_token; +	if (!oauth_verifier.empty()) +		body["oauth_verifier"] = oauth_verifier; +     +	LLHTTPClient::put(getTwitterConnectURL("/connection"), body, new LLTwitterConnectResponder()); +} + +void LLTwitterConnect::disconnectFromTwitter() +{ +	LLHTTPClient::del(getTwitterConnectURL("/connection"), new LLTwitterDisconnectResponder()); +} + +void LLTwitterConnect::checkConnectionToTwitter(bool auto_connect) +{ +	const bool follow_redirects = false; +	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	LLHTTPClient::get(getTwitterConnectURL("/connection", true), new LLTwitterConnectedResponder(auto_connect), +						LLSD(), timeout, follow_redirects); +} + +void LLTwitterConnect::loadTwitterInfo() +{ +	if(mRefreshInfo) +	{ +		const bool follow_redirects = false; +		const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +		LLHTTPClient::get(getTwitterConnectURL("/info", true), new LLTwitterInfoResponder(), +			LLSD(), timeout, follow_redirects); +	} +} + +void LLTwitterConnect::uploadPhoto(const std::string& image_url, const std::string& status) +{ +	LLSD body; +	body["image"] = image_url; +	body["status"] = status; +	 +    // Note: we can use that route for different publish action. We should be able to use the same responder. +	LLHTTPClient::post(getTwitterConnectURL("/share/photo", true), body, new LLTwitterShareResponder()); +} + +void LLTwitterConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& status) +{ +	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=\"status\"\r\n\r\n" +			<< status << "\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(getTwitterConnectURL("/share/photo", true), data, size, new LLTwitterShareResponder(), headers); +} + +void LLTwitterConnect::updateStatus(const std::string& status) +{ +	LLSD body; +	body["status"] = status; +	 +    // Note: we can use that route for different publish action. We should be able to use the same responder. +	LLHTTPClient::post(getTwitterConnectURL("/share/status", true), body, new LLTwitterShareResponder()); +} + +void LLTwitterConnect::storeInfo(const LLSD& info) +{ +	mInfo = info; +	mRefreshInfo = false; + +	sInfoWatcher->post(info); +} + +const LLSD& LLTwitterConnect::getInfo() const +{ +	return mInfo; +} + +void LLTwitterConnect::clearInfo() +{ +	mInfo = LLSD(); +} + +void LLTwitterConnect::setDataDirty() +{ +	mRefreshInfo = true; +} + +void LLTwitterConnect::setConnectionState(LLTwitterConnect::EConnectionState connection_state) +{ +	if(connection_state == TWITTER_CONNECTED) +	{ +		mReadFromMaster = true; +		setConnected(true); +		setDataDirty(); +	} +	else if(connection_state == TWITTER_NOT_CONNECTED) +	{ +		setConnected(false); +	} +	else if(connection_state == TWITTER_POSTED) +	{ +		mReadFromMaster = false; +	} + +	if (mConnectionState != connection_state) +	{ +		LLSD state_info; +		state_info["enum"] = connection_state; +		sStateWatcher->post(state_info); +	} +	 +	mConnectionState = connection_state; +} + +void LLTwitterConnect::setConnected(bool connected) +{ +	mConnected = connected; +} diff --git a/indra/newview/lltwitterconnect.h b/indra/newview/lltwitterconnect.h new file mode 100644 index 0000000000..c1df13f18c --- /dev/null +++ b/indra/newview/lltwitterconnect.h @@ -0,0 +1,99 @@ +/**  + * @file lltwitterconnect.h + * @author Merov, Cho + * @brief Connection to Twitter 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_LLTWITTERCONNECT_H +#define LL_LLTWITTERCONNECT_H + +#include "llsingleton.h" +#include "llimage.h" + +class LLEventPump; + +/** + * @class LLTwitterConnect + * + * Manages authentication to, and interaction with, a web service allowing the + * the viewer to post status updates and upload photos to Twitter. + */ +class LLTwitterConnect : public LLSingleton<LLTwitterConnect> +{ +	LOG_CLASS(LLTwitterConnect); +public: +    enum EConnectionState +	{ +		TWITTER_NOT_CONNECTED = 0, +		TWITTER_CONNECTION_IN_PROGRESS = 1, +		TWITTER_CONNECTED = 2, +		TWITTER_CONNECTION_FAILED = 3, +		TWITTER_POSTING = 4, +		TWITTER_POSTED = 5, +		TWITTER_POST_FAILED = 6, +		TWITTER_DISCONNECTING = 7, +		TWITTER_DISCONNECT_FAILED = 8 +	}; +	 +	void connectToTwitter(const std::string& request_token = "", const std::string& oauth_verifier = "");	// Initiate the complete Twitter connection. Please use checkConnectionToTwitter() in normal use. +	void disconnectFromTwitter();																			// Disconnect from the Twitter service. +    void checkConnectionToTwitter(bool auto_connect = false);												// Check if an access token is available on the Twitter service. If not, call connectToTwitter(). +     +	void loadTwitterInfo(); +	void uploadPhoto(const std::string& image_url, const std::string& status); +	void uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& status); +	void updateStatus(const std::string& status); +	 +	void storeInfo(const LLSD& info); +	const LLSD& getInfo() const; +	void clearInfo(); +	void setDataDirty(); +     +    void setConnectionState(EConnectionState connection_state); +	void setConnected(bool connected); +	bool isConnected() { return mConnected; } +	bool isTransactionOngoing() { return ((mConnectionState == TWITTER_CONNECTION_IN_PROGRESS) || (mConnectionState == TWITTER_POSTING) || (mConnectionState == TWITTER_DISCONNECTING)); } +    EConnectionState getConnectionState() { return mConnectionState; } +     +    void openTwitterWeb(std::string url); + +private: +	friend class LLSingleton<LLTwitterConnect>; + +	LLTwitterConnect(); +	~LLTwitterConnect() {}; + 	std::string getTwitterConnectURL(const std::string& route = "", bool include_read_from_master = false); + +    EConnectionState mConnectionState; +	BOOL mConnected; +	LLSD mInfo; +	bool mRefreshInfo; +	bool mReadFromMaster; +	 +	static boost::scoped_ptr<LLEventPump> sStateWatcher; +	static boost::scoped_ptr<LLEventPump> sInfoWatcher; +	static boost::scoped_ptr<LLEventPump> sContentWatcher; +}; + +#endif // LL_LLTWITTERCONNECT_H diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 4ce049df03..1e07aaf5ec 100755 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -53,13 +53,14 @@  #include "llfloaterconversationlog.h"  #include "llfloaterconversationpreview.h"  #include "llfloaterdeleteenvpreset.h" +#include "llfloaterdestinations.h"  #include "llfloaterdisplayname.h"  #include "llfloatereditdaycycle.h"  #include "llfloatereditsky.h"  #include "llfloatereditwater.h"  #include "llfloaterenvironmentsettings.h"  #include "llfloaterevent.h" -#include "llfloaterdestinations.h" +#include "llfloaterflickr.h"  #include "llfloaterfonttest.h"  #include "llfloatergesture.h"  #include "llfloatergodtools.h" @@ -115,6 +116,7 @@  #include "llfloatertopobjects.h"  #include "llfloatertoybox.h"  #include "llfloatertranslationsettings.h" +#include "llfloatertwitter.h"  #include "llfloateruipreview.h"  #include "llfloatervoiceeffect.h"  #include "llfloatervoicevolume.h" @@ -305,6 +307,8 @@ void LLViewerFloaterReg::registerFloaters()  	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("flickr", "floater_flickr.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFlickr>); +	LLFloaterReg::add("twitter", "floater_twitter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTwitter>);  	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>); @@ -312,8 +316,10 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSearch>);  	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("how_to", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);  	LLFloaterReg::add("fbc_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); +	LLFloaterReg::add("flickr_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); +	LLFloaterReg::add("twitter_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/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 94c187e21a..e42743824e 100755 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -149,6 +149,8 @@ with the same filename but different name    <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_Flickr_Icon"       file_name="toolbar_icons/flickr.png"     preload="true" /> +  <texture name="Command_Twitter_Icon"      file_name="toolbar_icons/twitter.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" /> diff --git a/indra/newview/skins/default/textures/toolbar_icons/flickr.png b/indra/newview/skins/default/textures/toolbar_icons/flickr.pngBinary files differ new file mode 100644 index 0000000000..7fce9f0df2 --- /dev/null +++ b/indra/newview/skins/default/textures/toolbar_icons/flickr.png diff --git a/indra/newview/skins/default/textures/toolbar_icons/twitter.png b/indra/newview/skins/default/textures/toolbar_icons/twitter.pngBinary files differ new file mode 100644 index 0000000000..a99c490887 --- /dev/null +++ b/indra/newview/skins/default/textures/toolbar_icons/twitter.png diff --git a/indra/newview/skins/default/xui/en/floater_flickr.xml b/indra/newview/skins/default/xui/en/floater_flickr.xml new file mode 100644 index 0000000000..57014f8427 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_flickr.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<floater +  positioning="cascading" +  can_close="true" +  can_resize="false" +  help_topic="floater_flickr" +  layout="topleft" +  name="floater_flickr" +  save_rect="true" +  single_instance="true" +  reuse_instance="true" +  title="UPLOAD TO FLICKR" +  height="622" +  width="304"> +  <panel +   height="622" +   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="577" +     halign="center"> +     <panel +       filename="panel_flickr_photo.xml" +       class="llflickrphotopanel" +       follows="all" +       label="PHOTO" +       name="panel_flickr_photo"/> +     <panel +       filename="panel_flickr_account.xml" +       class="llflickraccountpanel" +       follows="all" +       label="ACCOUNT" +       name="panel_flickr_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_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml index 853c209bca..019ddad33c 100755 --- a/indra/newview/skins/default/xui/en/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml @@ -10,7 +10,7 @@   help_topic="snapshot"   save_rect="true"   save_visibility="false" - title="SNAPSHOT PREVIEW" + title="SNAPSHOT"   width="470">      <floater.string       name="unknown"> diff --git a/indra/newview/skins/default/xui/en/floater_twitter.xml b/indra/newview/skins/default/xui/en/floater_twitter.xml new file mode 100644 index 0000000000..7007a14cdb --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_twitter.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<floater +  positioning="cascading" +  can_close="true" +  can_resize="false" +  help_topic="floater_twitter" +  layout="topleft" +  name="floater_twitter" +  save_rect="true" +  single_instance="true" +  reuse_instance="true" +  title="TWITTER" +  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_twitter_photo.xml" +       class="lltwitterphotopanel" +       follows="all" +       label="COMPOSE" +       name="panel_twitter_photo"/> +     <panel +       filename="panel_twitter_account.xml" +       class="lltwitteraccountpanel" +       follows="all" +       label="ACCOUNT" +       name="panel_twitter_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/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index d635b8ee93..79adb4e8bb 100755 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -16,14 +16,6 @@           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 @@ -288,6 +280,28 @@               parameter="conversation" />          </menu_item_check>          <menu_item_separator/> +      <menu_item_call +        label="Facebook..." +        name="Facebook"> +        <menu_item_call.on_click +          function="Floater.Toggle" +          parameter="social"/> +      </menu_item_call> +      <menu_item_call +        label="Twitter..." +        name="Twitter"> +        <menu_item_call.on_click +          function="Floater.Toggle" +          parameter="twitter"/> +      </menu_item_call> +      <menu_item_call +        label="Flickr..." +        name="Flickr"> +        <menu_item_call.on_click +          function="Floater.Toggle" +          parameter="flickr"/> +      </menu_item_call> +        <menu_item_separator/>          <menu           label="Voice morphing"           name="VoiceMorphing" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index e7c89db069..a3c0682aea 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6044,7 +6044,21 @@ Please select at least one type of content to search (General, Moderate, or Adul    type="notifytip">  [MESSAGE]   </notification> -     + +  <notification +   icon="notify.tga" +   name="FlickrConnect" +   type="notifytip"> +    [MESSAGE] +  </notification> + +  <notification +   icon="notify.tga" +   name="TwitterConnect" +   type="notifytip"> +    [MESSAGE] +  </notification> +    <notification     icon="notify.tga"     name="PaymentReceived" diff --git a/indra/newview/skins/default/xui/en/panel_flickr_account.xml b/indra/newview/skins/default/xui/en/panel_flickr_account.xml new file mode 100644 index 0000000000..3a38852049 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_flickr_account.xml @@ -0,0 +1,75 @@ +<panel +	 height="540" +	 width="304" +	 layout="topleft" +   name="panel_flickr_account"> +  <string +      name="flickr_connected" +      value="You are connected to Flickr as:" /> +  <string +      name="flickr_disconnected" +      value="Not connected to Flickr" /> +  <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 Flickr. +  </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 Flickr] +    </text> +  </panel> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_flickr_photo.xml b/indra/newview/skins/default/xui/en/panel_flickr_photo.xml new file mode 100644 index 0000000000..b3af271f34 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_flickr_photo.xml @@ -0,0 +1,231 @@ +    <panel +      height="540" +      width="304" +      layout="topleft" +      name="panel_flickr_photo"> +      <layout_stack +	   layout="topleft" +       border_size="0" +       height="532" +       follows="all" +       orientation="vertical" +       name="stack_photo" +       top="8"> +        <layout_panel	 +         name="snapshot_panel" +         height="507"> +            <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="title_label" +             top_pad="20" +             type="string"> +              Title: +            </text> +            <line_editor +             follows="left|top" +             height="20" +             width="250" +             left="9" +             length="1" +             max_length="256" +             name="photo_title" +             type="string"> +            </line_editor> +            <text +             length="1" +             follows="top|left|right" +             font="SansSerif" +             height="16" +             left="9" +             name="description_label" +             top_pad="10" +             type="string"> +              Description: +            </text> +            <text_editor +             follows="left|top" +             height="50" +             width="250" +             left="9" +             length="1" +             max_length="700" +             name="photo_description" +             type="string" +             word_wrap="true"> +            </text_editor> +            <check_box +             follows="left|top" +             initial_value="true" +             label="Include SL location at end of description" +             name="add_location_cb" +              left="9" +              height="16" +             top_pad="8"/> +            <text +             length="1" +             follows="top|left|right" +             font="SansSerif" +             height="16" +             left="9" +             name="tags_label" +             top_pad="10" +             type="string"> +              Tags: +            </text> +            <text +              length="1" +              follows="top|left" +              font="SansSerifSmall" +              text_color="White_50" +              height="30" +              name="tags_help_label" +              left="50" +              top_pad="-16" +              type="string"> +Separate tags with spaces +Use "" for multi-word tags +            </text> +            <text_editor +             follows="left|top" +             height="50" +             width="250" +             left="9" +             length="1" +             max_length="700" +             name="photo_tags" +             type="string" +             word_wrap="true"> +            </text_editor> +            <combo_box +             control_name="FlickrPhotoRating" +             follows="left|top" +             top_pad="16" +             left="9" +             label="Choose Flickr rating (required)..." +             name="rating_combobox" +             tool_tip="Flickr content rating" +             height="21" +             width="250"> +              <combo_box.item +               label="Safe content rating" +               name="SafeRating" +               value="1" /> +              <combo_box.item +               label="Moderate content rating" +               name="ModerateRating" +               value="2" /> +              <combo_box.item +               label="Restricted content rating" +               name="RestrictedRating" +               value="3" /> +            </combo_box> +        </layout_panel> +        <layout_panel +          name="photo_button_panel" +          height="25"> +          <button +           follows="left|top" +           top="0" +           left="9" +           height="23" +           label="Upload" +           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_snapshot_options.xml b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml index 61c8c971c2..eff60f8228 100755 --- a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml @@ -81,4 +81,40 @@      <button.commit_callback       function="Snapshot.SaveToComputer" />    </button> +  <text +    font="SansSerif" +    layout="topleft" +    length="1" +    follows="top|left" +    height="16" +    left="10" +    name="send_to_facebook_textbox" +    top_pad="10" +    type="string"> +    Send to:  [secondlife:/// Facebook] +  </text> +  <text +    font="SansSerif" +    layout="topleft" +    length="1" +    follows="top|left" +    height="16" +    left="140" +    name="send_to_twitter_textbox" +    top_pad="-16" +    type="string"> +    [secondlife:/// Twitter] +  </text> +  <text +    font="SansSerif" +    layout="topleft" +    length="1" +    follows="top|left" +    height="16" +    left="190" +    name="send_to_flickr_textbox" +    top_pad="-16" +    type="string"> +    [secondlife:/// Flickr] +  </text>  </panel> diff --git a/indra/newview/skins/default/xui/en/panel_twitter_account.xml b/indra/newview/skins/default/xui/en/panel_twitter_account.xml new file mode 100644 index 0000000000..4a413bd711 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_twitter_account.xml @@ -0,0 +1,75 @@ +<panel +	 height="400" +	 width="304" +	 layout="topleft" +   name="panel_twitter_account"> +  <string +      name="twitter_connected" +      value="You are connected to Twitter as:" /> +  <string +      name="twitter_disconnected" +      value="Not connected to Twitter" /> +  <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 Twitter. +  </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 Twitter] +    </text> +  </panel> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_twitter_photo.xml b/indra/newview/skins/default/xui/en/panel_twitter_photo.xml new file mode 100644 index 0000000000..8e2412c84e --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_twitter_photo.xml @@ -0,0 +1,156 @@ +    <panel +      height="400" +      width="304" +      layout="topleft" +      name="panel_twitter_photo"> +      <layout_stack +	   layout="topleft" +       border_size="0" +       height="392" +       follows="all" +       orientation="vertical" +       name="stack_photo" +       top="8"> +        <layout_panel +         name="text_panel" +         height="140"> +          <text +           length="1" +           follows="top|left|right" +           font="SansSerif" +           height="16" +           left="9" +           name="status_label" +           top="3" +           type="string"> +            What's happening? +          </text> +          <text_editor +           follows="left|top" +           height="87" +           width="250" +           left="9" +           length="1" +           max_length="140" +           name="photo_status" +           type="string" +           word_wrap="true"> +          </text_editor> +          <check_box +           follows="left|top" +           initial_value="true" +           label="Include a photo" +           name="add_photo_cb" +            left="9" +            height="16" +           top_pad="10"/> +        </layout_panel> +          <layout_panel +           name="snapshot_panel" +           height="227"> +            <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> +        </layout_panel> +        <layout_panel +          name="photo_button_panel" +          height="25"> +          <button +           follows="left|top" +           top="0" +           left="9" +           height="23" +           label="Tweet" +           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/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 8ac95beddb..b24cca588e 100755 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -148,13 +148,25 @@ 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> +	<!-- SLShare: Facebook, Flickr, and Twitter --> +  <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> +  <string name="SocialFlickrConnecting">Connecting to Flickr...</string> +  <string name="SocialFlickrPosting">Posting...</string> +  <string name="SocialFlickrDisconnecting">Disconnecting from Flickr...</string> +  <string name="SocialFlickrErrorConnecting">Problem connecting to Flickr</string> +  <string name="SocialFlickrErrorPosting">Problem posting to Flickr</string> +  <string name="SocialFlickrErrorDisconnecting">Problem disconnecting from Flickr</string> +  <string name="SocialTwitterConnecting">Connecting to Twitter...</string> +  <string name="SocialTwitterPosting">Posting...</string> +  <string name="SocialTwitterDisconnecting">Disconnecting from Twitter...</string> +  <string name="SocialTwitterErrorConnecting">Problem connecting to Twitter</string> +  <string name="SocialTwitterErrorPosting">Problem posting to Twitter</string> +  <string name="SocialTwitterErrorDisconnecting">Problem disconnecting from Twitter</string>  	<!-- Tooltip -->  	<string name="TooltipPerson">Person</string><!-- Object under mouse pointer is an avatar --> @@ -3442,6 +3454,12 @@ If you continue to receive this message, contact the [SUPPORT_SITE].    <string name="facebook_post_success">      You posted to Facebook.    </string> +  <string name="flickr_post_success"> +    You posted to Flickr. +  </string> +  <string name="twitter_post_success"> +    You posted to Twitter. +  </string>    <string name="no_session_message">      (IM Session Doesn't Exist) @@ -3875,6 +3893,8 @@ Try enclosing path to the editor with double quotes.    <string name="Command_Search_Label">Search</string>    <string name="Command_Snapshot_Label">Snapshot</string>    <string name="Command_Social_Label">Facebook</string> +  <string name="Command_Flickr_Label">Flickr</string> +  <string name="Command_Twitter_Label">Twitter</string>    <string name="Command_Speak_Label">Speak</string>    <string name="Command_View_Label">Camera controls</string>    <string name="Command_Voice_Label">Voice settings</string> @@ -3903,6 +3923,8 @@ Try enclosing path to the editor with double quotes.    <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_Flickr_Tooltip">Upload to Flickr</string> +  <string name="Command_Twitter_Tooltip">Twitter</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> | 
