summaryrefslogtreecommitdiff
path: root/indra/newview/llfloatertwitter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llfloatertwitter.cpp')
-rw-r--r--indra/newview/llfloatertwitter.cpp830
1 files changed, 830 insertions, 0 deletions
diff --git a/indra/newview/llfloatertwitter.cpp b/indra/newview/llfloatertwitter.cpp
new file mode 100644
index 0000000000..0b2987a3c1
--- /dev/null
+++ b/indra/newview/llfloatertwitter.cpp
@@ -0,0 +1,830 @@
+/**
+* @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 "llfloaterbigpreview.h"
+#include "llfloaterreg.h"
+#include "lliconctrl.h"
+#include "llimagefiltersmanager.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";
+const std::string DEFAULT_STATUS_TEXT = " #SecondLife";
+
+///////////////////////////
+//LLTwitterPhotoPanel///////
+///////////////////////////
+
+LLTwitterPhotoPanel::LLTwitterPhotoPanel() :
+mSnapshotPanel(NULL),
+mResolutionComboBox(NULL),
+mRefreshBtn(NULL),
+mBtnPreview(NULL),
+mWorkingLabel(NULL),
+mThumbnailPlaceholder(NULL),
+mStatusCounterLabel(NULL),
+mStatusTextBox(NULL),
+mLocationCheckbox(NULL),
+mPhotoCheckbox(NULL),
+mBigPreviewFloater(NULL),
+mPostButton(NULL)
+{
+ mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLTwitterPhotoPanel::onSend, this));
+ mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLTwitterPhotoPanel::onClickNewSnapshot, this));
+ mCommitCallbackRegistrar.add("SocialSharing.BigPreview", boost::bind(&LLTwitterPhotoPanel::onClickBigPreview, 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->setValue("[i800,i600]"); // hardcoded defaults ftw!
+ mResolutionComboBox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::updateResolution, this, TRUE));
+ mFilterComboBox = getChild<LLUICtrl>("filters_combobox");
+ mFilterComboBox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::updateResolution, this, TRUE));
+ mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn");
+ mBtnPreview = getChild<LLButton>("big_preview_btn");
+ mWorkingLabel = getChild<LLUICtrl>("working_lbl");
+ mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
+ mStatusCounterLabel = getChild<LLUICtrl>("status_counter_label");
+ mStatusTextBox = getChild<LLUICtrl>("photo_status");
+ mStatusTextBox->setValue(DEFAULT_STATUS_TEXT);
+ 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");
+ mBigPreviewFloater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
+
+ // Update filter list
+ std::vector<std::string> filter_list = LLImageFiltersManager::getInstance()->getFiltersList();
+ LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox);
+ for (U32 i = 0; i < filter_list.size(); i++)
+ {
+ filterbox->add(filter_list[i]);
+ }
+
+ return LLPanel::postBuild();
+}
+
+// virtual
+S32 LLTwitterPhotoPanel::notify(const LLSD& info)
+{
+ if (info.has("snapshot-updating"))
+ {
+ // Disable the Post button and whatever else while the snapshot is not updated
+ // updateControls();
+ return 1;
+ }
+
+ if (info.has("snapshot-updated"))
+ {
+ // Enable the send/post/save buttons.
+ updateControls();
+
+ // The refresh button is initially hidden. We show it after the first update,
+ // i.e. after snapshot is taken
+ LLUICtrl * refresh_button = getRefreshBtn();
+ if (!refresh_button->getVisible())
+ {
+ refresh_button->setVisible(true);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+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());
+ bool photo_checked = mPhotoCheckbox->getValue().asBoolean();
+ mCancelButton->setEnabled(no_ongoing_connection);
+ mStatusTextBox->setEnabled(no_ongoing_connection);
+ mResolutionComboBox->setEnabled(no_ongoing_connection && photo_checked);
+ mFilterComboBox->setEnabled(no_ongoing_connection && photo_checked);
+ mRefreshBtn->setEnabled(no_ongoing_connection && photo_checked);
+ mBtnPreview->setEnabled(no_ongoing_connection);
+ mLocationCheckbox->setEnabled(no_ongoing_connection);
+ mPhotoCheckbox->setEnabled(no_ongoing_connection);
+
+ bool add_location = mLocationCheckbox->getValue().asBoolean();
+ bool add_photo = mPhotoCheckbox->getValue().asBoolean();
+ updateStatusTextLength(false);
+
+ // Reassign the preview floater if we have the focus and the preview exists
+ if (hasFocus() && isPreviewVisible())
+ {
+ attachPreview();
+ }
+
+ // Toggle the button state as appropriate
+ bool preview_active = (isPreviewVisible() && mBigPreviewFloater->isFloaterOwner(getParentByType<LLFloater>()));
+ mBtnPreview->setToggleState(preview_active);
+
+ // 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);
+ }
+
+ // 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()) && (add_photo || 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->setContainer(this);
+ previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
+ previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
+ previewp->setThumbnailSubsampled(TRUE); // We want the preview to reflect the *saved* image
+ previewp->setAllowRenderUI(FALSE); // We do not want the rendered UI in our snapshots
+ previewp->setAllowFullScreenPreview(FALSE); // No full screen preview in SL Share mode
+ 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)
+ {
+ previewp->updateSnapshot(TRUE);
+ }
+}
+
+void LLTwitterPhotoPanel::onClickBigPreview()
+{
+ // Toggle the preview
+ if (isPreviewVisible())
+ {
+ LLFloaterReg::hideInstance("big_preview");
+ }
+ else
+ {
+ attachPreview();
+ LLFloaterReg::showInstance("big_preview");
+ }
+}
+
+bool LLTwitterPhotoPanel::isPreviewVisible()
+{
+ return (mBigPreviewFloater && mBigPreviewFloater->getVisible());
+}
+
+void LLTwitterPhotoPanel::attachPreview()
+{
+ if (mBigPreviewFloater)
+ {
+ LLSnapshotLivePreview* previewp = getPreviewView();
+ mBigPreviewFloater->setPreview(previewp);
+ mBigPreviewFloater->setFloaterOwner(getParentByType<LLFloater>());
+ }
+}
+
+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(DEFAULT_STATUS_TEXT);
+
+ LLFloater* floater = getParentByType<LLFloater>();
+ if (floater)
+ {
+ floater->closeFloater();
+ if (mBigPreviewFloater)
+ {
+ mBigPreviewFloater->closeOnFloaterOwnerClosing(floater);
+ }
+ }
+}
+
+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_snap = previewp && previewp->getSnapshotUpToDate();
+
+ // *TODO: Separate maximum size for Web images from postcards
+ lldebugs << "Is snapshot up-to-date? " << got_snap << llendl;
+
+ updateResolution(FALSE);
+}
+
+void LLTwitterPhotoPanel::updateResolution(BOOL do_update)
+{
+ LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox);
+ LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox);
+
+ 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];
+
+ // Note : index 0 of the filter drop down is assumed to be "No filter" in whichever locale
+ std::string filter_name = (filterbox->getCurrentIndex() ? filterbox->getSimple() : "");
+
+ 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);
+ if (do_update)
+ {
+ previewp->updateSnapshot(TRUE);
+ updateControls();
+ }
+ }
+ // Get the old filter, compare to the current one "filter_name" and set if changed
+ std::string original_filter = previewp->getFilter();
+ if (original_filter != filter_name)
+ {
+ previewp->setFilter(filter_name);
+ if (do_update)
+ {
+ previewp->updateSnapshot(FALSE, TRUE);
+ updateControls();
+ }
+ }
+ }
+}
+
+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::onClose(bool app_quitting)
+{
+ LLFloaterBigPreview* big_preview_floater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
+ if (big_preview_floater)
+ {
+ big_preview_floater->closeOnFloaterOwnerClosing(this);
+ }
+ LLFloater::onClose(app_quitting);
+}
+
+void LLFloaterTwitter::onCancel()
+{
+ LLFloaterBigPreview* big_preview_floater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
+ if (big_preview_floater)
+ {
+ big_preview_floater->closeOnFloaterOwnerClosing(this);
+ }
+ 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);
+}
+
+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();
+}
+