summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rwxr-xr-xindra/newview/CMakeLists.txt12
-rwxr-xr-xindra/newview/app_settings/commands.xml32
-rwxr-xr-xindra/newview/app_settings/settings.xml2
-rwxr-xr-xindra/newview/app_settings/toolbars.xml2
-rw-r--r--indra/newview/llfacebookconnect.cpp154
-rw-r--r--indra/newview/llfacebookconnect.h2
-rw-r--r--indra/newview/llflickrconnect.cpp479
-rw-r--r--indra/newview/llflickrconnect.h98
-rw-r--r--indra/newview/llfloaterfacebook.cpp (renamed from indra/newview/llfloatersocial.cpp)209
-rw-r--r--indra/newview/llfloaterfacebook.h (renamed from indra/newview/llfloatersocial.h)36
-rw-r--r--indra/newview/llfloaterflickr.cpp703
-rw-r--r--indra/newview/llfloaterflickr.h127
-rwxr-xr-xindra/newview/llfloatersnapshot.cpp10
-rw-r--r--indra/newview/llfloatertwitter.cpp762
-rw-r--r--indra/newview/llfloatertwitter.h131
-rwxr-xr-xindra/newview/llfloaterwebcontent.cpp34
-rwxr-xr-xindra/newview/llfloaterwebcontent.h3
-rwxr-xr-xindra/newview/llmediactrl.cpp4
-rwxr-xr-xindra/newview/llmediactrl.h2
-rwxr-xr-xindra/newview/llpanelsnapshotoptions.cpp57
-rw-r--r--indra/newview/llsnapshotlivepreview.cpp12
-rw-r--r--indra/newview/lltwitterconnect.cpp473
-rw-r--r--indra/newview/lltwitterconnect.h99
-rwxr-xr-xindra/newview/llviewerfloaterreg.cpp16
-rwxr-xr-xindra/newview/llviewermedia.cpp31
-rwxr-xr-xindra/newview/llviewermedia.h5
-rwxr-xr-xindra/newview/llviewerregion.cpp3
-rwxr-xr-xindra/newview/skins/default/textures/textures.xml4
-rw-r--r--indra/newview/skins/default/textures/toolbar_icons/flickr.pngbin0 -> 15530 bytes
-rw-r--r--indra/newview/skins/default/textures/toolbar_icons/twitter.pngbin0 -> 16051 bytes
-rw-r--r--indra/newview/skins/default/xui/en/floater_facebook.xml (renamed from indra/newview/skins/default/xui/en/floater_social.xml)28
-rw-r--r--indra/newview/skins/default/xui/en/floater_flickr.xml89
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_snapshot.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_twitter.xml89
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_viewer.xml30
-rwxr-xr-xindra/newview/skins/default/xui/en/notifications.xml16
-rw-r--r--indra/newview/skins/default/xui/en/panel_facebook_account.xml (renamed from indra/newview/skins/default/xui/en/panel_social_account.xml)2
-rw-r--r--indra/newview/skins/default/xui/en/panel_facebook_photo.xml (renamed from indra/newview/skins/default/xui/en/panel_social_photo.xml)2
-rw-r--r--indra/newview/skins/default/xui/en/panel_facebook_place.xml (renamed from indra/newview/skins/default/xui/en/panel_social_place.xml)2
-rw-r--r--indra/newview/skins/default/xui/en/panel_facebook_status.xml (renamed from indra/newview/skins/default/xui/en/panel_social_status.xml)2
-rw-r--r--indra/newview/skins/default/xui/en/panel_flickr_account.xml75
-rw-r--r--indra/newview/skins/default/xui/en/panel_flickr_photo.xml231
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_snapshot_options.xml36
-rw-r--r--indra/newview/skins/default/xui/en/panel_twitter_account.xml75
-rw-r--r--indra/newview/skins/default/xui/en/panel_twitter_photo.xml178
-rwxr-xr-xindra/newview/skins/default/xui/en/strings.xml40
46 files changed, 4180 insertions, 219 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index c5e1cde4e6..828849a327 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,8 @@ set(viewer_SOURCE_FILES
llfloatereditwater.cpp
llfloaterenvironmentsettings.cpp
llfloaterevent.cpp
+ llfloaterfacebook.cpp
+ llfloaterflickr.cpp
llfloaterfonttest.cpp
llfloatergesture.cpp
llfloatergodtools.cpp
@@ -274,7 +277,6 @@ set(viewer_SOURCE_FILES
llfloatersettingsdebug.cpp
llfloatersidepanelcontainer.cpp
llfloatersnapshot.cpp
- llfloatersocial.cpp
llfloatersounddevices.cpp
llfloaterspellchecksettings.cpp
llfloatertelehub.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,8 @@ set(viewer_HEADER_FILES
llfloatereditwater.h
llfloaterenvironmentsettings.h
llfloaterevent.h
+ llfloaterfacebook.h
+ llfloaterflickr.h
llfloaterfonttest.h
llfloatergesture.h
llfloatergodtools.h
@@ -862,7 +869,6 @@ set(viewer_HEADER_FILES
llfloatersettingsdebug.h
llfloatersidepanelcontainer.h
llfloatersnapshot.h
- llfloatersocial.h
llfloatersounddevices.h
llfloaterspellchecksettings.h
llfloatertelehub.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 ce878f156b..d332583ca9 100755
--- a/indra/newview/app_settings/commands.xml
+++ b/indra/newview/app_settings/commands.xml
@@ -260,15 +260,35 @@
is_running_function="Floater.IsOpen"
is_running_parameters="snapshot"
/>
- <command name="social"
+ <command name="facebook"
available_in_toybox="true"
- icon="Command_Social_Icon"
- label_ref="Command_Social_Label"
- tooltip_ref="Command_Social_Tooltip"
+ icon="Command_Facebook_Icon"
+ label_ref="Command_Facebook_Label"
+ tooltip_ref="Command_Facebook_Tooltip"
execute_function="Floater.ToggleOrBringToFront"
- execute_parameters="social"
+ execute_parameters="facebook"
is_running_function="Floater.IsOpen"
- is_running_parameters="social"
+ is_running_parameters="facebook"
+ />
+ <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"
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index d9093c2a6d..a82d0b3f95 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -13119,7 +13119,7 @@
<key>SocialPhotoResolution</key>
<map>
<key>Comment</key>
- <string>Default resolution when sharing photo using the social floater</string>
+ <string>Default resolution when sharing photo using the social floaters</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
diff --git a/indra/newview/app_settings/toolbars.xml b/indra/newview/app_settings/toolbars.xml
index 86f9912815..d61aee9a14 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="facebook"/>
</left_toolbar>
</toolbars>
diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp
index 9a20ce8f1b..eeb28376a9 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");
@@ -67,6 +69,75 @@ void toast_user_for_success()
///////////////////////////////////////////////////////////////////////////////
//
+class LLSLShareHandler : public LLCommandHandler
+{
+public:
+ LLSLShareHandler() : LLCommandHandler("slshare", UNTRUSTED_THROTTLE) { }
+
+ bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ if (tokens.size() >= 1)
+ {
+ if (tokens[0].asString() == "connect")
+ {
+ if (tokens.size() >= 2 && tokens[1].asString() == "flickr")
+ {
+ // 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;
+ }
+ 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")
+ {
+ // this command probably came from the fbc_web browser, so close it
+ LLFloater* fbc_web = LLFloaterReg::getInstance("fbc_web");
+ if (fbc_web)
+ {
+ fbc_web->closeFloater();
+ }
+
+ // connect to facebook
+ if (query_map.has("code"))
+ {
+ LLFacebookConnect::instance().connectToFacebook(query_map["code"], query_map.get("state"));
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+};
+LLSLShareHandler gSLShareHandler;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// DEPRECATED - please remove once "fbc" is phased out of the web service
class LLFacebookConnectHandler : public LLCommandHandler
{
public:
@@ -74,23 +145,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 +256,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);
@@ -340,10 +446,12 @@ void LLFacebookConnect::openFacebookWeb(std::string url)
{
// Open the URL in an internal browser window without navigation UI
LLFloaterWebContent::Params p;
- p.url(url).show_chrome(true);
- p.url(url).allow_address_entry(false);
- p.url(url).allow_back_forward_navigation(false);
- p.url(url).trusted_content(true);
+ p.url(url);
+ p.show_chrome(true);
+ p.allow_address_entry(false);
+ p.allow_back_forward_navigation(false);
+ p.trusted_content(true);
+ p.clean_browser(true);
LLFloater *floater = LLFloaterReg::showInstance("fbc_web", p);
//the internal web browser has a bug that prevents it from gaining focus unless a mouse event occurs first (it seems).
//So when showing the internal web browser, set focus to it's containing floater "fbc_web". When a mouse event
@@ -375,9 +483,13 @@ void LLFacebookConnect::connectToFacebook(const std::string& auth_code, const st
{
LLSD body;
if (!auth_code.empty())
+ {
body["code"] = auth_code;
+ }
if (!auth_state.empty())
+ {
body["state"] = auth_state;
+ }
LLHTTPClient::put(getFacebookConnectURL("/connection"), body, new LLFacebookConnectResponder());
}
@@ -421,15 +533,25 @@ void LLFacebookConnect::postCheckin(const std::string& location, const std::stri
{
LLSD body;
if (!location.empty())
+ {
body["location"] = location;
+ }
if (!name.empty())
+ {
body["name"] = name;
+ }
if (!description.empty())
+ {
body["description"] = description;
+ }
if (!image.empty())
+ {
body["image"] = image;
+ }
if (!message.empty())
+ {
body["message"] = message;
+ }
// Note: we can use that route for different publish action. We should be able to use the same responder.
LLHTTPClient::post(getFacebookConnectURL("/share/checkin", true), body, new LLFacebookShareResponder());
diff --git a/indra/newview/llfacebookconnect.h b/indra/newview/llfacebookconnect.h
index a77ac24167..c157db2178 100644
--- a/indra/newview/llfacebookconnect.h
+++ b/indra/newview/llfacebookconnect.h
@@ -89,7 +89,7 @@ private:
LLFacebookConnect();
~LLFacebookConnect() {};
std::string getFacebookConnectURL(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..8f9f55c1ea
--- /dev/null
+++ b/indra/newview/llflickrconnect.cpp
@@ -0,0 +1,479 @@
+/**
+ * @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);
+ p.show_chrome(true);
+ p.allow_address_entry(false);
+ p.allow_back_forward_navigation(false);
+ p.trusted_content(true);
+ p.clean_browser(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/llfloatersocial.cpp b/indra/newview/llfloaterfacebook.cpp
index 2a74c8e3ea..6488e7ea00 100644
--- a/indra/newview/llfloatersocial.cpp
+++ b/indra/newview/llfloaterfacebook.cpp
@@ -1,6 +1,6 @@
/**
-* @file llfloatersocial.cpp
-* @brief Implementation of llfloatersocial
+* @file llfloaterfacebook.cpp
+* @brief Implementation of llfloaterfacebook
* @author Gilbert@lindenlab.com
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
@@ -27,7 +27,7 @@
#include "llviewerprecompiledheaders.h"
-#include "llfloatersocial.h"
+#include "llfloaterfacebook.h"
#include "llagent.h"
#include "llagentui.h"
@@ -46,11 +46,12 @@
#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");
-static LLRegisterPanelClassWrapper<LLSocialCheckinPanel> t_panel_checkin("llsocialcheckinpanel");
-static LLRegisterPanelClassWrapper<LLSocialAccountPanel> t_panel_account("llsocialaccountpanel");
+static LLRegisterPanelClassWrapper<LLFacebookStatusPanel> t_panel_status("llfacebookstatuspanel");
+static LLRegisterPanelClassWrapper<LLFacebookPhotoPanel> t_panel_photo("llfacebookphotopanel");
+static LLRegisterPanelClassWrapper<LLFacebookCheckinPanel> t_panel_checkin("llfacebookcheckinpanel");
+static LLRegisterPanelClassWrapper<LLFacebookAccountPanel> t_panel_account("llfacebookaccountpanel");
const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte
const std::string DEFAULT_CHECKIN_LOCATION_URL = "http://maps.secondlife.com/";
@@ -61,9 +62,10 @@ const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_
std::string get_map_url()
{
LLVector3d center_agent;
- if (gAgent.getRegion())
+ LLViewerRegion *regionp = gAgent.getRegion();
+ if (regionp)
{
- center_agent = gAgent.getRegion()->getCenterGlobal();
+ center_agent = regionp->getCenterGlobal();
}
int x_pos = center_agent[0] / 256.0;
int y_pos = center_agent[1] / 256.0;
@@ -72,18 +74,18 @@ std::string get_map_url()
}
///////////////////////////
-//LLSocialStatusPanel//////
+//LLFacebookStatusPanel//////
///////////////////////////
-LLSocialStatusPanel::LLSocialStatusPanel() :
+LLFacebookStatusPanel::LLFacebookStatusPanel() :
mMessageTextEditor(NULL),
mPostButton(NULL),
mCancelButton(NULL)
{
- mCommitCallbackRegistrar.add("SocialSharing.SendStatus", boost::bind(&LLSocialStatusPanel::onSend, this));
+ mCommitCallbackRegistrar.add("SocialSharing.SendStatus", boost::bind(&LLFacebookStatusPanel::onSend, this));
}
-BOOL LLSocialStatusPanel::postBuild()
+BOOL LLFacebookStatusPanel::postBuild()
{
mMessageTextEditor = getChild<LLUICtrl>("status_message");
mPostButton = getChild<LLUICtrl>("post_status_btn");
@@ -92,7 +94,7 @@ BOOL LLSocialStatusPanel::postBuild()
return LLPanel::postBuild();
}
-void LLSocialStatusPanel::draw()
+void LLFacebookStatusPanel::draw()
{
if (mMessageTextEditor && mPostButton && mCancelButton)
{
@@ -106,10 +108,10 @@ void LLSocialStatusPanel::draw()
LLPanel::draw();
}
-void LLSocialStatusPanel::onSend()
+void LLFacebookStatusPanel::onSend()
{
- LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialStatusPanel"); // just in case it is already listening
- LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialStatusPanel", boost::bind(&LLSocialStatusPanel::onFacebookConnectStateChange, this, _1));
+ LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookStatusPanel"); // just in case it is already listening
+ LLEventPumps::instance().obtain("FacebookConnectState").listen("LLFacebookStatusPanel", boost::bind(&LLFacebookStatusPanel::onFacebookConnectStateChange, this, _1));
// Connect to Facebook if necessary and then post
if (LLFacebookConnect::instance().isConnected())
@@ -122,7 +124,7 @@ void LLSocialStatusPanel::onSend()
}
}
-bool LLSocialStatusPanel::onFacebookConnectStateChange(const LLSD& data)
+bool LLFacebookStatusPanel::onFacebookConnectStateChange(const LLSD& data)
{
switch (data.get("enum").asInteger())
{
@@ -131,7 +133,7 @@ bool LLSocialStatusPanel::onFacebookConnectStateChange(const LLSD& data)
break;
case LLFacebookConnect::FB_POSTED:
- LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialStatusPanel");
+ LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookStatusPanel");
clearAndClose();
break;
}
@@ -139,7 +141,7 @@ bool LLSocialStatusPanel::onFacebookConnectStateChange(const LLSD& data)
return false;
}
-void LLSocialStatusPanel::sendStatus()
+void LLFacebookStatusPanel::sendStatus()
{
std::string message = mMessageTextEditor->getValue().asString();
if (!message.empty())
@@ -148,7 +150,7 @@ void LLSocialStatusPanel::sendStatus()
}
}
-void LLSocialStatusPanel::clearAndClose()
+void LLFacebookStatusPanel::clearAndClose()
{
mMessageTextEditor->setValue("");
@@ -160,10 +162,10 @@ void LLSocialStatusPanel::clearAndClose()
}
///////////////////////////
-//LLSocialPhotoPanel///////
+//LLFacebookPhotoPanel///////
///////////////////////////
-LLSocialPhotoPanel::LLSocialPhotoPanel() :
+LLFacebookPhotoPanel::LLFacebookPhotoPanel() :
mSnapshotPanel(NULL),
mResolutionComboBox(NULL),
mRefreshBtn(NULL),
@@ -173,11 +175,11 @@ mCaptionTextBox(NULL),
mLocationCheckbox(NULL),
mPostButton(NULL)
{
- mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLSocialPhotoPanel::onSend, this));
- mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLSocialPhotoPanel::onClickNewSnapshot, this));
+ mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLFacebookPhotoPanel::onSend, this));
+ mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLFacebookPhotoPanel::onClickNewSnapshot, this));
}
-LLSocialPhotoPanel::~LLSocialPhotoPanel()
+LLFacebookPhotoPanel::~LLFacebookPhotoPanel()
{
if(mPreviewHandle.get())
{
@@ -185,13 +187,13 @@ LLSocialPhotoPanel::~LLSocialPhotoPanel()
}
}
-BOOL LLSocialPhotoPanel::postBuild()
+BOOL LLFacebookPhotoPanel::postBuild()
{
- setVisibleCallback(boost::bind(&LLSocialPhotoPanel::onVisibilityChange, this, _2));
+ setVisibleCallback(boost::bind(&LLFacebookPhotoPanel::onVisibilityChange, this, _2));
mSnapshotPanel = getChild<LLUICtrl>("snapshot_panel");
mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox");
- mResolutionComboBox->setCommitCallback(boost::bind(&LLSocialPhotoPanel::updateResolution, this, TRUE));
+ mResolutionComboBox->setCommitCallback(boost::bind(&LLFacebookPhotoPanel::updateResolution, this, TRUE));
mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn");
mWorkingLabel = getChild<LLUICtrl>("working_lbl");
mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
@@ -203,7 +205,7 @@ BOOL LLSocialPhotoPanel::postBuild()
return LLPanel::postBuild();
}
-void LLSocialPhotoPanel::draw()
+void LLFacebookPhotoPanel::draw()
{
LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
@@ -256,13 +258,13 @@ void LLSocialPhotoPanel::draw()
LLPanel::draw();
}
-LLSnapshotLivePreview* LLSocialPhotoPanel::getPreviewView()
+LLSnapshotLivePreview* LLFacebookPhotoPanel::getPreviewView()
{
LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get();
return previewp;
}
-void LLSocialPhotoPanel::onVisibilityChange(const LLSD& new_visibility)
+void LLFacebookPhotoPanel::onVisibilityChange(const LLSD& new_visibility)
{
bool visible = new_visibility.asBoolean();
if (visible)
@@ -294,7 +296,7 @@ void LLSocialPhotoPanel::onVisibilityChange(const LLSD& new_visibility)
}
}
-void LLSocialPhotoPanel::onClickNewSnapshot()
+void LLFacebookPhotoPanel::onClickNewSnapshot()
{
LLSnapshotLivePreview* previewp = getPreviewView();
if (previewp)
@@ -305,10 +307,10 @@ void LLSocialPhotoPanel::onClickNewSnapshot()
}
}
-void LLSocialPhotoPanel::onSend()
+void LLFacebookPhotoPanel::onSend()
{
- LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialPhotoPanel"); // just in case it is already listening
- LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialPhotoPanel", boost::bind(&LLSocialPhotoPanel::onFacebookConnectStateChange, this, _1));
+ LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookPhotoPanel"); // just in case it is already listening
+ LLEventPumps::instance().obtain("FacebookConnectState").listen("LLFacebookPhotoPanel", boost::bind(&LLFacebookPhotoPanel::onFacebookConnectStateChange, this, _1));
// Connect to Facebook if necessary and then post
if (LLFacebookConnect::instance().isConnected())
@@ -321,7 +323,7 @@ void LLSocialPhotoPanel::onSend()
}
}
-bool LLSocialPhotoPanel::onFacebookConnectStateChange(const LLSD& data)
+bool LLFacebookPhotoPanel::onFacebookConnectStateChange(const LLSD& data)
{
switch (data.get("enum").asInteger())
{
@@ -330,7 +332,7 @@ bool LLSocialPhotoPanel::onFacebookConnectStateChange(const LLSD& data)
break;
case LLFacebookConnect::FB_POSTED:
- LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialPhotoPanel");
+ LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookPhotoPanel");
clearAndClose();
break;
}
@@ -338,7 +340,7 @@ bool LLSocialPhotoPanel::onFacebookConnectStateChange(const LLSD& data)
return false;
}
-void LLSocialPhotoPanel::sendPhoto()
+void LLFacebookPhotoPanel::sendPhoto()
{
// Get the caption
std::string caption = mCaptionTextBox->getValue().asString();
@@ -371,7 +373,7 @@ void LLSocialPhotoPanel::sendPhoto()
updateControls();
}
-void LLSocialPhotoPanel::clearAndClose()
+void LLFacebookPhotoPanel::clearAndClose()
{
mCaptionTextBox->setValue("");
@@ -382,7 +384,7 @@ void LLSocialPhotoPanel::clearAndClose()
}
}
-void LLSocialPhotoPanel::updateControls()
+void LLFacebookPhotoPanel::updateControls()
{
LLSnapshotLivePreview* previewp = getPreviewView();
BOOL got_bytes = previewp && previewp->getDataSize() > 0;
@@ -409,7 +411,7 @@ void LLSocialPhotoPanel::updateControls()
updateResolution(FALSE);
}
-void LLSocialPhotoPanel::updateResolution(BOOL do_update)
+void LLFacebookPhotoPanel::updateResolution(BOOL do_update)
{
LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox);
@@ -456,14 +458,14 @@ void LLSocialPhotoPanel::updateResolution(BOOL do_update)
{
lldebugs << "Will update controls" << llendl;
updateControls();
- LLSocialPhotoPanel::onClickNewSnapshot();
+ LLFacebookPhotoPanel::onClickNewSnapshot();
}
}
}
}
-void LLSocialPhotoPanel::checkAspectRatio(S32 index)
+void LLFacebookPhotoPanel::checkAspectRatio(S32 index)
{
LLSnapshotLivePreview *previewp = getPreviewView() ;
@@ -484,23 +486,23 @@ void LLSocialPhotoPanel::checkAspectRatio(S32 index)
}
}
-LLUICtrl* LLSocialPhotoPanel::getRefreshBtn()
+LLUICtrl* LLFacebookPhotoPanel::getRefreshBtn()
{
return mRefreshBtn;
}
////////////////////////
-//LLSocialCheckinPanel//
+//LLFacebookCheckinPanel//
////////////////////////
-LLSocialCheckinPanel::LLSocialCheckinPanel() :
+LLFacebookCheckinPanel::LLFacebookCheckinPanel() :
mMapUrl(""),
mReloadingMapTexture(false)
{
- mCommitCallbackRegistrar.add("SocialSharing.SendCheckin", boost::bind(&LLSocialCheckinPanel::onSend, this));
+ mCommitCallbackRegistrar.add("SocialSharing.SendCheckin", boost::bind(&LLFacebookCheckinPanel::onSend, this));
}
-BOOL LLSocialCheckinPanel::postBuild()
+BOOL LLFacebookCheckinPanel::postBuild()
{
// Keep pointers to widgets so we don't traverse the UI hierarchy too often
mPostButton = getChild<LLUICtrl>("post_place_btn");
@@ -514,7 +516,7 @@ BOOL LLSocialCheckinPanel::postBuild()
return LLPanel::postBuild();
}
-void LLSocialCheckinPanel::draw()
+void LLFacebookCheckinPanel::draw()
{
bool no_ongoing_connection = !(LLFacebookConnect::instance().isTransactionOngoing());
mPostButton->setEnabled(no_ongoing_connection);
@@ -555,10 +557,10 @@ void LLSocialCheckinPanel::draw()
LLPanel::draw();
}
-void LLSocialCheckinPanel::onSend()
+void LLFacebookCheckinPanel::onSend()
{
- LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialCheckinPanel"); // just in case it is already listening
- LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialCheckinPanel", boost::bind(&LLSocialCheckinPanel::onFacebookConnectStateChange, this, _1));
+ LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookCheckinPanel"); // just in case it is already listening
+ LLEventPumps::instance().obtain("FacebookConnectState").listen("LLFacebookCheckinPanel", boost::bind(&LLFacebookCheckinPanel::onFacebookConnectStateChange, this, _1));
// Connect to Facebook if necessary and then post
if (LLFacebookConnect::instance().isConnected())
@@ -571,7 +573,7 @@ void LLSocialCheckinPanel::onSend()
}
}
-bool LLSocialCheckinPanel::onFacebookConnectStateChange(const LLSD& data)
+bool LLFacebookCheckinPanel::onFacebookConnectStateChange(const LLSD& data)
{
switch (data.get("enum").asInteger())
{
@@ -580,7 +582,7 @@ bool LLSocialCheckinPanel::onFacebookConnectStateChange(const LLSD& data)
break;
case LLFacebookConnect::FB_POSTED:
- LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialCheckinPanel");
+ LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookCheckinPanel");
clearAndClose();
break;
}
@@ -588,7 +590,7 @@ bool LLSocialCheckinPanel::onFacebookConnectStateChange(const LLSD& data)
return false;
}
-void LLSocialCheckinPanel::sendCheckin()
+void LLFacebookCheckinPanel::sendCheckin()
{
// Get the location SLURL
LLSLURL slurl;
@@ -606,7 +608,12 @@ void LLSocialCheckinPanel::sendCheckin()
slurl_string += DEFAULT_CHECKIN_QUERY_PARAMETERS;
// Get the region name
- std::string region_name = gAgent.getRegion()->getName();
+ std::string region_name("");
+ LLViewerRegion *regionp = gAgent.getRegion();
+ if (regionp)
+ {
+ region_name = regionp->getName();
+ }
// Get the region description
std::string description;
@@ -623,7 +630,7 @@ void LLSocialCheckinPanel::sendCheckin()
LLFacebookConnect::instance().postCheckin(slurl_string, region_name, description, map_url, caption);
}
-void LLSocialCheckinPanel::clearAndClose()
+void LLFacebookCheckinPanel::clearAndClose()
{
mMessageTextEditor->setValue("");
@@ -635,23 +642,23 @@ void LLSocialCheckinPanel::clearAndClose()
}
///////////////////////////
-//LLSocialAccountPanel//////
+//LLFacebookAccountPanel//////
///////////////////////////
-LLSocialAccountPanel::LLSocialAccountPanel() :
+LLFacebookAccountPanel::LLFacebookAccountPanel() :
mAccountCaptionLabel(NULL),
mAccountNameLabel(NULL),
mPanelButtons(NULL),
mConnectButton(NULL),
mDisconnectButton(NULL)
{
- mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLSocialAccountPanel::onConnect, this));
- mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLSocialAccountPanel::onDisconnect, this));
+ mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLFacebookAccountPanel::onConnect, this));
+ mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLFacebookAccountPanel::onDisconnect, this));
- setVisibleCallback(boost::bind(&LLSocialAccountPanel::onVisibilityChange, this, _2));
+ setVisibleCallback(boost::bind(&LLFacebookAccountPanel::onVisibilityChange, this, _2));
}
-BOOL LLSocialAccountPanel::postBuild()
+BOOL LLFacebookAccountPanel::postBuild()
{
mAccountCaptionLabel = getChild<LLTextBox>("account_caption_label");
mAccountNameLabel = getChild<LLTextBox>("account_name_label");
@@ -662,7 +669,7 @@ BOOL LLSocialAccountPanel::postBuild()
return LLPanel::postBuild();
}
-void LLSocialAccountPanel::draw()
+void LLFacebookAccountPanel::draw()
{
LLFacebookConnect::EConnectionState connection_state = LLFacebookConnect::instance().getConnectionState();
@@ -677,17 +684,17 @@ void LLSocialAccountPanel::draw()
LLPanel::draw();
}
-void LLSocialAccountPanel::onVisibilityChange(const LLSD& new_visibility)
+void LLFacebookAccountPanel::onVisibilityChange(const LLSD& new_visibility)
{
bool visible = new_visibility.asBoolean();
if(visible)
{
- LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialAccountPanel");
- LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialAccountPanel", boost::bind(&LLSocialAccountPanel::onFacebookConnectStateChange, this, _1));
+ LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookAccountPanel");
+ LLEventPumps::instance().obtain("FacebookConnectState").listen("LLFacebookAccountPanel", boost::bind(&LLFacebookAccountPanel::onFacebookConnectStateChange, this, _1));
- LLEventPumps::instance().obtain("FacebookConnectInfo").stopListening("LLSocialAccountPanel");
- LLEventPumps::instance().obtain("FacebookConnectInfo").listen("LLSocialAccountPanel", boost::bind(&LLSocialAccountPanel::onFacebookConnectInfoChange, this));
+ LLEventPumps::instance().obtain("FacebookConnectInfo").stopListening("LLFacebookAccountPanel");
+ LLEventPumps::instance().obtain("FacebookConnectInfo").listen("LLFacebookAccountPanel", boost::bind(&LLFacebookAccountPanel::onFacebookConnectInfoChange, this));
//Connected
if(LLFacebookConnect::instance().isConnected())
@@ -707,12 +714,12 @@ void LLSocialAccountPanel::onVisibilityChange(const LLSD& new_visibility)
}
else
{
- LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialAccountPanel");
- LLEventPumps::instance().obtain("FacebookConnectInfo").stopListening("LLSocialAccountPanel");
+ LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLFacebookAccountPanel");
+ LLEventPumps::instance().obtain("FacebookConnectInfo").stopListening("LLFacebookAccountPanel");
}
}
-bool LLSocialAccountPanel::onFacebookConnectStateChange(const LLSD& data)
+bool LLFacebookAccountPanel::onFacebookConnectStateChange(const LLSD& data)
{
if(LLFacebookConnect::instance().isConnected())
{
@@ -730,7 +737,7 @@ bool LLSocialAccountPanel::onFacebookConnectStateChange(const LLSD& data)
return false;
}
-bool LLSocialAccountPanel::onFacebookConnectInfoChange()
+bool LLFacebookAccountPanel::onFacebookConnectInfoChange()
{
LLSD info = LLFacebookConnect::instance().getInfo();
std::string clickable_name;
@@ -746,7 +753,7 @@ bool LLSocialAccountPanel::onFacebookConnectInfoChange()
return false;
}
-void LLSocialAccountPanel::showConnectButton()
+void LLFacebookAccountPanel::showConnectButton()
{
if(!mConnectButton->getVisible())
{
@@ -755,7 +762,7 @@ void LLSocialAccountPanel::showConnectButton()
}
}
-void LLSocialAccountPanel::hideConnectButton()
+void LLFacebookAccountPanel::hideConnectButton()
{
if(mConnectButton->getVisible())
{
@@ -764,14 +771,14 @@ void LLSocialAccountPanel::hideConnectButton()
}
}
-void LLSocialAccountPanel::showDisconnectedLayout()
+void LLFacebookAccountPanel::showDisconnectedLayout()
{
mAccountCaptionLabel->setText(getString("facebook_disconnected"));
mAccountNameLabel->setText(std::string(""));
showConnectButton();
}
-void LLSocialAccountPanel::showConnectedLayout()
+void LLFacebookAccountPanel::showConnectedLayout()
{
LLFacebookConnect::instance().loadFacebookInfo();
@@ -779,7 +786,7 @@ void LLSocialAccountPanel::showConnectedLayout()
hideConnectButton();
}
-void LLSocialAccountPanel::onConnect()
+void LLFacebookAccountPanel::onConnect()
{
LLFacebookConnect::instance().checkConnectionToFacebook(true);
@@ -787,7 +794,7 @@ void LLSocialAccountPanel::onConnect()
LLViewerMedia::getCookieStore()->removeCookiesByDomain(".facebook.com");
}
-void LLSocialAccountPanel::onDisconnect()
+void LLFacebookAccountPanel::onDisconnect()
{
LLFacebookConnect::instance().disconnectFromFacebook();
@@ -795,27 +802,27 @@ void LLSocialAccountPanel::onDisconnect()
}
////////////////////////
-//LLFloaterSocial///////
+//LLFloaterFacebook///////
////////////////////////
-LLFloaterSocial::LLFloaterSocial(const LLSD& key) : LLFloater(key),
- mSocialPhotoPanel(NULL),
+LLFloaterFacebook::LLFloaterFacebook(const LLSD& key) : LLFloater(key),
+ mFacebookPhotoPanel(NULL),
mStatusErrorText(NULL),
mStatusLoadingText(NULL),
mStatusLoadingIndicator(NULL)
{
- mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterSocial::onCancel, this));
+ mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterFacebook::onCancel, this));
}
-void LLFloaterSocial::onCancel()
+void LLFloaterFacebook::onCancel()
{
closeFloater();
}
-BOOL LLFloaterSocial::postBuild()
+BOOL LLFloaterFacebook::postBuild()
{
// Keep tab of the Photo Panel
- mSocialPhotoPanel = static_cast<LLSocialPhotoPanel*>(getChild<LLUICtrl>("panel_social_photo"));
+ mFacebookPhotoPanel = static_cast<LLFacebookPhotoPanel*>(getChild<LLUICtrl>("panel_facebook_photo"));
// Connection status widgets
mStatusErrorText = getChild<LLTextBox>("connection_error_text");
mStatusLoadingText = getChild<LLTextBox>("connection_loading_text");
@@ -823,29 +830,41 @@ BOOL LLFloaterSocial::postBuild()
return LLFloater::postBuild();
}
+void LLFloaterFacebook::showPhotoPanel()
+{
+ LLTabContainer* parent = dynamic_cast<LLTabContainer*>(mFacebookPhotoPanel->getParent());
+ if (!parent)
+ {
+ llwarns << "Cannot find panel container" << llendl;
+ return;
+ }
+
+ parent->selectTabPanel(mFacebookPhotoPanel);
+}
+
// static
-void LLFloaterSocial::preUpdate()
+void LLFloaterFacebook::preUpdate()
{
- LLFloaterSocial* instance = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social");
+ LLFloaterFacebook* instance = LLFloaterReg::findTypedInstance<LLFloaterFacebook>("facebook");
if (instance)
{
//Will set file size text to 'unknown'
- instance->mSocialPhotoPanel->updateControls();
+ instance->mFacebookPhotoPanel->updateControls();
}
}
// static
-void LLFloaterSocial::postUpdate()
+void LLFloaterFacebook::postUpdate()
{
- LLFloaterSocial* instance = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social");
+ LLFloaterFacebook* instance = LLFloaterReg::findTypedInstance<LLFloaterFacebook>("facebook");
if (instance)
{
//Will set the file size text
- instance->mSocialPhotoPanel->updateControls();
+ instance->mFacebookPhotoPanel->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();
+ LLUICtrl * refresh_button = instance->mFacebookPhotoPanel->getRefreshBtn();
if (!refresh_button->getVisible())
{
@@ -855,7 +874,7 @@ void LLFloaterSocial::postUpdate()
}
}
-void LLFloaterSocial::draw()
+void LLFloaterFacebook::draw()
{
if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator)
{
diff --git a/indra/newview/llfloatersocial.h b/indra/newview/llfloaterfacebook.h
index bbe07c9704..ab6420264b 100644
--- a/indra/newview/llfloatersocial.h
+++ b/indra/newview/llfloaterfacebook.h
@@ -1,6 +1,6 @@
/**
-* @file llfloatersocial.h
-* @brief Header file for llfloatersocial
+* @file llfloaterfacebook.h
+* @brief Header file for llfloaterfacebook
* @author Gilbert@lindenlab.com
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
@@ -24,8 +24,8 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
-#ifndef LL_LLFLOATERSOCIAL_H
-#define LL_LLFLOATERSOCIAL_H
+#ifndef LL_LLFLOATERFACEBOOK_H
+#define LL_LLFLOATERFACEBOOK_H
#include "llfloater.h"
#include "lltextbox.h"
@@ -35,10 +35,10 @@ class LLIconCtrl;
class LLCheckBoxCtrl;
class LLSnapshotLivePreview;
-class LLSocialStatusPanel : public LLPanel
+class LLFacebookStatusPanel : public LLPanel
{
public:
- LLSocialStatusPanel();
+ LLFacebookStatusPanel();
BOOL postBuild();
void draw();
void onSend();
@@ -53,11 +53,11 @@ private:
LLUICtrl* mCancelButton;
};
-class LLSocialPhotoPanel : public LLPanel
+class LLFacebookPhotoPanel : public LLPanel
{
public:
- LLSocialPhotoPanel();
- ~LLSocialPhotoPanel();
+ LLFacebookPhotoPanel();
+ ~LLFacebookPhotoPanel();
BOOL postBuild();
void draw();
@@ -90,10 +90,10 @@ private:
LLUICtrl* mCancelButton;
};
-class LLSocialCheckinPanel : public LLPanel
+class LLFacebookCheckinPanel : public LLPanel
{
public:
- LLSocialCheckinPanel();
+ LLFacebookCheckinPanel();
BOOL postBuild();
void draw();
void onSend();
@@ -115,10 +115,10 @@ private:
bool mReloadingMapTexture;
};
-class LLSocialAccountPanel : public LLPanel
+class LLFacebookAccountPanel : public LLPanel
{
public:
- LLSocialAccountPanel();
+ LLFacebookAccountPanel();
BOOL postBuild();
void draw();
@@ -143,23 +143,25 @@ private:
};
-class LLFloaterSocial : public LLFloater
+class LLFloaterFacebook : public LLFloater
{
public:
- LLFloaterSocial(const LLSD& key);
+ LLFloaterFacebook(const LLSD& key);
BOOL postBuild();
void draw();
void onCancel();
+
+ void showPhotoPanel();
static void preUpdate();
static void postUpdate();
private:
- LLSocialPhotoPanel* mSocialPhotoPanel;
+ LLFacebookPhotoPanel* mFacebookPhotoPanel;
LLTextBox* mStatusErrorText;
LLTextBox* mStatusLoadingText;
LLUICtrl* mStatusLoadingIndicator;
};
-#endif // LL_LLFLOATERSOCIAL_H
+#endif // LL_LLFLOATERFACEBOOK_H
diff --git a/indra/newview/llfloaterflickr.cpp b/indra/newview/llfloaterflickr.cpp
new file mode 100644
index 0000000000..0a4c3f091b
--- /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),
+ mFlickrPhotoPanel(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
+ mFlickrPhotoPanel = 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*>(mFlickrPhotoPanel->getParent());
+ if (!parent)
+ {
+ llwarns << "Cannot find panel container" << llendl;
+ return;
+ }
+
+ parent->selectTabPanel(mFlickrPhotoPanel);
+}
+
+// static
+void LLFloaterFlickr::preUpdate()
+{
+ LLFloaterFlickr* instance = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr");
+ if (instance)
+ {
+ //Will set file size text to 'unknown'
+ instance->mFlickrPhotoPanel->updateControls();
+ }
+}
+
+// static
+void LLFloaterFlickr::postUpdate()
+{
+ LLFloaterFlickr* instance = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr");
+ if (instance)
+ {
+ //Will set the file size text
+ instance->mFlickrPhotoPanel->updateControls();
+
+ // The refresh button is initially hidden. We show it after the first update,
+ // i.e. after snapshot is taken
+ LLUICtrl * refresh_button = instance->mFlickrPhotoPanel->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..9a329d4451
--- /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* mFlickrPhotoPanel;
+ LLTextBox* mStatusErrorText;
+ LLTextBox* mStatusLoadingText;
+ LLUICtrl* mStatusLoadingIndicator;
+};
+
+#endif // LL_LLFLOATERFLICKR_H
+
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index ea385d7baf..c3efc26991 100755
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -31,7 +31,9 @@
#include "llagent.h"
#include "llfacebookconnect.h"
#include "llfloaterreg.h"
-#include "llfloatersocial.h"
+#include "llfloaterfacebook.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");
+ LLFloaterFacebook* floater_facebook = LLFloaterReg::findTypedInstance<LLFloaterFacebook>("facebook");
+ LLFloaterFlickr* floater_flickr = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr");
+ LLFloaterTwitter* floater_twitter = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter");
- if (!inst && !floater_social)
+ if (!inst && !floater_facebook && !floater_flickr && !floater_twitter)
return;
BOOL changed = FALSE;
diff --git a/indra/newview/llfloatertwitter.cpp b/indra/newview/llfloatertwitter.cpp
new file mode 100644
index 0000000000..ea263566a6
--- /dev/null
+++ b/indra/newview/llfloatertwitter.cpp
@@ -0,0 +1,762 @@
+/**
+* @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_LOCATION_URL = "http://maps.secondlife.com/";
+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),
+mStatusCounterLabel(NULL),
+mStatusTextBox(NULL),
+mLocationCheckbox(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");
+ mStatusCounterLabel = getChild<LLUICtrl>("status_counter_label");
+ mStatusTextBox = getChild<LLUICtrl>("photo_status");
+ mLocationCheckbox = getChild<LLUICtrl>("add_location_cb");
+ mLocationCheckbox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::onAddLocationToggled, this));
+ mPhotoCheckbox = getChild<LLUICtrl>("add_photo_cb");
+ mPhotoCheckbox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::onAddPhotoToggled, this));
+ 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());
+ mLocationCheckbox->setEnabled(no_ongoing_connection);
+ mPhotoCheckbox->setEnabled(no_ongoing_connection);
+
+ bool add_location = mLocationCheckbox->getValue().asBoolean();
+ bool add_photo = mPhotoCheckbox->getValue().asBoolean();
+ updateStatusTextLength(false);
+
+ // 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()) || add_location || !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::onAddLocationToggled()
+{
+ bool add_location = mLocationCheckbox->getValue().asBoolean();
+ updateStatusTextLength(!add_location);
+}
+
+void LLTwitterPhotoPanel::onAddPhotoToggled()
+{
+ bool add_photo = mPhotoCheckbox->getValue().asBoolean();
+ updateStatusTextLength(!add_photo);
+}
+
+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 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();
+
+ // Use a valid http:// URL if the scheme is secondlife://
+ LLURI slurl_uri(slurl_string);
+ if (slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME)
+ {
+ slurl_string = DEFAULT_PHOTO_LOCATION_URL;
+ }
+
+ // Add query parameters so Google Analytics can track incoming clicks!
+ slurl_string += DEFAULT_PHOTO_QUERY_PARAMETERS;
+
+ // Add it to the status (pretty crude, but we don't have a better option with photos)
+ if (status.empty())
+ status = slurl_string;
+ else
+ status = status + " " + slurl_string;
+ }
+
+ // 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::updateStatusTextLength(BOOL restore_old_status_text)
+{
+ bool add_location = mLocationCheckbox->getValue().asBoolean();
+ 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 = 140 - (add_location ? 40 : 0) - (add_photo ? 40 : 0);
+ status_text_box->setMaxTextLength(max_status_length);
+ if (restore_old_status_text)
+ {
+ 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);
+ }
+ if (mOldStatusText.length() <= max_status_length)
+ {
+ mOldStatusText = "";
+ }
+ }
+ if (status_text_box->getText().length() > max_status_length)
+ {
+ if (mOldStatusText.length() < status_text_box->getText().length() || status_text_box->getText() != mOldStatusText.substr(0, status_text_box->getText().length()))
+ {
+ mOldStatusText = status_text_box->getText();
+ }
+ status_text_box->setText(mOldStatusText.substr(0, max_status_length));
+ }
+
+ // Update the status character counter
+ int characters_remaining = max_status_length - status_text_box->getText().length();
+ mStatusCounterLabel->setValue(characters_remaining);
+ }
+
+}
+
+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),
+ mTwitterPhotoPanel(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
+ mTwitterPhotoPanel = 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*>(mTwitterPhotoPanel->getParent());
+ if (!parent)
+ {
+ llwarns << "Cannot find panel container" << llendl;
+ return;
+ }
+
+ parent->selectTabPanel(mTwitterPhotoPanel);
+}
+
+// static
+void LLFloaterTwitter::preUpdate()
+{
+ LLFloaterTwitter* instance = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter");
+ if (instance)
+ {
+ //Will set file size text to 'unknown'
+ instance->mTwitterPhotoPanel->updateControls();
+ }
+}
+
+// static
+void LLFloaterTwitter::postUpdate()
+{
+ LLFloaterTwitter* instance = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter");
+ if (instance)
+ {
+ //Will set the file size text
+ instance->mTwitterPhotoPanel->updateControls();
+
+ // The refresh button is initially hidden. We show it after the first update,
+ // i.e. after snapshot is taken
+ LLUICtrl * refresh_button = instance->mTwitterPhotoPanel->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..f267f76694
--- /dev/null
+++ b/indra/newview/llfloatertwitter.h
@@ -0,0 +1,131 @@
+/**
+* @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 onAddLocationToggled();
+ void onAddPhotoToggled();
+ void onClickNewSnapshot();
+ void onSend();
+ bool onTwitterConnectStateChange(const LLSD& data);
+
+ void sendPhoto();
+ void clearAndClose();
+
+ void updateStatusTextLength(BOOL restore_old_status_text);
+ 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 * mStatusCounterLabel;
+ LLUICtrl * mStatusTextBox;
+ LLUICtrl * mLocationCheckbox;
+ 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* mTwitterPhotoPanel;
+ LLTextBox* mStatusErrorText;
+ LLTextBox* mStatusLoadingText;
+ LLUICtrl* mStatusLoadingIndicator;
+};
+
+#endif // LL_LLFLOATERTWITTER_H
+
diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
index 76b73fcf29..4151eec3e3 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"
@@ -51,7 +53,8 @@ LLFloaterWebContent::_Params::_Params()
allow_back_forward_navigation("allow_back_forward_navigation", true),
preferred_media_size("preferred_media_size"),
trusted_content("trusted_content", false),
- show_page_title("show_page_title", true)
+ show_page_title("show_page_title", true),
+ clean_browser("clean_browser", false)
{}
LLFloaterWebContent::LLFloaterWebContent( const Params& params )
@@ -242,7 +245,7 @@ void LLFloaterWebContent::open_media(const Params& p)
LLViewerMedia::proxyWindowOpened(p.target(), p.id());
mWebBrowser->setHomePageUrl(p.url, "text/html");
mWebBrowser->setTarget(p.target);
- mWebBrowser->navigateTo(p.url, "text/html");
+ mWebBrowser->navigateTo(p.url, "text/html", p.clean_browser);
set_current_url(p.url);
@@ -253,11 +256,6 @@ void LLFloaterWebContent::open_media(const Params& p)
getChildView("address")->setEnabled(address_entry_enabled);
getChildView("popexternal")->setEnabled(address_entry_enabled);
- if (!address_entry_enabled)
- {
- mWebBrowser->setFocus(TRUE);
- }
-
if (!p.show_chrome)
{
setResizeLimits(100, 100);
@@ -303,7 +301,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();
}
@@ -436,9 +451,6 @@ void LLFloaterWebContent::set_current_url(const std::string& url)
mAddressCombo->remove(mCurrentURL);
mAddressCombo->add(mDisplayURL);
mAddressCombo->selectByValue(mDisplayURL);
-
- // Set the focus back to the web page. When setting the url, there's no point to leave the focus anywhere else.
- mWebBrowser->setFocus(TRUE);
}
}
diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h
index f22940cd07..2bb8e3271f 100755
--- a/indra/newview/llfloaterwebcontent.h
+++ b/indra/newview/llfloaterwebcontent.h
@@ -57,7 +57,8 @@ public:
allow_address_entry,
allow_back_forward_navigation,
trusted_content,
- show_page_title;
+ show_page_title,
+ clean_browser;
Optional<LLRect> preferred_media_size;
_Params();
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 2075aeed63..229542c1c4 100755
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -539,7 +539,7 @@ void LLMediaCtrl::clearCache()
////////////////////////////////////////////////////////////////////////////////
//
-void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type)
+void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type, bool clean_browser)
{
// don't browse to anything that starts with secondlife:// or sl://
const std::string protocol1 = "secondlife://";
@@ -556,7 +556,7 @@ void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type)
{
mCurrentNavUrl = url_in;
mMediaSource->setSize(mTextureWidth, mTextureHeight);
- mMediaSource->navigateTo(url_in, mime_type, mime_type.empty());
+ mMediaSource->navigateTo(url_in, mime_type, mime_type.empty(), false, clean_browser);
}
}
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 6c38c1fb56..8429d8188e 100755
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -95,7 +95,7 @@ public:
virtual BOOL handleToolTip(S32 x, S32 y, MASK mask);
// navigation
- void navigateTo( std::string url_in, std::string mime_type = "");
+ void navigateTo( std::string url_in, std::string mime_type = "", bool clean_browser = false);
void navigateBack();
void navigateHome();
void navigateForward();
diff --git a/indra/newview/llpanelsnapshotoptions.cpp b/indra/newview/llpanelsnapshotoptions.cpp
index 554fabe5b3..a7b9b6d22e 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 "llfloaterfacebook.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");
+
+ LLFloaterFacebook* facebook_floater = dynamic_cast<LLFloaterFacebook*>(LLFloaterReg::getInstance("facebook"));
+ if (facebook_floater)
+ {
+ facebook_floater->showPhotoPanel();
+ }
+ LLFloaterReg::showInstance("facebook");
+}
+
+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..9feeea1644 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -34,7 +34,9 @@
#include "lleconomy.h"
#include "llfloaterperms.h"
#include "llfloaterreg.h"
-#include "llfloatersocial.h"
+#include "llfloaterfacebook.h"
+#include "llfloaterflickr.h"
+#include "llfloatertwitter.h"
#include "llimagebmp.h"
#include "llimagej2c.h"
#include "llimagejpeg.h"
@@ -208,7 +210,9 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail
mSnapshotDelayTimer.start();
mSnapshotDelayTimer.setTimerExpirySec(delay);
LLFloaterSnapshot::preUpdate();
- LLFloaterSocial::preUpdate();
+ LLFloaterFacebook::preUpdate();
+ LLFloaterFlickr::preUpdate();
+ LLFloaterTwitter::preUpdate();
}
// Update thumbnail if requested.
@@ -765,7 +769,9 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
}
lldebugs << "done creating snapshot" << llendl;
LLFloaterSnapshot::postUpdate();
- LLFloaterSocial::postUpdate();
+ LLFloaterFacebook::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..7942b21319
--- /dev/null
+++ b/indra/newview/lltwitterconnect.cpp
@@ -0,0 +1,473 @@
+/**
+ * @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);
+ p.show_chrome(true);
+ p.allow_address_entry(false);
+ p.allow_back_forward_navigation(false);
+ p.trusted_content(true);
+ p.clean_browser(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..e38ffbbc63 100755
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -53,13 +53,15 @@
#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 "llfloaterfacebook.h"
+#include "llfloaterflickr.h"
#include "llfloaterfonttest.h"
#include "llfloatergesture.h"
#include "llfloatergodtools.h"
@@ -103,7 +105,6 @@
#include "llfloatersettingsdebug.h"
#include "llfloatersidepanelcontainer.h"
#include "llfloatersnapshot.h"
-#include "llfloatersocial.h"
#include "llfloatersounddevices.h"
#include "llfloaterspellchecksettings.h"
#include "llfloatertelehub.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"
@@ -304,7 +306,6 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater);
LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>);
LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>);
- LLFloaterReg::add("social", "floater_social.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSocial>);
LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>);
LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>);
LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>);
@@ -312,8 +313,15 @@ 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);
+
+ LLFloaterReg::add("facebook", "floater_facebook.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFacebook>);
+ LLFloaterReg::add("flickr", "floater_flickr.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFlickr>);
+ LLFloaterReg::add("twitter", "floater_twitter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTwitter>);
LLFloaterUIPreviewUtil::registerFloater();
LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBvhPreview>, "upload");
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 21fb8d519b..3a3b00a604 100755
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -429,7 +429,7 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s
// Try to find media with the same media ID
viewer_media_t media_impl = getMediaImplFromTextureID(media_entry->getMediaID());
- lldebugs << "called, current URL is \"" << media_entry->getCurrentURL()
+ lldebugs << "called, current URL is \"" << media_entry->getCurrentURL()
<< "\", previous URL is \"" << previous_url
<< "\", update_from_self is " << (update_from_self?"true":"false")
<< llendl;
@@ -1534,7 +1534,7 @@ void LLViewerMedia::createSpareBrowserMediaSource()
// popping up at the moment we start a media plugin.
if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))
{
- // The null owner will keep the browser plugin from fully initializing
+ // The null owner will keep the browser plugin from fully initializing
// (specifically, it keeps LLPluginClassMedia from negotiating a size change,
// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color)
sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0);
@@ -1543,7 +1543,7 @@ void LLViewerMedia::createSpareBrowserMediaSource()
/////////////////////////////////////////////////////////////////////////////////////////
// static
-LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource()
+LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource()
{
LLPluginClassMedia* result = sSpareBrowserMediaSource;
sSpareBrowserMediaSource = NULL;
@@ -1592,7 +1592,7 @@ std::string LLViewerMedia::getParcelAudioURL()
// static
void LLViewerMedia::initClass()
{
- gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL);
+ gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL);
sTeleportFinishConnection = LLViewerParcelMgr::getInstance()->
setTeleportFinishedCallback(boost::bind(&LLViewerMedia::onTeleportFinished));
}
@@ -1669,7 +1669,8 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id,
mNavigateSuspendedDeferred(false),
mIsUpdated(false),
mTrustedBrowser(false),
- mZoomFactor(1.0)
+ mZoomFactor(1.0),
+ mCleanBrowser(false)
{
// Set up the mute list observer if it hasn't been set up already.
@@ -1793,14 +1794,16 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type)
//////////////////////////////////////////////////////////////////////////////////////////
/*static*/
-LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target)
+LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target, bool clean_browser)
{
std::string plugin_basename = LLMIMETypes::implType(media_type);
LLPluginClassMedia* media_source = NULL;
// HACK: we always try to keep a spare running webkit plugin around to improve launch times.
// If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it.
- if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))
+ // Do not use a spare if launching with full viewer control (e.g. Facebook, Twitter and few others)
+ if ((plugin_basename == "media_plugin_webkit") &&
+ !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins") && !clean_browser)
{
media_source = LLViewerMedia::getSpareBrowserMediaSource();
if(media_source)
@@ -1812,7 +1815,6 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
return media_source;
}
}
-
if(plugin_basename.empty())
{
LL_WARNS_ONCE("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL;
@@ -1856,18 +1858,18 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
// collect 'cookies enabled' setting from prefs and send to embedded browser
bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" );
- media_source->enable_cookies( cookies_enabled );
+ media_source->enable_cookies( cookies_enabled || clean_browser);
// collect 'plugins enabled' setting from prefs and send to embedded browser
bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" );
- media_source->setPluginsEnabled( plugins_enabled );
+ media_source->setPluginsEnabled( plugins_enabled || clean_browser);
// collect 'javascript enabled' setting from prefs and send to embedded browser
bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" );
- media_source->setJavascriptEnabled( javascript_enabled );
+ media_source->setJavascriptEnabled( javascript_enabled || clean_browser);
bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging");
- media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled );
+ media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled || clean_browser);
media_source->setTarget(target);
@@ -1922,7 +1924,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
// Save the MIME type that really caused the plugin to load
mCurrentMimeType = mMimeType;
- LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget);
+ LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget, mCleanBrowser);
if (media_source)
{
@@ -2543,7 +2545,7 @@ void LLViewerMediaImpl::unload()
}
//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request)
+void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request, bool clean_browser)
{
cancelMimeTypeProbe();
@@ -2556,6 +2558,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
// Always set the current URL and MIME type.
mMediaURL = url;
mMimeType = mime_type;
+ mCleanBrowser = clean_browser;
// Clear the current media URL, since it will no longer be correct.
mCurrentMediaURL.clear();
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index fff5b3fc08..6803adfaa2 100755
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -234,7 +234,7 @@ public:
void navigateReload();
void navigateHome();
void unload();
- void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false, bool server_request = false);
+ void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false, bool server_request = false, bool clean_browser = false);
void navigateInternal();
void navigateStop();
bool handleKeyHere(KEY key, MASK mask);
@@ -289,7 +289,7 @@ public:
void setTarget(const std::string& target) { mTarget = target; }
// utility function to create a ready-to-use media instance from a desired media type.
- static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target = LLStringUtil::null);
+ static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target = LLStringUtil::null, bool clean_browser = false);
// Internally set our desired browser user agent string, including
// the Second Life version and skin name. Used because we can
@@ -464,6 +464,7 @@ private:
bool mTrustedBrowser;
std::string mTarget;
LLNotificationPtr mNotification;
+ bool mCleanBrowser; // force the creation of a clean browsing target with full options enabled
private:
BOOL mIsUpdated ;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 6018c2d250..f56a2dd04f 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1588,7 +1588,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("EstateChangeInfo");
capabilityNames.append("EventQueueGet");
capabilityNames.append("FacebookConnect");
- //capabilityNames.append("FacebookRedirect");
+ capabilityNames.append("FlickrConnect");
+ capabilityNames.append("TwitterConnect");
if (gSavedSettings.getBOOL("UseHTTPInventory"))
{
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index bb891996c9..47d105728d 100755
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -133,6 +133,8 @@ with the same filename but different name
<texture name="Command_Chat_Icon" file_name="toolbar_icons/chat.png" preload="true" />
<texture name="Command_Compass_Icon" file_name="toolbar_icons/land.png" preload="true" />
<texture name="Command_Destinations_Icon" file_name="toolbar_icons/destinations.png" preload="true" />
+ <texture name="Command_Facebook_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_Gestures_Icon" file_name="toolbar_icons/gestures.png" preload="true" />
<texture name="Command_HowTo_Icon" file_name="toolbar_icons/howto.png" preload="true" />
<texture name="Command_Inventory_Icon" file_name="toolbar_icons/inventory.png" preload="true" />
@@ -148,9 +150,9 @@ with the same filename but different name
<texture name="Command_Preferences_Icon" file_name="toolbar_icons/preferences.png" preload="true" />
<texture name="Command_Profile_Icon" file_name="toolbar_icons/profile.png" preload="true" />
<texture name="Command_Search_Icon" file_name="toolbar_icons/search.png" preload="true" />
- <texture name="Command_Social_Icon" file_name="toolbar_icons/facebook.png" preload="true" />
<texture name="Command_Snapshot_Icon" file_name="toolbar_icons/snapshot.png" preload="true" />
<texture name="Command_Speak_Icon" file_name="toolbar_icons/speak.png" preload="true" />
+ <texture name="Command_Twitter_Icon" file_name="toolbar_icons/twitter.png" preload="true" />
<texture name="Command_View_Icon" file_name="toolbar_icons/view.png" preload="true" />
<texture name="Command_Voice_Icon" file_name="toolbar_icons/nearbyvoice.png" preload="true" />
<texture name="Command_Highlighting_Icon" file_name="toolbar_icons/highlighting.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
diff --git a/indra/newview/skins/default/textures/toolbar_icons/flickr.png b/indra/newview/skins/default/textures/toolbar_icons/flickr.png
new file mode 100644
index 0000000000..7fce9f0df2
--- /dev/null
+++ b/indra/newview/skins/default/textures/toolbar_icons/flickr.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/toolbar_icons/twitter.png b/indra/newview/skins/default/textures/toolbar_icons/twitter.png
new file mode 100644
index 0000000000..a99c490887
--- /dev/null
+++ b/indra/newview/skins/default/textures/toolbar_icons/twitter.png
Binary files differ
diff --git a/indra/newview/skins/default/xui/en/floater_social.xml b/indra/newview/skins/default/xui/en/floater_facebook.xml
index b7ff374d5f..820e105e53 100644
--- a/indra/newview/skins/default/xui/en/floater_social.xml
+++ b/indra/newview/skins/default/xui/en/floater_facebook.xml
@@ -3,9 +3,9 @@
positioning="cascading"
can_close="true"
can_resize="false"
- help_topic="floater_social"
+ help_topic="floater_facebook"
layout="topleft"
- name="floater_social"
+ name="floater_facebook"
save_rect="true"
single_instance="true"
reuse_instance="true"
@@ -30,29 +30,29 @@
height="437"
halign="center">
<panel
- filename="panel_social_status.xml"
- class="llsocialstatuspanel"
+ filename="panel_facebook_status.xml"
+ class="llfacebookstatuspanel"
follows="all"
label="STATUS"
- name="panel_social_status"/>
+ name="panel_facebook_status"/>
<panel
- filename="panel_social_photo.xml"
- class="llsocialphotopanel"
+ filename="panel_facebook_photo.xml"
+ class="llfacebookphotopanel"
follows="all"
label="PHOTO"
- name="panel_social_photo"/>
+ name="panel_facebook_photo"/>
<panel
- filename="panel_social_place.xml"
- class="llsocialcheckinpanel"
+ filename="panel_facebook_place.xml"
+ class="llfacebookcheckinpanel"
follows="all"
label="CHECK IN"
- name="panel_social_place"/>
+ name="panel_facebook_place"/>
<panel
- filename="panel_social_account.xml"
- class="llsocialaccountpanel"
+ filename="panel_facebook_account.xml"
+ class="llfacebookaccountpanel"
follows="all"
label="ACCOUNT"
- name="panel_social_account"/>
+ name="panel_facebook_account"/>
</tab_container>
<panel
name="connection_status_panel"
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..751914141c
--- /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="502"
+ width="304">
+ <panel
+ height="502"
+ 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="457"
+ 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 e5e2bd4c11..74bfd2cf01 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="facebook"/>
+ </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 35f2e7b31e..f6db3aa953 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_social_account.xml b/indra/newview/skins/default/xui/en/panel_facebook_account.xml
index d7235396fe..f091d2e9b9 100644
--- a/indra/newview/skins/default/xui/en/panel_social_account.xml
+++ b/indra/newview/skins/default/xui/en/panel_facebook_account.xml
@@ -2,7 +2,7 @@
height="400"
width="304"
layout="topleft"
- name="panel_social_account">
+ name="panel_facebook_account">
<string
name="facebook_connected"
value="You are connected to Facebook as:" />
diff --git a/indra/newview/skins/default/xui/en/panel_social_photo.xml b/indra/newview/skins/default/xui/en/panel_facebook_photo.xml
index a55613b52a..19f9f2fb74 100644
--- a/indra/newview/skins/default/xui/en/panel_social_photo.xml
+++ b/indra/newview/skins/default/xui/en/panel_facebook_photo.xml
@@ -2,7 +2,7 @@
height="400"
width="304"
layout="topleft"
- name="panel_social_photo">
+ name="panel_facebook_photo">
<layout_stack
layout="topleft"
border_size="0"
diff --git a/indra/newview/skins/default/xui/en/panel_social_place.xml b/indra/newview/skins/default/xui/en/panel_facebook_place.xml
index 13e94f6998..1eea8f317b 100644
--- a/indra/newview/skins/default/xui/en/panel_social_place.xml
+++ b/indra/newview/skins/default/xui/en/panel_facebook_place.xml
@@ -2,7 +2,7 @@
height="400"
width="304"
layout="topleft"
- name="panel_social_place">
+ name="panel_facebook_place">
<layout_stack
layout="topleft"
border_size="0"
diff --git a/indra/newview/skins/default/xui/en/panel_social_status.xml b/indra/newview/skins/default/xui/en/panel_facebook_status.xml
index 54cfa3f524..50e15c2e80 100644
--- a/indra/newview/skins/default/xui/en/panel_social_status.xml
+++ b/indra/newview/skins/default/xui/en/panel_facebook_status.xml
@@ -2,7 +2,7 @@
height="400"
width="304"
layout="topleft"
- name="panel_social_status">
+ name="panel_facebook_status">
<layout_stack
layout="topleft"
border_size="0"
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..14268c1bcf
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_twitter_photo.xml
@@ -0,0 +1,178 @@
+ <panel
+ height="420"
+ width="304"
+ layout="topleft"
+ name="panel_twitter_photo">
+ <layout_stack
+ layout="topleft"
+ border_size="0"
+ height="412"
+ follows="all"
+ orientation="vertical"
+ name="stack_photo"
+ top="8">
+ <layout_panel
+ name="text_panel"
+ height="160">
+ <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
+ length="1"
+ follows="top|left"
+ font="SansSerif"
+ text_color="EmphasisColor"
+ halign="right"
+ height="16"
+ width="30"
+ left="227"
+ name="status_counter_label"
+ top="3"
+ type="string">
+ 140
+ </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 SL location"
+ name="add_location_cb"
+ left="9"
+ height="16"
+ top_pad="10"/>
+ <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 7e79d297ef..d226a72d7b 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 -->
@@ -3444,6 +3456,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)
@@ -3861,6 +3879,8 @@ Try enclosing path to the editor with double quotes.
<string name="Command_Conversations_Label">Conversations</string>
<string name="Command_Compass_Label">Compass</string>
<string name="Command_Destinations_Label">Destinations</string>
+ <string name="Command_Facebook_Label">Facebook</string>
+ <string name="Command_Flickr_Label">Flickr</string>
<string name="Command_Gestures_Label">Gestures</string>
<string name="Command_HowTo_Label">How to</string>
<string name="Command_Inventory_Label">Inventory</string>
@@ -3876,8 +3896,8 @@ Try enclosing path to the editor with double quotes.
<string name="Command_Profile_Label">Profile</string>
<string name="Command_Search_Label">Search</string>
<string name="Command_Snapshot_Label">Snapshot</string>
- <string name="Command_Social_Label">Facebook</string>
<string name="Command_Speak_Label">Speak</string>
+ <string name="Command_Twitter_Label">Twitter</string>
<string name="Command_View_Label">Camera controls</string>
<string name="Command_Voice_Label">Voice settings</string>
@@ -3889,6 +3909,8 @@ Try enclosing path to the editor with double quotes.
<string name="Command_Conversations_Tooltip">Converse with everyone</string>
<string name="Command_Compass_Tooltip">Compass</string>
<string name="Command_Destinations_Tooltip">Destinations of interest</string>
+ <string name="Command_Facebook_Tooltip">Post to Facebook</string>
+ <string name="Command_Flickr_Tooltip">Upload to Flickr</string>
<string name="Command_Gestures_Tooltip">Gestures for your avatar</string>
<string name="Command_HowTo_Tooltip">How to do common tasks</string>
<string name="Command_Inventory_Tooltip">View and use your belongings</string>
@@ -3904,8 +3926,8 @@ Try enclosing path to the editor with double quotes.
<string name="Command_Profile_Tooltip">Edit or view your profile</string>
<string name="Command_Search_Tooltip">Find places, events, people</string>
<string name="Command_Snapshot_Tooltip">Take a picture</string>
- <string name="Command_Social_Tooltip">Post to Facebook</string>
<string name="Command_Speak_Tooltip">Speak with people nearby using your microphone</string>
+ <string name="Command_Twitter_Tooltip">Twitter</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>