merge changes for storm-1580

master
Oz Linden 2011-11-08 15:06:43 -05:00
commit 22dd6acbc9
38 changed files with 3560 additions and 1382 deletions

View File

@ -219,7 +219,6 @@ set(viewer_SOURCE_FILES
llfloateropenobject.cpp
llfloaterpay.cpp
llfloaterperms.cpp
llfloaterpostcard.cpp
llfloaterpostprocess.cpp
llfloaterpreference.cpp
llfloaterproperties.cpp
@ -396,6 +395,12 @@ set(viewer_SOURCE_FILES
llpanelprimmediacontrols.cpp
llpanelprofile.cpp
llpanelprofileview.cpp
llpanelsnapshot.cpp
llpanelsnapshotinventory.cpp
llpanelsnapshotlocal.cpp
llpanelsnapshotoptions.cpp
llpanelsnapshotpostcard.cpp
llpanelsnapshotprofile.cpp
llpanelteleporthistory.cpp
llpaneltiptoast.cpp
llpanelvoiceeffect.cpp
@ -414,6 +419,7 @@ set(viewer_SOURCE_FILES
llpopupview.cpp
llpolymesh.cpp
llpolymorph.cpp
llpostcard.cpp
llpreview.cpp
llpreviewanim.cpp
llpreviewgesture.cpp
@ -603,6 +609,7 @@ set(viewer_SOURCE_FILES
llwearablelist.cpp
llwearabletype.cpp
llweb.cpp
llwebprofile.cpp
llwebsharing.cpp
llwind.cpp
llwindowlistener.cpp
@ -786,7 +793,6 @@ set(viewer_HEADER_FILES
llfloateropenobject.h
llfloaterpay.h
llfloaterperms.h
llfloaterpostcard.h
llfloaterpostprocess.h
llfloaterpreference.h
llfloaterproperties.h
@ -957,6 +963,7 @@ set(viewer_HEADER_FILES
llpanelprimmediacontrols.h
llpanelprofile.h
llpanelprofileview.h
llpanelsnapshot.h
llpanelteleporthistory.h
llpaneltiptoast.h
llpanelvoicedevicesettings.h
@ -975,6 +982,7 @@ set(viewer_HEADER_FILES
llpolymesh.h
llpolymorph.h
llpopupview.h
llpostcard.h
llpreview.h
llpreviewanim.h
llpreviewgesture.h
@ -1164,6 +1172,7 @@ set(viewer_HEADER_FILES
llwearablelist.h
llwearabletype.h
llweb.h
llwebprofile.h
llwebsharing.h
llwind.h
llwindowlistener.h

View File

@ -1605,17 +1605,6 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>CloseSnapshotOnKeep</key>
<map>
<key>Comment</key>
<string>Close snapshot window after saving snapshot</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>CmdLineDisableVoice</key>
<map>
<key>Comment</key>
@ -4667,6 +4656,17 @@
<string>0.0.0</string>
</map>
<key>LastSnapshotToProfileHeight</key>
<map>
<key>Comment</key>
<string>The height of the last profile snapshot, in px</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>768</integer>
</map>
<key>LastSnapshotToEmailHeight</key>
<map>
<key>Comment</key>
@ -4678,6 +4678,17 @@
<key>Value</key>
<integer>768</integer>
</map>
<key>LastSnapshotToProfileWidth</key>
<map>
<key>Comment</key>
<string>The width of the last profile snapshot, in px</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>1024</integer>
</map>
<key>LastSnapshotToEmailWidth</key>
<map>
<key>Comment</key>
@ -4733,17 +4744,6 @@
<key>Value</key>
<integer>512</integer>
</map>
<key>LastSnapshotType</key>
<map>
<key>Comment</key>
<string>Select this as next type of snapshot to take (0 = postcard, 1 = texture, 2 = local image)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>LeftClickShowMenu</key>
<map>
<key>Comment</key>
@ -10608,6 +10608,17 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotProfileLastResolution</key>
<map>
<key>Comment</key>
<string>Take next profile snapshot at this resolution</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotPostcardLastResolution</key>
<map>
<key>Comment</key>

View File

@ -78,6 +78,8 @@ void on_new_single_inventory_upload_complete(
const LLSD& server_response,
S32 upload_price)
{
bool success = false;
if ( upload_price > 0 )
{
// this upload costed us L$, update our balance
@ -152,6 +154,7 @@ void on_new_single_inventory_upload_complete(
gInventory.updateItem(item);
gInventory.notifyObservers();
success = true;
// Show the preview panel for textures and sounds to let
// user know that the image (or snapshot) arrived intact.
@ -175,6 +178,13 @@ void on_new_single_inventory_upload_complete(
// remove the "Uploading..." message
LLUploadDialog::modalUploadFinished();
// Let the Snapshot floater know we have finished uploading a snapshot to inventory.
LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot");
if (asset_type == LLAssetType::AT_TEXTURE && floater_snapshot)
{
floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", success).with("msg", "inventory")));
}
}
LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data,

View File

@ -1,384 +0,0 @@
/**
* @file llfloaterpostcard.cpp
* @brief Postcard send floater, allows setting name, e-mail address, etc.
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "llfloaterpostcard.h"
#include "llfontgl.h"
#include "llsys.h"
#include "llgl.h"
#include "v3dmath.h"
#include "lldir.h"
#include "llagent.h"
#include "llui.h"
#include "lllineeditor.h"
#include "llbutton.h"
#include "lltexteditor.h"
#include "llfloaterreg.h"
#include "llnotificationsutil.h"
#include "llviewercontrol.h"
#include "llviewernetwork.h"
#include "lluictrlfactory.h"
#include "lluploaddialog.h"
#include "llviewerstats.h"
#include "llviewerwindow.h"
#include "llstatusbar.h"
#include "llviewerregion.h"
#include "lleconomy.h"
#include "message.h"
#include "llimagejpeg.h"
#include "llimagej2c.h"
#include "llvfile.h"
#include "llvfs.h"
#include "llviewertexture.h"
#include "llassetuploadresponders.h"
#include "llagentui.h"
#include <boost/regex.hpp> //boost.regex lib
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
///----------------------------------------------------------------------------
///----------------------------------------------------------------------------
/// Class LLFloaterPostcard
///----------------------------------------------------------------------------
LLFloaterPostcard::LLFloaterPostcard(const LLSD& key)
: LLFloater(key),
mJPEGImage(NULL),
mViewerImage(NULL),
mHasFirstMsgFocus(false)
{
}
// Destroys the object
LLFloaterPostcard::~LLFloaterPostcard()
{
mJPEGImage = NULL; // deletes image
}
BOOL LLFloaterPostcard::postBuild()
{
// pick up the user's up-to-date email address
gAgent.sendAgentUserInfoRequest();
childSetAction("cancel_btn", onClickCancel, this);
childSetAction("send_btn", onClickSend, this);
getChildView("from_form")->setEnabled(FALSE);
std::string name_string;
LLAgentUI::buildFullname(name_string);
getChild<LLUICtrl>("name_form")->setValue(LLSD(name_string));
// For the first time a user focusess to .the msg box, all text will be selected.
getChild<LLUICtrl>("msg_form")->setFocusChangedCallback(boost::bind(onMsgFormFocusRecieved, _1, this));
getChild<LLUICtrl>("to_form")->setFocus(TRUE);
return TRUE;
}
// static
LLFloaterPostcard* LLFloaterPostcard::showFromSnapshot(LLImageJPEG *jpeg, LLViewerTexture *img, const LLVector2 &image_scale, const LLVector3d& pos_taken_global)
{
// Take the images from the caller
// It's now our job to clean them up
LLFloaterPostcard* instance = LLFloaterReg::showTypedInstance<LLFloaterPostcard>("postcard", LLSD(img->getID()));
if (instance) // may be 0 if we're in mouselook mode
{
instance->mJPEGImage = jpeg;
instance->mViewerImage = img;
instance->mImageScale = image_scale;
instance->mPosTakenGlobal = pos_taken_global;
}
return instance;
}
void LLFloaterPostcard::draw()
{
LLGLSUIDefault gls_ui;
LLFloater::draw();
if(!isMinimized() && mViewerImage.notNull() && mJPEGImage.notNull())
{
// Force the texture to be 100% opaque when the floater is focused.
F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
LLRect rect(getRect());
// first set the max extents of our preview
rect.translate(-rect.mLeft, -rect.mBottom);
rect.mLeft += 320;
rect.mRight -= 10;
rect.mTop -= 27;
rect.mBottom = rect.mTop - 130;
// then fix the aspect ratio
F32 ratio = (F32)mJPEGImage->getWidth() / (F32)mJPEGImage->getHeight();
if ((F32)rect.getWidth() / (F32)rect.getHeight() >= ratio)
{
rect.mRight = LLRect::tCoordType((F32)rect.mLeft + ((F32)rect.getHeight() * ratio));
}
else
{
rect.mBottom = LLRect::tCoordType((F32)rect.mTop - ((F32)rect.getWidth() / ratio));
}
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gl_rect_2d(rect, LLColor4(0.f, 0.f, 0.f, 1.f) % alpha);
rect.stretch(-1);
}
{
glMatrixMode(GL_TEXTURE);
glPushMatrix();
{
glScalef(mImageScale.mV[VX], mImageScale.mV[VY], 1.f);
glMatrixMode(GL_MODELVIEW);
gl_draw_scaled_image(rect.mLeft,
rect.mBottom,
rect.getWidth(),
rect.getHeight(),
mViewerImage.get(),
LLColor4::white % alpha);
}
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
}
}
// static
void LLFloaterPostcard::onClickCancel(void* data)
{
if (data)
{
LLFloaterPostcard *self = (LLFloaterPostcard *)data;
self->closeFloater(false);
}
}
class LLSendPostcardResponder : public LLAssetUploadResponder
{
public:
LLSendPostcardResponder(const LLSD &post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type):
LLAssetUploadResponder(post_data, vfile_id, asset_type)
{
}
// *TODO define custom uploadFailed here so it's not such a generic message
void uploadComplete(const LLSD& content)
{
// we don't care about what the server returns from this post, just clean up the UI
LLUploadDialog::modalUploadFinished();
}
};
// static
void LLFloaterPostcard::onClickSend(void* data)
{
if (data)
{
LLFloaterPostcard *self = (LLFloaterPostcard *)data;
std::string from(self->getChild<LLUICtrl>("from_form")->getValue().asString());
std::string to(self->getChild<LLUICtrl>("to_form")->getValue().asString());
boost::regex emailFormat("[A-Za-z0-9.%+-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}(,[ \t]*[A-Za-z0-9.%+-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,})*");
if (to.empty() || !boost::regex_match(to, emailFormat))
{
LLNotificationsUtil::add("PromptRecipientEmail");
return;
}
if (from.empty() || !boost::regex_match(from, emailFormat))
{
LLNotificationsUtil::add("PromptSelfEmail");
return;
}
std::string subject(self->getChild<LLUICtrl>("subject_form")->getValue().asString());
if(subject.empty() || !self->mHasFirstMsgFocus)
{
LLNotificationsUtil::add("PromptMissingSubjMsg", LLSD(), LLSD(), boost::bind(&LLFloaterPostcard::missingSubjMsgAlertCallback, self, _1, _2));
return;
}
if (self->mJPEGImage.notNull())
{
self->sendPostcard();
}
else
{
LLNotificationsUtil::add("ErrorProcessingSnapshot");
}
}
}
// static
void LLFloaterPostcard::uploadCallback(const LLUUID& asset_id, void *user_data, S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed)
{
LLFloaterPostcard *self = (LLFloaterPostcard *)user_data;
LLUploadDialog::modalUploadFinished();
if (result)
{
LLSD args;
args["REASON"] = std::string(LLAssetStorage::getErrorString(result));
LLNotificationsUtil::add("ErrorUploadingPostcard", args);
}
else
{
// only create the postcard once the upload succeeds
// request the postcard
LLMessageSystem* msg = gMessageSystem;
msg->newMessage("SendPostcard");
msg->nextBlock("AgentData");
msg->addUUID("AgentID", gAgent.getID());
msg->addUUID("SessionID", gAgent.getSessionID());
msg->addUUID("AssetID", self->mAssetID);
msg->addVector3d("PosGlobal", self->mPosTakenGlobal);
msg->addString("To", self->getChild<LLUICtrl>("to_form")->getValue().asString());
msg->addString("From", self->getChild<LLUICtrl>("from_form")->getValue().asString());
msg->addString("Name", self->getChild<LLUICtrl>("name_form")->getValue().asString());
msg->addString("Subject", self->getChild<LLUICtrl>("subject_form")->getValue().asString());
msg->addString("Msg", self->getChild<LLUICtrl>("msg_form")->getValue().asString());
msg->addBOOL("AllowPublish", FALSE);
msg->addBOOL("MaturePublish", FALSE);
gAgent.sendReliableMessage();
}
self->closeFloater();
}
// static
void LLFloaterPostcard::updateUserInfo(const std::string& email)
{
LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("postcard");
for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin();
iter != inst_list.end(); ++iter)
{
LLFloater* instance = *iter;
const std::string& text = instance->getChild<LLUICtrl>("from_form")->getValue().asString();
if (text.empty())
{
// there's no text in this field yet, pre-populate
instance->getChild<LLUICtrl>("from_form")->setValue(LLSD(email));
}
}
}
void LLFloaterPostcard::onMsgFormFocusRecieved(LLFocusableElement* receiver, void* data)
{
LLFloaterPostcard* self = (LLFloaterPostcard *)data;
if(self)
{
LLTextEditor* msgForm = self->getChild<LLTextEditor>("msg_form");
if(msgForm && msgForm == receiver && msgForm->hasFocus() && !(self->mHasFirstMsgFocus))
{
self->mHasFirstMsgFocus = true;
msgForm->setText(LLStringUtil::null);
}
}
}
bool LLFloaterPostcard::missingSubjMsgAlertCallback(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if(0 == option)
{
// User clicked OK
if((getChild<LLUICtrl>("subject_form")->getValue().asString()).empty())
{
// Stuff the subject back into the form.
getChild<LLUICtrl>("subject_form")->setValue(getString("default_subject"));
}
if(!mHasFirstMsgFocus)
{
// The user never switched focus to the messagee window.
// Using the default string.
getChild<LLUICtrl>("msg_form")->setValue(getString("default_message"));
}
sendPostcard();
}
return false;
}
void LLFloaterPostcard::sendPostcard()
{
mTransactionID.generate();
mAssetID = mTransactionID.makeAssetID(gAgent.getSecureSessionID());
LLVFile::writeFile(mJPEGImage->getData(), mJPEGImage->getDataSize(), gVFS, mAssetID, LLAssetType::AT_IMAGE_JPEG);
// upload the image
std::string url = gAgent.getRegion()->getCapability("SendPostcard");
if(!url.empty())
{
llinfos << "Send Postcard via capability" << llendl;
LLSD body = LLSD::emptyMap();
// the capability already encodes: agent ID, region ID
body["pos-global"] = mPosTakenGlobal.getValue();
body["to"] = getChild<LLUICtrl>("to_form")->getValue().asString();
body["from"] = getChild<LLUICtrl>("from_form")->getValue().asString();
body["name"] = getChild<LLUICtrl>("name_form")->getValue().asString();
body["subject"] = getChild<LLUICtrl>("subject_form")->getValue().asString();
body["msg"] = getChild<LLUICtrl>("msg_form")->getValue().asString();
LLHTTPClient::post(url, body, new LLSendPostcardResponder(body, mAssetID, LLAssetType::AT_IMAGE_JPEG));
}
else
{
gAssetStorage->storeAssetData(mTransactionID, LLAssetType::AT_IMAGE_JPEG, &uploadCallback, (void *)this, FALSE);
}
// give user feedback of the event
gViewerWindow->playSnapshotAnimAndSound();
LLUploadDialog::modalUploadDialog(getString("upload_message"));
// don't destroy the window until the upload is done
// this way we keep the information in the form
setVisible(FALSE);
// also remove any dependency on another floater
// so that we can be sure to outlive it while we
// need to.
LLFloater* dependee = getDependee();
if (dependee)
dependee->removeDependentFloater(this);
}

View File

@ -1,79 +0,0 @@
/**
* @file llfloaterpostcard.h
* @brief Postcard send floater, allows setting name, e-mail address, etc.
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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_LLFLOATERPOSTCARD_H
#define LL_LLFLOATERPOSTCARD_H
#include "llfloater.h"
#include "llcheckboxctrl.h"
#include "llpointer.h"
class LLTextEditor;
class LLLineEditor;
class LLButton;
class LLViewerTexture;
class LLImageJPEG;
class LLFloaterPostcard
: public LLFloater
{
public:
LLFloaterPostcard(const LLSD& key);
virtual ~LLFloaterPostcard();
virtual BOOL postBuild();
virtual void draw();
static LLFloaterPostcard* showFromSnapshot(LLImageJPEG *jpeg, LLViewerTexture *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global);
static void onClickCancel(void* data);
static void onClickSend(void* data);
static void uploadCallback(const LLUUID& asset_id,
void *user_data,
S32 result, LLExtStat ext_status);
static void updateUserInfo(const std::string& email);
static void onMsgFormFocusRecieved(LLFocusableElement* receiver, void* data);
bool missingSubjMsgAlertCallback(const LLSD& notification, const LLSD& response);
void sendPostcard();
private:
LLPointer<LLImageJPEG> mJPEGImage;
LLPointer<LLViewerTexture> mViewerImage;
LLTransactionID mTransactionID;
LLAssetID mAssetID;
LLVector2 mImageScale;
LLVector3d mPosTakenGlobal;
bool mHasFirstMsgFocus;
};
#endif // LL_LLFLOATERPOSTCARD_H

File diff suppressed because it is too large Load Diff

View File

@ -27,11 +27,15 @@
#ifndef LL_LLFLOATERSNAPSHOT_H
#define LL_LLFLOATERSNAPSHOT_H
#include "llimage.h"
#include "llfloater.h"
class LLSpinCtrl;
class LLFloaterSnapshot : public LLFloater
{
LOG_CLASS(LLFloaterSnapshot);
public:
typedef enum e_snapshot_format
{
@ -47,20 +51,29 @@ public:
/*virtual*/ void draw();
/*virtual*/ void onOpen(const LLSD& key);
/*virtual*/ void onClose(bool app_quitting);
/*virtual*/ S32 notify(const LLSD& info);
static void update();
static S32 getUIWinHeightLong() {return sUIWinHeightLong ;}
static S32 getUIWinHeightShort() {return sUIWinHeightShort ;}
static S32 getUIWinWidth() {return sUIWinWidth ;}
// TODO: create a snapshot model instead
static LLFloaterSnapshot* getInstance();
static void saveTexture();
static void saveLocal();
static void preUpdate();
static void postUpdate();
static void postSave();
static void postPanelSwitch();
static LLPointer<LLImageFormatted> getImageData();
static const LLVector3d& getPosTakenGlobal();
static void setAgentEmail(const std::string& email);
static const LLRect& getThumbnailPlaceholderRect() { return sThumbnailPlaceholder->getRect(); }
private:
static LLUICtrl* sThumbnailPlaceholder;
class Impl;
Impl& impl;
static S32 sUIWinHeightLong ;
static S32 sUIWinHeightShort ;
static S32 sUIWinWidth ;
};
class LLSnapshotFloaterView : public LLFloaterView

View File

@ -0,0 +1,195 @@
/**
* @file llpanelsnapshot.cpp
* @brief Snapshot panel base class
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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 "llpanelsnapshot.h"
// libs
#include "llcombobox.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"
#include "lltrans.h"
// newview
#include "llsidetraypanelcontainer.h"
#include "llviewercontrol.h" // gSavedSettings
// virtual
BOOL LLPanelSnapshot::postBuild()
{
getChild<LLUICtrl>(getImageSizeComboName())->setCommitCallback(boost::bind(&LLPanelSnapshot::onResolutionComboCommit, this, _1));
getChild<LLUICtrl>(getWidthSpinnerName())->setCommitCallback(boost::bind(&LLPanelSnapshot::onCustomResolutionCommit, this));
getChild<LLUICtrl>(getHeightSpinnerName())->setCommitCallback(boost::bind(&LLPanelSnapshot::onCustomResolutionCommit, this));
getChild<LLUICtrl>(getAspectRatioCBName())->setCommitCallback(boost::bind(&LLPanelSnapshot::onKeepAspectRatioCommit, this, _1));
updateControls(LLSD());
return TRUE;
}
// virtual
void LLPanelSnapshot::onOpen(const LLSD& key)
{
S32 old_format = gSavedSettings.getS32("SnapshotFormat");
S32 new_format = (S32) getImageFormat();
gSavedSettings.setS32("SnapshotFormat", new_format);
setCtrlsEnabled(true);
// Switching panels will likely change image format.
// Not updating preview right away may lead to errors,
// e.g. attempt to send a large BMP image by email.
if (old_format != new_format)
{
LLFloaterSnapshot::getInstance()->notify(LLSD().with("image-format-change", true));
}
updateCustomResControls();
}
LLFloaterSnapshot::ESnapshotFormat LLPanelSnapshot::getImageFormat() const
{
return LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG;
}
LLSpinCtrl* LLPanelSnapshot::getWidthSpinner()
{
return getChild<LLSpinCtrl>(getWidthSpinnerName());
}
LLSpinCtrl* LLPanelSnapshot::getHeightSpinner()
{
return getChild<LLSpinCtrl>(getHeightSpinnerName());
}
S32 LLPanelSnapshot::getTypedPreviewWidth() const
{
return getChild<LLUICtrl>(getWidthSpinnerName())->getValue().asInteger();
}
S32 LLPanelSnapshot::getTypedPreviewHeight() const
{
return getChild<LLUICtrl>(getHeightSpinnerName())->getValue().asInteger();
}
void LLPanelSnapshot::enableAspectRatioCheckbox(BOOL enable)
{
getChild<LLUICtrl>(getAspectRatioCBName())->setEnabled(enable);
}
LLSideTrayPanelContainer* LLPanelSnapshot::getParentContainer()
{
LLSideTrayPanelContainer* parent = dynamic_cast<LLSideTrayPanelContainer*>(getParent());
if (!parent)
{
llwarns << "Cannot find panel container" << llendl;
return NULL;
}
return parent;
}
// virtual
void LLPanelSnapshot::updateCustomResControls()
{
LLComboBox* combo = getChild<LLComboBox>(getImageSizeComboName());
S32 selected_idx = combo->getFirstSelectedIndex();
const bool enable = selected_idx == (combo->getItemCount() - 1); // Current Window or Custom selected
getChild<LLUICtrl>(getWidthSpinnerName())->setEnabled(enable);
getChild<LLSpinCtrl>(getWidthSpinnerName())->setAllowEdit(enable);
getChild<LLUICtrl>(getHeightSpinnerName())->setEnabled(enable);
getChild<LLSpinCtrl>(getHeightSpinnerName())->setAllowEdit(enable);
enableAspectRatioCheckbox(enable);
}
void LLPanelSnapshot::updateImageQualityLevel()
{
LLSliderCtrl* quality_slider = getChild<LLSliderCtrl>("image_quality_slider");
S32 quality_val = llfloor((F32) quality_slider->getValue().asReal());
std::string quality_lvl;
if (quality_val < 20)
{
quality_lvl = LLTrans::getString("snapshot_quality_very_low");
}
else if (quality_val < 40)
{
quality_lvl = LLTrans::getString("snapshot_quality_low");
}
else if (quality_val < 60)
{
quality_lvl = LLTrans::getString("snapshot_quality_medium");
}
else if (quality_val < 80)
{
quality_lvl = LLTrans::getString("snapshot_quality_high");
}
else
{
quality_lvl = LLTrans::getString("snapshot_quality_very_high");
}
getChild<LLTextBox>("image_quality_level")->setTextArg("[QLVL]", quality_lvl);
}
void LLPanelSnapshot::goBack()
{
LLSideTrayPanelContainer* parent = getParentContainer();
if (parent)
{
parent->openPreviousPanel();
parent->getCurrentPanel()->onOpen(LLSD());
}
}
void LLPanelSnapshot::cancel()
{
goBack();
LLFloaterSnapshot::getInstance()->notify(LLSD().with("set-ready", true));
}
void LLPanelSnapshot::onCustomResolutionCommit()
{
LLSD info;
info["w"] = getChild<LLUICtrl>(getWidthSpinnerName())->getValue().asInteger();
info["h"] = getChild<LLUICtrl>(getHeightSpinnerName())->getValue().asInteger();
LLFloaterSnapshot::getInstance()->notify(LLSD().with("custom-res-change", info));
}
void LLPanelSnapshot::onResolutionComboCommit(LLUICtrl* ctrl)
{
updateCustomResControls();
LLSD info;
info["combo-res-change"]["control-name"] = ctrl->getName();
LLFloaterSnapshot::getInstance()->notify(info);
}
void LLPanelSnapshot::onKeepAspectRatioCommit(LLUICtrl* ctrl)
{
LLFloaterSnapshot::getInstance()->notify(LLSD().with("keep-aspect-change", ctrl->getValue().asBoolean()));
}

View File

@ -0,0 +1,69 @@
/**
* @file llpanelsnapshot.h
* @brief Snapshot panel base class
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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_LLPANELSNAPSHOT_H
#define LL_LLPANELSNAPSHOT_H
#include "llfloatersnapshot.h"
class LLSideTrayPanelContainer;
/**
* Snapshot panel base class.
*/
class LLPanelSnapshot: public LLPanel
{
public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
virtual std::string getWidthSpinnerName() const = 0;
virtual std::string getHeightSpinnerName() const = 0;
virtual std::string getAspectRatioCBName() const = 0;
virtual std::string getImageSizeComboName() const = 0;
virtual S32 getTypedPreviewWidth() const;
virtual S32 getTypedPreviewHeight() const;
virtual LLSpinCtrl* getWidthSpinner();
virtual LLSpinCtrl* getHeightSpinner();
virtual void enableAspectRatioCheckbox(BOOL enable);
virtual LLFloaterSnapshot::ESnapshotFormat getImageFormat() const;
virtual void updateControls(const LLSD& info) = 0; ///< Update controls from saved settings
protected:
LLSideTrayPanelContainer* getParentContainer();
virtual void updateCustomResControls();
void updateImageQualityLevel();
void goBack(); ///< Switch to the default (Snapshot Options) panel
void cancel();
// common UI callbacks
void onCustomResolutionCommit();
void onResolutionComboCommit(LLUICtrl* ctrl);
void onKeepAspectRatioCommit(LLUICtrl* ctrl);
};
#endif // LL_LLPANELSNAPSHOT_H

View File

@ -0,0 +1,109 @@
/**
* @file llpanelsnapshotinventory.cpp
* @brief The panel provides UI for saving snapshot as an inventory texture.
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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 "llcombobox.h"
#include "lleconomy.h"
#include "llsidetraypanelcontainer.h"
#include "llspinctrl.h"
#include "llfloatersnapshot.h" // FIXME: replace with a snapshot storage model
#include "llpanelsnapshot.h"
#include "llviewercontrol.h" // gSavedSettings
/**
* The panel provides UI for saving snapshot as an inventory texture.
*/
class LLPanelSnapshotInventory
: public LLPanelSnapshot
{
LOG_CLASS(LLPanelSnapshotInventory);
public:
LLPanelSnapshotInventory();
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
private:
/*virtual*/ void updateCustomResControls(); ///< Show/hide custom resolution controls (spinners and checkbox)
/*virtual*/ std::string getWidthSpinnerName() const { return "inventory_snapshot_width"; }
/*virtual*/ std::string getHeightSpinnerName() const { return "inventory_snapshot_height"; }
/*virtual*/ std::string getAspectRatioCBName() const { return "inventory_keep_aspect_check"; }
/*virtual*/ std::string getImageSizeComboName() const { return "texture_size_combo"; }
/*virtual*/ void updateControls(const LLSD& info);
void onSend();
};
static LLRegisterPanelClassWrapper<LLPanelSnapshotInventory> panel_class("llpanelsnapshotinventory");
LLPanelSnapshotInventory::LLPanelSnapshotInventory()
{
mCommitCallbackRegistrar.add("Inventory.Save", boost::bind(&LLPanelSnapshotInventory::onSend, this));
mCommitCallbackRegistrar.add("Inventory.Cancel", boost::bind(&LLPanelSnapshotInventory::cancel, this));
}
// virtual
BOOL LLPanelSnapshotInventory::postBuild()
{
return LLPanelSnapshot::postBuild();
}
// virtual
void LLPanelSnapshotInventory::onOpen(const LLSD& key)
{
getChild<LLUICtrl>("hint_lbl")->setTextArg("[UPLOAD_COST]", llformat("%d", LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()));
LLPanelSnapshot::onOpen(key);
}
// virtual
void LLPanelSnapshotInventory::updateCustomResControls()
{
LLComboBox* combo = getChild<LLComboBox>(getImageSizeComboName());
S32 selected_idx = combo->getFirstSelectedIndex();
const bool show = selected_idx == (combo->getItemCount() - 1); // Custom selected
getChild<LLUICtrl>(getWidthSpinnerName())->setVisible(show);
getChild<LLUICtrl>(getHeightSpinnerName())->setVisible(show);
getChild<LLUICtrl>(getAspectRatioCBName())->setVisible(show);
// enable controls if possible
LLPanelSnapshot::updateCustomResControls();
}
// virtual
void LLPanelSnapshotInventory::updateControls(const LLSD& info)
{
const bool have_snapshot = info.has("have-snapshot") ? info["have-snapshot"].asBoolean() : true;
getChild<LLUICtrl>("save_btn")->setEnabled(have_snapshot);
}
void LLPanelSnapshotInventory::onSend()
{
LLFloaterSnapshot::saveTexture();
LLFloaterSnapshot::postSave();
}

View File

@ -0,0 +1,154 @@
/**
* @file llpanelsnapshotlocal.cpp
* @brief The panel provides UI for saving snapshot to a local folder.
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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 "llcombobox.h"
#include "llsidetraypanelcontainer.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"
#include "llfloatersnapshot.h" // FIXME: replace with a snapshot storage model
#include "llpanelsnapshot.h"
#include "llviewercontrol.h" // gSavedSettings
/**
* The panel provides UI for saving snapshot to a local folder.
*/
class LLPanelSnapshotLocal
: public LLPanelSnapshot
{
LOG_CLASS(LLPanelSnapshotLocal);
public:
LLPanelSnapshotLocal();
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
private:
/*virtual*/ std::string getWidthSpinnerName() const { return "local_snapshot_width"; }
/*virtual*/ std::string getHeightSpinnerName() const { return "local_snapshot_height"; }
/*virtual*/ std::string getAspectRatioCBName() const { return "local_keep_aspect_check"; }
/*virtual*/ std::string getImageSizeComboName() const { return "local_size_combo"; }
/*virtual*/ LLFloaterSnapshot::ESnapshotFormat getImageFormat() const;
/*virtual*/ void updateControls(const LLSD& info);
void onFormatComboCommit(LLUICtrl* ctrl);
void onQualitySliderCommit(LLUICtrl* ctrl);
void onSend();
};
static LLRegisterPanelClassWrapper<LLPanelSnapshotLocal> panel_class("llpanelsnapshotlocal");
LLPanelSnapshotLocal::LLPanelSnapshotLocal()
{
mCommitCallbackRegistrar.add("Local.Save", boost::bind(&LLPanelSnapshotLocal::onSend, this));
mCommitCallbackRegistrar.add("Local.Cancel", boost::bind(&LLPanelSnapshotLocal::cancel, this));
}
// virtual
BOOL LLPanelSnapshotLocal::postBuild()
{
getChild<LLUICtrl>("image_quality_slider")->setCommitCallback(boost::bind(&LLPanelSnapshotLocal::onQualitySliderCommit, this, _1));
getChild<LLUICtrl>("local_format_combo")->setCommitCallback(boost::bind(&LLPanelSnapshotLocal::onFormatComboCommit, this, _1));
return LLPanelSnapshot::postBuild();
}
// virtual
void LLPanelSnapshotLocal::onOpen(const LLSD& key)
{
LLPanelSnapshot::onOpen(key);
}
// virtual
LLFloaterSnapshot::ESnapshotFormat LLPanelSnapshotLocal::getImageFormat() const
{
LLFloaterSnapshot::ESnapshotFormat fmt = LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG;
LLComboBox* local_format_combo = getChild<LLComboBox>("local_format_combo");
const std::string id = local_format_combo->getValue().asString();
if (id == "PNG")
{
fmt = LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG;
}
else if (id == "JPEG")
{
fmt = LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG;
}
else if (id == "BMP")
{
fmt = LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP;
}
return fmt;
}
// virtual
void LLPanelSnapshotLocal::updateControls(const LLSD& info)
{
LLFloaterSnapshot::ESnapshotFormat fmt =
(LLFloaterSnapshot::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat");
getChild<LLComboBox>("local_format_combo")->selectNthItem((S32) fmt);
const bool show_quality_ctrls = (fmt == LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
getChild<LLUICtrl>("image_quality_slider")->setVisible(show_quality_ctrls);
getChild<LLUICtrl>("image_quality_level")->setVisible(show_quality_ctrls);
getChild<LLUICtrl>("image_quality_slider")->setValue(gSavedSettings.getS32("SnapshotQuality"));
updateImageQualityLevel();
const bool have_snapshot = info.has("have-snapshot") ? info["have-snapshot"].asBoolean() : true;
getChild<LLUICtrl>("save_btn")->setEnabled(have_snapshot);
}
void LLPanelSnapshotLocal::onFormatComboCommit(LLUICtrl* ctrl)
{
// will call updateControls()
LLFloaterSnapshot::getInstance()->notify(LLSD().with("image-format-change", true));
}
void LLPanelSnapshotLocal::onQualitySliderCommit(LLUICtrl* ctrl)
{
updateImageQualityLevel();
LLSliderCtrl* slider = (LLSliderCtrl*)ctrl;
S32 quality_val = llfloor((F32)slider->getValue().asReal());
LLSD info;
info["image-quality-change"] = quality_val;
LLFloaterSnapshot::getInstance()->notify(info);
}
void LLPanelSnapshotLocal::onSend()
{
LLFloaterSnapshot* floater = LLFloaterSnapshot::getInstance();
floater->notify(LLSD().with("set-working", true));
LLFloaterSnapshot::saveLocal();
LLFloaterSnapshot::postSave();
goBack();
floater->notify(LLSD().with("set-finished", LLSD().with("ok", true).with("msg", "local")));
}

View File

@ -0,0 +1,104 @@
/**
* @file llpanelsnapshotoptions.cpp
* @brief Snapshot posting options panel.
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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 "lleconomy.h"
#include "llpanel.h"
#include "llsidetraypanelcontainer.h"
#include "llfloatersnapshot.h" // FIXME: create a snapshot model
/**
* Provides several ways to save a snapshot.
*/
class LLPanelSnapshotOptions
: public LLPanel
{
LOG_CLASS(LLPanelSnapshotOptions);
public:
LLPanelSnapshotOptions();
/*virtual*/ void onOpen(const LLSD& key);
private:
void openPanel(const std::string& panel_name);
void onSaveToProfile();
void onSaveToEmail();
void onSaveToInventory();
void onSaveToComputer();
};
static LLRegisterPanelClassWrapper<LLPanelSnapshotOptions> panel_class("llpanelsnapshotoptions");
LLPanelSnapshotOptions::LLPanelSnapshotOptions()
{
mCommitCallbackRegistrar.add("Snapshot.SaveToProfile", boost::bind(&LLPanelSnapshotOptions::onSaveToProfile, this));
mCommitCallbackRegistrar.add("Snapshot.SaveToEmail", boost::bind(&LLPanelSnapshotOptions::onSaveToEmail, this));
mCommitCallbackRegistrar.add("Snapshot.SaveToInventory", boost::bind(&LLPanelSnapshotOptions::onSaveToInventory, this));
mCommitCallbackRegistrar.add("Snapshot.SaveToComputer", boost::bind(&LLPanelSnapshotOptions::onSaveToComputer, this));
}
// virtual
void LLPanelSnapshotOptions::onOpen(const LLSD& key)
{
S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
getChild<LLUICtrl>("save_to_inventory_btn")->setLabelArg("[AMOUNT]", llformat("%d", upload_cost));
}
void LLPanelSnapshotOptions::openPanel(const std::string& panel_name)
{
LLSideTrayPanelContainer* parent = dynamic_cast<LLSideTrayPanelContainer*>(getParent());
if (!parent)
{
llwarns << "Cannot find panel container" << llendl;
return;
}
parent->openPanel(panel_name);
parent->getCurrentPanel()->onOpen(LLSD());
LLFloaterSnapshot::postPanelSwitch();
}
void LLPanelSnapshotOptions::onSaveToProfile()
{
openPanel("panel_snapshot_profile");
}
void LLPanelSnapshotOptions::onSaveToEmail()
{
openPanel("panel_snapshot_postcard");
}
void LLPanelSnapshotOptions::onSaveToInventory()
{
openPanel("panel_snapshot_inventory");
}
void LLPanelSnapshotOptions::onSaveToComputer()
{
openPanel("panel_snapshot_local");
}

View File

@ -0,0 +1,269 @@
/**
* @file llpanelsnapshotpostcard.cpp
* @brief Postcard sending panel.
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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 "llcombobox.h"
#include "llnotificationsutil.h"
#include "llsidetraypanelcontainer.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"
#include "lltexteditor.h"
#include "llagent.h"
#include "llagentui.h"
#include "llfloatersnapshot.h" // FIXME: replace with a snapshot storage model
#include "llpanelsnapshot.h"
#include "llpostcard.h"
#include "llviewercontrol.h" // gSavedSettings
#include "llviewerwindow.h"
#include <boost/regex.hpp>
/**
* Sends postcard via email.
*/
class LLPanelSnapshotPostcard
: public LLPanelSnapshot
{
LOG_CLASS(LLPanelSnapshotPostcard);
public:
LLPanelSnapshotPostcard();
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
/*virtual*/ S32 notify(const LLSD& info);
private:
/*virtual*/ std::string getWidthSpinnerName() const { return "postcard_snapshot_width"; }
/*virtual*/ std::string getHeightSpinnerName() const { return "postcard_snapshot_height"; }
/*virtual*/ std::string getAspectRatioCBName() const { return "postcard_keep_aspect_check"; }
/*virtual*/ std::string getImageSizeComboName() const { return "postcard_size_combo"; }
/*virtual*/ LLFloaterSnapshot::ESnapshotFormat getImageFormat() const { return LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG; }
/*virtual*/ void updateControls(const LLSD& info);
bool missingSubjMsgAlertCallback(const LLSD& notification, const LLSD& response);
void sendPostcard();
void onMsgFormFocusRecieved();
void onFormatComboCommit(LLUICtrl* ctrl);
void onQualitySliderCommit(LLUICtrl* ctrl);
void onTabButtonPress(S32 btn_idx);
void onSend();
bool mHasFirstMsgFocus;
std::string mAgentEmail;
};
static LLRegisterPanelClassWrapper<LLPanelSnapshotPostcard> panel_class("llpanelsnapshotpostcard");
LLPanelSnapshotPostcard::LLPanelSnapshotPostcard()
: mHasFirstMsgFocus(false)
{
mCommitCallbackRegistrar.add("Postcard.Send", boost::bind(&LLPanelSnapshotPostcard::onSend, this));
mCommitCallbackRegistrar.add("Postcard.Cancel", boost::bind(&LLPanelSnapshotPostcard::cancel, this));
mCommitCallbackRegistrar.add("Postcard.Message", boost::bind(&LLPanelSnapshotPostcard::onTabButtonPress, this, 0));
mCommitCallbackRegistrar.add("Postcard.Settings", boost::bind(&LLPanelSnapshotPostcard::onTabButtonPress, this, 1));
}
// virtual
BOOL LLPanelSnapshotPostcard::postBuild()
{
// pick up the user's up-to-date email address
gAgent.sendAgentUserInfoRequest();
std::string name_string;
LLAgentUI::buildFullname(name_string);
getChild<LLUICtrl>("name_form")->setValue(LLSD(name_string));
// For the first time a user focuses to .the msg box, all text will be selected.
getChild<LLUICtrl>("msg_form")->setFocusChangedCallback(boost::bind(&LLPanelSnapshotPostcard::onMsgFormFocusRecieved, this));
getChild<LLUICtrl>("to_form")->setFocus(TRUE);
getChild<LLUICtrl>("image_quality_slider")->setCommitCallback(boost::bind(&LLPanelSnapshotPostcard::onQualitySliderCommit, this, _1));
getChild<LLButton>("message_btn")->setToggleState(TRUE);
return LLPanelSnapshot::postBuild();
}
// virtual
void LLPanelSnapshotPostcard::onOpen(const LLSD& key)
{
LLPanelSnapshot::onOpen(key);
}
// virtual
S32 LLPanelSnapshotPostcard::notify(const LLSD& info)
{
if (!info.has("agent-email"))
{
llassert(info.has("agent-email"));
return 0;
}
if (mAgentEmail.empty())
{
mAgentEmail = info["agent-email"].asString();
}
return 1;
}
// virtual
void LLPanelSnapshotPostcard::updateControls(const LLSD& info)
{
getChild<LLUICtrl>("image_quality_slider")->setValue(gSavedSettings.getS32("SnapshotQuality"));
updateImageQualityLevel();
const bool have_snapshot = info.has("have-snapshot") ? info["have-snapshot"].asBoolean() : true;
getChild<LLUICtrl>("send_btn")->setEnabled(have_snapshot);
}
bool LLPanelSnapshotPostcard::missingSubjMsgAlertCallback(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if(0 == option)
{
// User clicked OK
if((getChild<LLUICtrl>("subject_form")->getValue().asString()).empty())
{
// Stuff the subject back into the form.
getChild<LLUICtrl>("subject_form")->setValue(getString("default_subject"));
}
if (!mHasFirstMsgFocus)
{
// The user never switched focus to the message window.
// Using the default string.
getChild<LLUICtrl>("msg_form")->setValue(getString("default_message"));
}
sendPostcard();
}
return false;
}
void LLPanelSnapshotPostcard::sendPostcard()
{
std::string to(getChild<LLUICtrl>("to_form")->getValue().asString());
std::string subject(getChild<LLUICtrl>("subject_form")->getValue().asString());
LLSD postcard = LLSD::emptyMap();
postcard["pos-global"] = LLFloaterSnapshot::getPosTakenGlobal().getValue();
postcard["to"] = to;
postcard["from"] = mAgentEmail;
postcard["name"] = getChild<LLUICtrl>("name_form")->getValue().asString();
postcard["subject"] = subject;
postcard["msg"] = getChild<LLUICtrl>("msg_form")->getValue().asString();
LLPostCard::send(LLFloaterSnapshot::getImageData(), postcard);
// Give user feedback of the event.
gViewerWindow->playSnapshotAnimAndSound();
LLFloaterSnapshot::postSave();
}
void LLPanelSnapshotPostcard::onMsgFormFocusRecieved()
{
LLTextEditor* msg_form = getChild<LLTextEditor>("msg_form");
if (msg_form->hasFocus() && !mHasFirstMsgFocus)
{
mHasFirstMsgFocus = true;
msg_form->setText(LLStringUtil::null);
}
}
void LLPanelSnapshotPostcard::onFormatComboCommit(LLUICtrl* ctrl)
{
// will call updateControls()
LLFloaterSnapshot::getInstance()->notify(LLSD().with("image-format-change", true));
}
void LLPanelSnapshotPostcard::onQualitySliderCommit(LLUICtrl* ctrl)
{
updateImageQualityLevel();
LLSliderCtrl* slider = (LLSliderCtrl*)ctrl;
S32 quality_val = llfloor((F32)slider->getValue().asReal());
LLSD info;
info["image-quality-change"] = quality_val;
LLFloaterSnapshot::getInstance()->notify(info); // updates the "SnapshotQuality" setting
}
void LLPanelSnapshotPostcard::onTabButtonPress(S32 btn_idx)
{
LLButton* buttons[2] = {
getChild<LLButton>("message_btn"),
getChild<LLButton>("settings_btn"),
};
// Switch between Message and Settings tabs.
LLButton* clicked_btn = buttons[btn_idx];
LLButton* other_btn = buttons[!btn_idx];
LLSideTrayPanelContainer* container =
getChild<LLSideTrayPanelContainer>("postcard_panel_container");
container->selectTab(clicked_btn->getToggleState() ? btn_idx : !btn_idx);
//clicked_btn->setEnabled(FALSE);
other_btn->toggleState();
//other_btn->setEnabled(TRUE);
lldebugs << "Button #" << btn_idx << " (" << clicked_btn->getName() << ") clicked" << llendl;
}
void LLPanelSnapshotPostcard::onSend()
{
// Validate input.
std::string to(getChild<LLUICtrl>("to_form")->getValue().asString());
boost::regex email_format("[A-Za-z0-9.%+-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}(,[ \t]*[A-Za-z0-9.%+-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,})*");
if (to.empty() || !boost::regex_match(to, email_format))
{
LLNotificationsUtil::add("PromptRecipientEmail");
return;
}
if (mAgentEmail.empty() || !boost::regex_match(mAgentEmail, email_format))
{
LLNotificationsUtil::add("PromptSelfEmail");
return;
}
std::string subject(getChild<LLUICtrl>("subject_form")->getValue().asString());
if(subject.empty() || !mHasFirstMsgFocus)
{
LLNotificationsUtil::add("PromptMissingSubjMsg", LLSD(), LLSD(), boost::bind(&LLPanelSnapshotPostcard::missingSubjMsgAlertCallback, this, _1, _2));
return;
}
// Send postcard.
sendPostcard();
}

View File

@ -0,0 +1,100 @@
/**
* @file llpanelsnapshotprofile.cpp
* @brief Posts a snapshot to My Profile feed.
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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"
// libs
#include "llcombobox.h"
#include "llfloaterreg.h"
#include "llpanel.h"
#include "llspinctrl.h"
// newview
#include "llfloatersnapshot.h"
#include "llpanelsnapshot.h"
#include "llsidetraypanelcontainer.h"
#include "llwebprofile.h"
/**
* Posts a snapshot to My Profile feed.
*/
class LLPanelSnapshotProfile
: public LLPanelSnapshot
{
LOG_CLASS(LLPanelSnapshotProfile);
public:
LLPanelSnapshotProfile();
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
private:
/*virtual*/ std::string getWidthSpinnerName() const { return "profile_snapshot_width"; }
/*virtual*/ std::string getHeightSpinnerName() const { return "profile_snapshot_height"; }
/*virtual*/ std::string getAspectRatioCBName() const { return "profile_keep_aspect_check"; }
/*virtual*/ std::string getImageSizeComboName() const { return "profile_size_combo"; }
/*virtual*/ LLFloaterSnapshot::ESnapshotFormat getImageFormat() const { return LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG; }
/*virtual*/ void updateControls(const LLSD& info);
void onSend();
};
static LLRegisterPanelClassWrapper<LLPanelSnapshotProfile> panel_class("llpanelsnapshotprofile");
LLPanelSnapshotProfile::LLPanelSnapshotProfile()
{
mCommitCallbackRegistrar.add("PostToProfile.Send", boost::bind(&LLPanelSnapshotProfile::onSend, this));
mCommitCallbackRegistrar.add("PostToProfile.Cancel", boost::bind(&LLPanelSnapshotProfile::cancel, this));
}
// virtual
BOOL LLPanelSnapshotProfile::postBuild()
{
return LLPanelSnapshot::postBuild();
}
// virtual
void LLPanelSnapshotProfile::onOpen(const LLSD& key)
{
LLPanelSnapshot::onOpen(key);
}
// virtual
void LLPanelSnapshotProfile::updateControls(const LLSD& info)
{
const bool have_snapshot = info.has("have-snapshot") ? info["have-snapshot"].asBoolean() : true;
getChild<LLUICtrl>("post_btn")->setEnabled(have_snapshot);
}
void LLPanelSnapshotProfile::onSend()
{
std::string caption = getChild<LLUICtrl>("caption")->getValue().asString();
bool add_location = getChild<LLUICtrl>("add_location_cb")->getValue().asBoolean();
LLWebProfile::uploadImage(LLFloaterSnapshot::getImageData(), caption, add_location);
LLFloaterSnapshot::postSave();
}

View File

@ -0,0 +1,155 @@
/**
* @file llpostcard.cpp
* @brief Sending postcards.
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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 "llpostcard.h"
#include "llvfile.h"
#include "llvfs.h"
#include "llviewerregion.h"
#include "message.h"
#include "llagent.h"
#include "llassetuploadresponders.h"
///////////////////////////////////////////////////////////////////////////////
// misc
static void postcard_upload_callback(const LLUUID& asset_id, void *user_data, S32 result, LLExtStat ext_status)
{
LLSD* postcard_data = (LLSD*)user_data;
if (result)
{
// TODO: display the error messages in UI
llwarns << "Failed to send postcard: " << LLAssetStorage::getErrorString(result) << llendl;
LLPostCard::reportPostResult(false);
}
else
{
// only create the postcard once the upload succeeds
// request the postcard
const LLSD& data = *postcard_data;
LLMessageSystem* msg = gMessageSystem;
msg->newMessage("SendPostcard");
msg->nextBlock("AgentData");
msg->addUUID("AgentID", gAgent.getID());
msg->addUUID("SessionID", gAgent.getSessionID());
msg->addUUID("AssetID", data["asset-id"].asUUID());
msg->addVector3d("PosGlobal", LLVector3d(data["pos-global"]));
msg->addString("To", data["to"]);
msg->addString("From", data["from"]);
msg->addString("Name", data["name"]);
msg->addString("Subject", data["subject"]);
msg->addString("Msg", data["msg"]);
msg->addBOOL("AllowPublish", FALSE);
msg->addBOOL("MaturePublish", FALSE);
gAgent.sendReliableMessage();
LLPostCard::reportPostResult(true);
}
delete postcard_data;
}
///////////////////////////////////////////////////////////////////////////////
// LLPostcardSendResponder
class LLPostcardSendResponder : public LLAssetUploadResponder
{
LOG_CLASS(LLPostcardSendResponder);
public:
LLPostcardSendResponder(const LLSD &post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type):
LLAssetUploadResponder(post_data, vfile_id, asset_type)
{
}
/*virtual*/ void uploadComplete(const LLSD& content)
{
llinfos << "Postcard sent" << llendl;
LL_DEBUGS("Snapshots") << "content: " << content << llendl;
LLPostCard::reportPostResult(true);
}
/*virtual*/ void uploadFailure(const LLSD& content)
{
llwarns << "Sending postcard failed: " << content << llendl;
LLPostCard::reportPostResult(false);
}
};
///////////////////////////////////////////////////////////////////////////////
// LLPostCard
LLPostCard::result_callback_t LLPostCard::mResultCallback;
// static
void LLPostCard::send(LLPointer<LLImageFormatted> image, const LLSD& postcard_data)
{
LLTransactionID transaction_id;
LLAssetID asset_id;
transaction_id.generate();
asset_id = transaction_id.makeAssetID(gAgent.getSecureSessionID());
LLVFile::writeFile(image->getData(), image->getDataSize(), gVFS, asset_id, LLAssetType::AT_IMAGE_JPEG);
// upload the image
std::string url = gAgent.getRegion()->getCapability("SendPostcard");
if (!url.empty())
{
llinfos << "Sending postcard via capability" << llendl;
// the capability already encodes: agent ID, region ID
LL_DEBUGS("Snapshots") << "url: " << url << llendl;
LL_DEBUGS("Snapshots") << "body: " << postcard_data << llendl;
LL_DEBUGS("Snapshots") << "data size: " << image->getDataSize() << llendl;
LLHTTPClient::post(url, postcard_data,
new LLPostcardSendResponder(postcard_data, asset_id, LLAssetType::AT_IMAGE_JPEG));
}
else
{
llinfos << "Sending postcard" << llendl;
LLSD* data = new LLSD(postcard_data);
(*data)["asset-id"] = asset_id;
gAssetStorage->storeAssetData(transaction_id, LLAssetType::AT_IMAGE_JPEG,
&postcard_upload_callback, (void *)data, FALSE);
}
}
// static
void LLPostCard::reportPostResult(bool ok)
{
if (mResultCallback)
{
mResultCallback(ok);
}
}

View File

@ -0,0 +1,48 @@
/**
* @file llpostcard.h
* @brief Sending postcards.
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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_LLPOSTCARD_H
#define LL_LLPOSTCARD_H
#include "llimage.h"
#include "lluuid.h"
class LLPostCard
{
LOG_CLASS(LLPostCard);
public:
typedef boost::function<void(bool ok)> result_callback_t;
static void send(LLPointer<LLImageFormatted> image, const LLSD& postcard_data);
static void setPostResultCallback(result_callback_t cb) { mResultCallback = cb; }
static void reportPostResult(bool ok);
private:
static result_callback_t mResultCallback;
};
#endif // LL_LLPOSTCARD_H

View File

@ -62,6 +62,13 @@ void LLSideTrayPanelContainer::onOpen(const LLSD& key)
getCurrentPanel()->onOpen(key);
}
void LLSideTrayPanelContainer::openPanel(const std::string& panel_name, const LLSD& key)
{
LLSD combined_key = key;
combined_key[PARAM_SUB_PANEL_NAME] = panel_name;
onOpen(combined_key);
}
void LLSideTrayPanelContainer::openPreviousPanel()
{
if(!mDefaultPanelName.empty())

View File

@ -56,6 +56,11 @@ public:
*/
/*virtual*/ void onOpen(const LLSD& key);
/**
* Opens given subpanel.
*/
void openPanel(const std::string& panel_name, const LLSD& key = LLSD::emptyMap());
/**
* Opens previous panel from panel navigation history.
*/

View File

@ -85,7 +85,6 @@
#include "llfloateropenobject.h"
#include "llfloaterpay.h"
#include "llfloaterperms.h"
#include "llfloaterpostcard.h"
#include "llfloaterpostprocess.h"
#include "llfloaterpreference.h"
#include "llfloaterproperties.h"
@ -245,7 +244,6 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("people", "floater_people.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>);
LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>);
LLFloaterReg::add("postcard", "floater_postcard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostcard>);
LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>);
LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>);
LLFloaterReg::add("prefs_hardware_settings", "floater_hardware_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHardwareSettings>);

View File

@ -50,6 +50,7 @@
#include "llvoavatar.h"
#include "llvoavatarself.h"
#include "llviewerregion.h"
#include "llwebprofile.h"
#include "llwebsharing.h" // For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this!
#include "llfilepicker.h"
#include "llnotifications.h"
@ -319,6 +320,10 @@ public:
std::string cookie = content["set-cookie"].asString();
LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost);
// Set cookie for snapshot publishing.
std::string auth_cookie = cookie.substr(0, cookie.find(";")); // strip path
LLWebProfile::setAuthCookie(auth_cookie);
}
void completedRaw(
@ -1484,6 +1489,8 @@ void LLViewerMedia::setOpenIDCookie()
std::string profile_url = getProfileURL("");
LLURL raw_profile_url( profile_url.c_str() );
LL_DEBUGS("MediaAuth") << "Requesting " << profile_url << llendl;
LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << llendl;
LLHTTPClient::get(profile_url,
new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()),
headers);

View File

@ -528,23 +528,7 @@ class LLFileTakeSnapshotToDisk : public view_listener_t
{
gViewerWindow->playSnapshotAnimAndSound();
LLPointer<LLImageFormatted> formatted;
switch(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat")))
{
case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality"));
break;
case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
formatted = new LLImagePNG;
break;
case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
formatted = new LLImageBMP;
break;
default:
llwarns << "Unknown Local Snapshot format" << llendl;
return true;
}
LLPointer<LLImageFormatted> formatted = new LLImagePNG;
formatted->enableOverSize() ;
formatted->encode(raw, 0);
formatted->disableOverSize() ;

View File

@ -59,9 +59,9 @@
#include "llfloaterland.h"
#include "llfloaterregioninfo.h"
#include "llfloaterlandholdings.h"
#include "llfloaterpostcard.h"
#include "llfloaterpreference.h"
#include "llfloatersidepanelcontainer.h"
#include "llfloatersnapshot.h"
#include "llhudeffecttrail.h"
#include "llhudmanager.h"
#include "llinventoryfunctions.h"
@ -6470,7 +6470,7 @@ void process_user_info_reply(LLMessageSystem* msg, void**)
msg->getString( "UserData", "DirectoryVisibility", dir_visibility);
LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email);
LLFloaterPostcard::updateUserInfo(email);
LLFloaterSnapshot::setAgentEmail(email);
}

View File

@ -4020,10 +4020,11 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d
}
// Saves an image to the harddrive as "SnapshotX" where X >= 1.
BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image)
BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image, bool force_picker)
{
if (!image)
{
llwarns << "No image to save" << llendl;
return FALSE;
}
@ -4043,7 +4044,7 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image)
pick_type = LLFilePicker::FFSAVE_ALL; // ???
// Get a base file location if needed.
if ( ! isSnapshotLocSet())
if (force_picker || !isSnapshotLocSet())
{
std::string proposed_name( sSnapshotBaseName );
@ -4083,6 +4084,7 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image)
}
while( -1 != err ); // search until the file is not found (i.e., stat() gives an error).
llinfos << "Saving snapshot to " << filepath << llendl;
return image->save(filepath);
}

View File

@ -324,7 +324,7 @@ public:
BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) ;
BOOL isSnapshotLocSet() const { return ! sSnapshotDir.empty(); }
void resetSnapshotLoc() const { sSnapshotDir.clear(); }
BOOL saveImageNumbered(LLImageFormatted *image);
BOOL saveImageNumbered(LLImageFormatted *image, bool force_picker = false);
// Reset the directory where snapshots are saved.
// Client will open directory picker on next snapshot save.

View File

@ -0,0 +1,305 @@
/**
* @file llwebprofile.cpp
* @brief Web profile access.
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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 "llwebprofile.h"
// libs
#include "llbufferstream.h"
#include "llhttpclient.h"
#include "llimagepng.h"
#include "llplugincookiestore.h"
// newview
#include "llpanelprofile.h" // for getProfileURL(). FIXME: move the method to LLAvatarActions
#include "llviewermedia.h" // FIXME: don't use LLViewerMedia internals
// third-party
#include "reader.h" // JSON
/*
* Workflow:
* 1. LLViewerMedia::setOpenIDCookie()
* -> GET https://my-demo.secondlife.com/ via LLViewerMediaWebProfileResponder
* -> LLWebProfile::setAuthCookie()
* 2. LLWebProfile::uploadImage()
* -> GET "https://my-demo.secondlife.com/snapshots/s3_upload_config" via ConfigResponder
* 3. LLWebProfile::post()
* -> POST <config_url> via PostImageResponder
* -> redirect
* -> GET <redirect_url> via PostImageRedirectResponder
*/
///////////////////////////////////////////////////////////////////////////////
// LLWebProfileResponders::ConfigResponder
class LLWebProfileResponders::ConfigResponder : public LLHTTPClient::Responder
{
LOG_CLASS(LLWebProfileResponders::ConfigResponder);
public:
ConfigResponder(LLPointer<LLImageFormatted> imagep)
: mImagep(imagep)
{
}
/*virtual*/ void completedRaw(
U32 status,
const std::string& reason,
const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer)
{
LLBufferStream istr(channels, buffer.get());
std::stringstream strstrm;
strstrm << istr.rdbuf();
const std::string body = strstrm.str();
if (status != 200)
{
llwarns << "Failed to get upload config (" << status << ")" << llendl;
LLWebProfile::reportImageUploadStatus(false);
return;
}
Json::Value root;
Json::Reader reader;
if (!reader.parse(body, root))
{
llwarns << "Failed to parse upload config: " << reader.getFormatedErrorMessages() << llendl;
LLWebProfile::reportImageUploadStatus(false);
return;
}
// *TODO: 404 = not supported by the grid
// *TODO: increase timeout or handle 499 Expired
// Convert config to LLSD.
const Json::Value data = root["data"];
const std::string upload_url = root["url"].asString();
LLSD config;
config["acl"] = data["acl"].asString();
config["AWSAccessKeyId"] = data["AWSAccessKeyId"].asString();
config["Content-Type"] = data["Content-Type"].asString();
config["key"] = data["key"].asString();
config["policy"] = data["policy"].asString();
config["success_action_redirect"] = data["success_action_redirect"].asString();
config["signature"] = data["signature"].asString();
config["add_loc"] = data.get("add_loc", "0").asString();
config["caption"] = data.get("caption", "").asString();
// Do the actual image upload using the configuration.
LL_DEBUGS("Snapshots") << "Got upload config, POSTing image to " << upload_url << ", config=[" << config << "]" << llendl;
LLWebProfile::post(mImagep, config, upload_url);
}
private:
LLPointer<LLImageFormatted> mImagep;
};
///////////////////////////////////////////////////////////////////////////////
// LLWebProfilePostImageRedirectResponder
class LLWebProfileResponders::PostImageRedirectResponder : public LLHTTPClient::Responder
{
LOG_CLASS(LLWebProfileResponders::PostImageRedirectResponder);
public:
/*virtual*/ void completedRaw(
U32 status,
const std::string& reason,
const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer)
{
if (status != 200)
{
llwarns << "Failed to upload image: " << status << " " << reason << llendl;
LLWebProfile::reportImageUploadStatus(false);
return;
}
LLBufferStream istr(channels, buffer.get());
std::stringstream strstrm;
strstrm << istr.rdbuf();
const std::string body = strstrm.str();
llinfos << "Image uploaded." << llendl;
LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << llendl;
LLWebProfile::reportImageUploadStatus(true);
}
private:
LLPointer<LLImageFormatted> mImagep;
};
///////////////////////////////////////////////////////////////////////////////
// LLWebProfileResponders::PostImageResponder
class LLWebProfileResponders::PostImageResponder : public LLHTTPClient::Responder
{
LOG_CLASS(LLWebProfileResponders::PostImageResponder);
public:
/*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
{
// Viewer seems to fail to follow a 303 redirect on POST request
// (URLRequest Error: 65, Send failed since rewinding of the data stream failed).
// Handle it manually.
if (status == 303)
{
LLSD headers = LLViewerMedia::getHeaders();
headers["Cookie"] = LLWebProfile::getAuthCookie();
const std::string& redir_url = content["location"];
LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << llendl;
LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers);
}
else
{
llwarns << "Unexpected POST status: " << status << " " << reason << llendl;
LL_DEBUGS("Snapshots") << "headers: [" << content << "]" << llendl;
LLWebProfile::reportImageUploadStatus(false);
}
}
// Override just to suppress warnings.
/*virtual*/ void completedRaw(U32 status, const std::string& reason,
const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer)
{
}
};
///////////////////////////////////////////////////////////////////////////////
// LLWebProfile
std::string LLWebProfile::sAuthCookie;
LLWebProfile::status_callback_t LLWebProfile::mStatusCallback;
// static
void LLWebProfile::uploadImage(LLPointer<LLImageFormatted> image, const std::string& caption, bool add_location)
{
// Get upload configuration data.
std::string config_url(getProfileURL(LLStringUtil::null) + "snapshots/s3_upload_config");
config_url += "?caption=" + LLURI::escape(caption);
config_url += "&add_loc=" + std::string(add_location ? "1" : "0");
LL_DEBUGS("Snapshots") << "Requesting " << config_url << llendl;
LLSD headers = LLViewerMedia::getHeaders();
headers["Cookie"] = getAuthCookie();
LLHTTPClient::get(config_url, new LLWebProfileResponders::ConfigResponder(image), headers);
}
// static
void LLWebProfile::setAuthCookie(const std::string& cookie)
{
LL_DEBUGS("Snapshots") << "Setting auth cookie: " << cookie << llendl;
sAuthCookie = cookie;
}
// static
void LLWebProfile::post(LLPointer<LLImageFormatted> image, const LLSD& config, const std::string& url)
{
if (dynamic_cast<LLImagePNG*>(image.get()) == 0)
{
llwarns << "Image to upload is not a PNG" << llendl;
llassert(dynamic_cast<LLImagePNG*>(image.get()) != 0);
return;
}
const std::string boundary = "----------------------------0123abcdefab";
LLSD headers = LLViewerMedia::getHeaders();
headers["Cookie"] = getAuthCookie();
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=\"key\"\r\n\r\n"
<< config["key"].asString() << "\r\n";
body << "--" << boundary << "\r\n"
<< "Content-Disposition: form-data; name=\"AWSAccessKeyId\"\r\n\r\n"
<< config["AWSAccessKeyId"].asString() << "\r\n";
body << "--" << boundary << "\r\n"
<< "Content-Disposition: form-data; name=\"acl\"\r\n\r\n"
<< config["acl"].asString() << "\r\n";
body << "--" << boundary << "\r\n"
<< "Content-Disposition: form-data; name=\"Content-Type\"\r\n\r\n"
<< config["Content-Type"].asString() << "\r\n";
body << "--" << boundary << "\r\n"
<< "Content-Disposition: form-data; name=\"policy\"\r\n\r\n"
<< config["policy"].asString() << "\r\n";
body << "--" << boundary << "\r\n"
<< "Content-Disposition: form-data; name=\"signature\"\r\n\r\n"
<< config["signature"].asString() << "\r\n";
body << "--" << boundary << "\r\n"
<< "Content-Disposition: form-data; name=\"success_action_redirect\"\r\n\r\n"
<< config["success_action_redirect"].asString() << "\r\n";
body << "--" << boundary << "\r\n"
<< "Content-Disposition: form-data; name=\"file\"; filename=\"snapshot.png\"\r\n"
<< "Content-Type: image/png\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);
// Send request, successful upload will trigger posting metadata.
LLHTTPClient::postRaw(url, data, size, new LLWebProfileResponders::PostImageResponder(), headers);
}
// static
void LLWebProfile::reportImageUploadStatus(bool ok)
{
if (mStatusCallback)
{
mStatusCallback(ok);
}
}
// static
std::string LLWebProfile::getAuthCookie()
{
// This is needed to test image uploads on Linux viewer built with OpenSSL 1.0.0 (0.9.8 works fine).
const char* debug_cookie = getenv("LL_SNAPSHOT_COOKIE");
return debug_cookie ? debug_cookie : sAuthCookie;
}

View File

@ -0,0 +1,69 @@
/**
* @file llwebprofile.h
* @brief Web profile access.
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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_LLWEBPROFILE_H
#define LL_LLWEBPROFILE_H
#include "llimage.h"
namespace LLWebProfileResponders
{
class ConfigResponder;
class PostImageResponder;
class PostImageRedirectResponder;
};
/**
* @class LLWebProfile
*
* Manages interaction with, a web service allowing the upload of snapshot images
* taken within the viewer.
*/
class LLWebProfile
{
LOG_CLASS(LLWebProfile);
public:
typedef boost::function<void(bool ok)> status_callback_t;
static void uploadImage(LLPointer<LLImageFormatted> image, const std::string& caption, bool add_location);
static void setAuthCookie(const std::string& cookie);
static void setImageUploadResultCallback(status_callback_t cb) { mStatusCallback = cb; }
private:
friend class LLWebProfileResponders::ConfigResponder;
friend class LLWebProfileResponders::PostImageResponder;
friend class LLWebProfileResponders::PostImageRedirectResponder;
static void post(LLPointer<LLImageFormatted> image, const LLSD& config, const std::string& url);
static void reportImageUploadStatus(bool ok);
static std::string getAuthCookie();
static std::string sAuthCookie;
static status_callback_t mStatusCallback;
};
#endif // LL_LLWEBPROFILE_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -547,6 +547,10 @@ with the same filename but different name
<texture name="Unknown_Icon" file_name="icons/unknown_icon.png" preload="true" />
<texture name="Snapshot_Off" file_name="bottomtray/Snapshot_Off.png" preload="true" scale.left="4" scale.top="19" scale.right="22" scale.bottom="4" />
<texture name="Snapshot_Download" file_name="snapshot_download.png" preload="false" />
<texture name="Snapshot_Email" file_name="snapshot_email.png" preload="false" />
<texture name="Snapshot_Inventory" file_name="toolbar_icons/inventory.png" preload="false" />
<texture name="Snapshot_Profile" file_name="toolbar_icons/profile.png" preload="false" />
<texture name="startup_logo" file_name="windows/startup_logo.png" preload="true" />

View File

@ -5,400 +5,308 @@
can_minimize="true"
can_close="true"
follows="left|top"
height="520"
height="600"
layout="topleft"
name="Snapshot"
help_topic="snapshot"
save_rect="true"
save_visibility="true"
title="SNAPSHOT PREVIEW"
width="245">
width="470">
<floater.string
name="unknown">
unknown
</floater.string>
<radio_group
height="70"
label="Snapshot type"
<string
name="postcard_progress_str">
Sending Email
</string>
<string
name="profile_progress_str">
Posting
</string>
<string
name="inventory_progress_str">
Saving to Inventory
</string>
<string
name="local_progress_str">
Saving to Computer
</string>
<string
name="profile_succeeded_str">
Your Profile Feed has been updated!
</string>
<string
name="postcard_succeeded_str">
Email Sent!
</string>
<string
name="inventory_succeeded_str">
Saved to Inventory!
</string>
<string
name="local_succeeded_str">
Saved to Computer!
</string>
<string
name="profile_failed_str">
Failed to update your Profile Feed.
</string>
<string
name="postcard_failed_str">
Failed to send email.
</string>
<string
name="inventory_failed_str">
Failed to save to inventory.
</string>
<string
name="local_failed_str">
Failed to save to computer.
</string>
<view_border
bevel_style="in"
follows="left|top"
height="21"
left="10"
layout="topleft"
name="img_info_border"
top="22"
width="50"
/>
<icon
follows="top|left"
height="18"
image_name="Snapshot_Off"
layout="topleft"
left_delta="-5"
mouse_opaque="true"
name="refresh_icon"
top_delta="3"
width="36" />
<button
follows="left|top"
height="22"
image_overlay="Refresh_Off"
layout="topleft"
left_delta="31"
name="new_snapshot_btn"
top_delta="-3"
width="23" />
<button
follows="left|top"
height="23"
image_overlay="TabIcon_Close_Off"
is_toggle="true"
layout="topleft"
left="10"
name="snapshot_type_radio"
top="20"
width="205">
<!--
<radio_item
height="16"
label="Share to Web"
layout="topleft"
name="share_to_web"
top_pad="0" />
-->
<radio_item
height="16"
label="Email"
layout="topleft"
name="postcard"
top_pad="2" />
<radio_item
height="16"
label="My inventory (L$[AMOUNT])"
layout="topleft"
name="texture"
top_pad="2" />
<radio_item
height="16"
label="Save to my computer"
layout="topleft"
name="local"
top_pad="2" />
</radio_group>
left="240"
name="advanced_options_btn"
tool_tip="Advanced options"
top_delta="0"
width="23" />
<ui_ctrl
height="90"
width="125"
height="160"
width="250"
layout="topleft"
name="thumbnail_placeholder"
top_pad="6"
top="50"
follows="left|top"
left="10"
/>
<text
type="string"
font="SansSerifSmall"
length="1"
left="10">
<loading_indicator
follows="left|top"
height="48"
layout="topleft"
name="working_indicator"
left="101"
top="46"
visible="false"
width="48" />
<text
follows="left|top|right"
font="SansSerifBold"
height="14"
layout="topleft"
left="5"
length="1"
halign="center"
name="working_lbl"
right="-5"
top="98"
translate="false"
type="string"
visible="false"
width="130">
Working
</text>
</ui_ctrl>
<view_border
bevel_style="in"
height="21"
width="250"
layout="topleft"
name="img_info_border"
top_pad="3"
follows="left|top"
left_delta="0"
/>
<text
type="string"
font="SansSerifSmall"
length="1"
follows="left|top"
height="14"
layout="topleft"
left_delta="5"
halign="left"
name="image_res_text"
top_delta="5"
width="100">
[WIDTH] x [HEIGHT] px
</text>
<text
follows="left|top"
font="SansSerifSmall"
height="14"
layout="topleft"
left="200"
length="1"
halign="right"
name="file_size_label"
top_delta="0"
type="string"
width="50">
[SIZE] KB
</text>
<panel_container
follows="left|top"
height="14"
height="360"
layout="topleft"
right="-5"
left_delta="0"
halign="right"
name="file_size_label"
top_pad="8"
width="195">
[SIZE] KB
</text>
<button
follows="left|top"
height="22"
image_overlay="Refresh_Off"
layout="topleft"
left="10"
name="new_snapshot_btn"
width="23" />
<button
follows="left|top"
height="23"
label="Send"
layout="topleft"
left_pad="5"
right="-5"
name="send_btn"
width="100" />
<button
follows="left|top"
height="23"
label="Save (L$[AMOUNT])"
layout="topleft"
right="-5"
name="upload_btn"
top_delta="0"
width="110" />
<flyout_button
follows="left|top"
height="23"
label="Save"
layout="topleft"
right="-5"
name="save_btn"
tool_tip="Save image to a file"
top_delta="0"
width="100">
<flyout_button.item
label="Save"
name="save_item"
value="save" />
<flyout_button.item
label="Save As..."
name="saveas_item"
value="save as" />
</flyout_button>
<button
follows="left|top"
height="23"
label="More"
layout="topleft"
left="10"
name="more_btn"
tool_tip="Advanced options"
width="80" />
<button
follows="left|top"
height="23"
label="Less"
layout="topleft"
left_delta="0"
name="less_btn"
tool_tip="Advanced options"
top_delta="0"
width="80" />
<button
follows="left|top"
height="23"
label="Cancel"
layout="topleft"
right="-5"
left_pad="5"
name="discard_btn"
width="110" />
<text
type="string"
length="1"
follows="top|left"
height="12"
layout="topleft"
left="10"
name="type_label2"
top_pad="5"
width="127">
Size
</text>
<text
type="string"
length="1"
follows="top|left"
height="12"
layout="topleft"
left_pad="5"
name="format_label"
top_delta="0"
width="70">
Format
</text>
<combo_box
height="23"
label="Resolution"
layout="topleft"
left="10"
name="postcard_size_combo"
width="120">
<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.item
label="Custom"
name="Custom"
value="[i-1,i-1]" />
</combo_box>
<combo_box
height="23"
label="Resolution"
layout="topleft"
left_delta="0"
name="texture_size_combo"
top_delta="0"
width="127">
<combo_box.item
label="Current Window"
name="CurrentWindow"
value="[i0,i0]" />
<combo_box.item
label="Small (128x128)"
name="Small(128x128)"
value="[i128,i128]" />
<combo_box.item
label="Medium (256x256)"
name="Medium(256x256)"
value="[i256,i256]" />
<combo_box.item
label="Large (512x512)"
name="Large(512x512)"
value="[i512,i512]" />
<combo_box.item
label="Custom"
name="Custom"
value="[i-1,i-1]" />
</combo_box>
<combo_box
height="23"
label="Resolution"
layout="topleft"
left_delta="0"
name="local_size_combo"
top_delta="0"
width="127">
<combo_box.item
label="Current Window"
name="CurrentWindow"
value="[i0,i0]" />
<combo_box.item
label="320x240"
name="320x240"
value="[i320,i240]" />
<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.item
label="1280x1024"
name="1280x1024"
value="[i1280,i1024]" />
<combo_box.item
label="1600x1200"
name="1600x1200"
value="[i1600,i1200]" />
<combo_box.item
label="Custom"
name="Custom"
value="[i-1,i-1]" />
</combo_box>
<combo_box
height="23"
label="Format"
layout="topleft"
left_pad="5"
name="local_format_combo"
width="70">
<combo_box.item
label="PNG"
name="PNG" />
<combo_box.item
label="JPEG"
name="JPEG" />
<combo_box.item
label="BMP"
name="BMP" />
</combo_box>
<spinner
allow_text_entry="false"
decimal_digits="0"
follows="left|top"
height="20"
increment="32"
label="Width"
label_width="40"
layout="topleft"
left="10"
max_val="6016"
min_val="32"
name="snapshot_width"
left="0"
name="panel_container"
default_panel_name="panel_snapshot_options"
top_pad="10"
width="95" />
<spinner
allow_text_entry="false"
decimal_digits="0"
follows="left|top"
height="20"
increment="32"
label="Height"
label_width="40"
width="270">
<panel
class="llpanelsnapshotoptions"
filename="panel_snapshot_options.xml"
follows="all"
layout="topleft"
left="0"
name="panel_snapshot_options"
top="0" />
<panel
class="llpanelsnapshotprofile"
follows="all"
layout="topleft"
name="panel_snapshot_profile"
filename="panel_snapshot_profile.xml" />
<panel
class="llpanelsnapshotpostcard"
follows="all"
layout="topleft"
name="panel_snapshot_postcard"
filename="panel_snapshot_postcard.xml" />
<panel
class="llpanelsnapshotinventory"
follows="all"
layout="topleft"
name="panel_snapshot_inventory"
filename="panel_snapshot_inventory.xml" />
<panel
class="llpanelsnapshotlocal"
follows="all"
layout="topleft"
name="panel_snapshot_local"
filename="panel_snapshot_local.xml" />
</panel_container>
<panel
height="295"
layout="topleft"
left_pad="5"
max_val="6016"
min_val="32"
name="snapshot_height"
top_delta="0"
width="95" />
<check_box
bottom_delta="20"
label="Constrain proportions"
layout="topleft"
left="10"
name="keep_aspect_check" />
<slider
decimal_digits="0"
follows="left|top"
height="15"
increment="1"
initial_value="75"
label="Image quality"
label_width="124"
layout="topleft"
left_delta="0"
max_val="100"
name="image_quality_slider"
top_pad="5"
width="228" />
<text
type="string"
length="1"
follows="left|top"
height="13"
layout="topleft"
left="10"
name="layer_type_label"
top_pad="5"
width="50">
Capture:
</text>
<combo_box
height="23"
label="Image Layers"
layout="topleft"
left="30"
name="layer_types"
width="145">
<combo_box.item
label="Colors"
name="Colors"
value="colors" />
<combo_box.item
label="Depth"
name="Depth"
value="depth" />
</combo_box>
<check_box
label="Interface"
layout="topleft"
left="30"
top_pad="10"
width="180"
name="ui_check" />
<check_box
label="HUDs"
layout="topleft"
left="30"
top_pad="10"
width="180"
name="hud_check" />
<check_box
label="Keep open after saving"
layout="topleft"
left="10"
top_pad="8"
width="180"
name="keep_open_check" />
<check_box
label="Freeze frame (fullscreen)"
layout="topleft"
left="10"
top_pad="8"
width="180"
name="freeze_frame_check" />
<check_box
label="Auto-refresh"
layout="topleft"
left="10"
top_pad="8"
width="180"
name="auto_snapshot_check" />
left="270"
name="advanced_options_panel"
top="20"
width="200">
<text
type="string"
font="SansSerifSmall"
length="1"
follows="left|top"
height="14"
layout="topleft"
left="10"
halign="left"
name="advanced_options_label"
right="-10"
top="10">
ADVANCED OPTIONS
</text>
<view_border
bevel_style="in"
follows="left|top|right"
height="1"
left="10"
layout="topleft"
name="advanced_options_hr"
right="-10"
top_pad="5"
/>
<text
type="string"
length="1"
follows="left|top"
height="13"
layout="topleft"
left="10"
name="layer_type_label"
top_pad="10"
width="50">
Capture:
</text>
<combo_box
follows="left|top|right"
height="23"
label="Image Layers"
layout="topleft"
left="30"
name="layer_types"
right="-10">
<combo_box.item
label="Colors"
name="Colors"
value="colors" />
<combo_box.item
label="Depth"
name="Depth"
value="depth" />
</combo_box>
<check_box
label="Interface"
layout="topleft"
left="30"
top_pad="10"
width="180"
name="ui_check" />
<check_box
label="HUDs"
layout="topleft"
left="30"
top_pad="10"
width="180"
name="hud_check" />
<check_box
label="Freeze frame (fullscreen)"
layout="topleft"
left="10"
top_pad="8"
width="180"
name="freeze_frame_check" />
<check_box
label="Auto-refresh"
layout="topleft"
left="10"
top_pad="8"
width="180"
name="auto_snapshot_check" />
</panel>
</floater>

View File

@ -1,117 +1,87 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater
legacy_header_height="18"
can_minimize="false"
can_resize="true"
<panel
height="380"
layout="topleft"
min_height="380"
min_width="490"
name="Postcard"
help_topic="postcard"
title="EMAIL SNAPSHOT"
name="panel_postcard_message"
width="490">
<floater.string
name="default_subject">
Postcard from [SECOND_LIFE].
</floater.string>
<floater.string
name="default_message">
Check this out!
</floater.string>
<floater.string
name="upload_message">
Sending...
</floater.string>
<text
type="string"
length="1"
bottom="35"
follows="top|left"
font="SansSerif"
height="16"
layout="topleft"
left="12"
name="to_label">
Recipient&apos;s Email:
name="to_label"
top="10"
width="60">
To:
</text>
<line_editor
control_name="LastPostcardRecipient"
follows="left|top"
follows="left|top|right"
height="20"
layout="topleft"
left_delta="148"
left_pad="10"
name="to_form"
top_delta="-4"
width="150" />
right="-10"
top_delta="-4" />
<text
type="string"
length="1"
bottom_delta="23"
follows="top|left"
font="SansSerif"
height="16"
layout="topleft"
left="12"
name="from_label">
Your Email:
name="name_label"
width="60">
From:
</text>
<line_editor
follows="left|top"
follows="left|top|right"
height="20"
layout="topleft"
left_delta="148"
name="from_form"
top_delta="-4"
width="150" />
<text
type="string"
length="1"
bottom_delta="23"
follows="top|left"
font="SansSerif"
layout="topleft"
left="12"
name="name_label">
Your Name:
</text>
<line_editor
follows="left|top"
height="20"
layout="topleft"
left_delta="148"
left_pad="10"
max_length_bytes="100"
name="name_form"
top_delta="-4"
width="150" />
right="-10"
top_delta="-4" />
<text
type="string"
length="1"
bottom_delta="23"
follows="top|left"
font="SansSerif"
height="16"
layout="topleft"
left="12"
name="subject_label">
name="subject_label"
width="60">
Subject:
</text>
<line_editor
follows="left|top"
follows="left|top|right"
height="20"
label="Type your subject here."
layout="topleft"
left_delta="148"
left_pad="10"
max_length_bytes="100"
name="subject_form"
top_delta="-4"
width="150" />
right="-10"
top_delta="-4" />
<text
type="string"
length="1"
bottom_delta="23"
follows="top|left"
follows="top|left|right"
font="SansSerif"
layout="topleft"
left="12"
name="msg_label">
name="msg_label"
right="-10">
Message:
</text>
<text_editor
@ -123,9 +93,9 @@
left_delta="0"
max_length="700"
name="msg_form"
word_wrap="true"
right="-10"
top_pad="10"
width="420">
word_wrap="true">
Type your message here.
</text_editor>
<button
@ -136,7 +106,10 @@
name="cancel_btn"
right="-10"
top="350"
width="100" />
width="100">
<button.commit_callback
function="Postcard.Cancel" />
</button>
<button
follows="right|bottom"
height="23"
@ -145,5 +118,8 @@
left_delta="-106"
name="send_btn"
top_delta="0"
width="100" />
</floater>
width="100">
<button.commit_callback
function="Postcard.Send" />
</button>
</panel>

View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
height="380"
layout="topleft"
name="panel_postcard_settings"
width="490">
<combo_box
follows="left|top|right"
height="23"
label="Resolution"
layout="topleft"
left="10"
name="postcard_size_combo"
right="-10"
top_pad="10">
<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.item
label="Custom"
name="Custom"
value="[i-1,i-1]" />
</combo_box>
<spinner
allow_text_entry="false"
decimal_digits="0"
follows="left|top"
height="20"
increment="32"
label="Width"
label_width="40"
layout="topleft"
left="10"
max_val="6016"
min_val="32"
name="postcard_snapshot_width"
top_pad="10"
width="95" />
<spinner
allow_text_entry="false"
decimal_digits="0"
follows="left|top"
height="20"
increment="32"
label="Height"
label_width="40"
layout="topleft"
left_pad="5"
max_val="6016"
min_val="32"
name="postcard_snapshot_height"
top_delta="0"
width="95" />
<check_box
bottom_delta="20"
follows="left|top"
label="Constrain proportions"
layout="topleft"
left="10"
name="postcard_keep_aspect_check" />
<slider
decimal_digits="0"
follows="left|top"
height="15"
increment="1"
initial_value="75"
label="Image quality"
label_width="80"
layout="topleft"
left="10"
max_val="100"
name="image_quality_slider"
top_pad="7"
width="200" />
<text
type="string"
follows="left|top"
font="SansSerifSmall"
length="1"
height="14"
layout="topleft"
left_pad="-5"
halign="left"
name="image_quality_level"
top_delta="0"
width="60">
([QLVL])
</text>
</panel>

View File

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
height="380"
layout="topleft"
name="panel_snapshot_inventory"
width="490">
<icon
follows="top|left"
height="18"
image_name="Snapshot_Inventory"
layout="topleft"
left="12"
mouse_opaque="true"
name="title_icon"
top="5"
width="18" />
<text
follows="top|left|right"
font="SansSerifBold"
height="20"
layout="topleft"
left_pad="12"
length="1"
name="title"
right="-10"
text_color="white"
type="string"
top_delta="5">
Save to My Inventory
</text>
<view_border
bevel_style="in"
follows="left|top|right"
height="1"
left="10"
layout="topleft"
name="hr"
right="-10"
top_pad="5"
/>
<text
bottom="35"
follows="top|left|right"
font="SansSerif"
height="56"
layout="topleft"
left="12"
length="1"
name="hint_lbl"
top_pad="10"
type="string"
word_wrap="true">
Saving an image to your inventory costs L$[UPLOAD_COST]. To save your image as a texture select one of the square formats.
</text>
<combo_box
follows="top|left|right"
height="23"
label="Resolution"
layout="topleft"
left_delta="0"
name="texture_size_combo"
right="-10"
top_pad="10">
<combo_box.item
label="Current Window"
name="CurrentWindow"
value="[i0,i0]" />
<combo_box.item
label="Small (128x128)"
name="Small(128x128)"
value="[i128,i128]" />
<combo_box.item
label="Medium (256x256)"
name="Medium(256x256)"
value="[i256,i256]" />
<combo_box.item
label="Large (512x512)"
name="Large(512x512)"
value="[i512,i512]" />
<combo_box.item
label="Custom"
name="Custom"
value="[i-1,i-1]" />
</combo_box>
<spinner
allow_text_entry="false"
decimal_digits="0"
follows="left|top"
height="20"
increment="32"
label="Width"
label_width="40"
layout="topleft"
left="10"
max_val="6016"
min_val="32"
name="inventory_snapshot_width"
top_pad="10"
width="95" />
<spinner
allow_text_entry="false"
decimal_digits="0"
follows="left|top"
height="20"
increment="32"
label="Height"
label_width="40"
layout="topleft"
left_pad="5"
max_val="6016"
min_val="32"
name="inventory_snapshot_height"
top_delta="0"
width="95" />
<check_box
bottom_delta="20"
follows="left|top"
label="Constrain proportions"
layout="topleft"
left="10"
name="inventory_keep_aspect_check" />
<button
follows="right|bottom"
height="23"
label="Cancel"
layout="topleft"
name="cancel_btn"
right="-10"
top="350"
width="100">
<button.commit_callback
function="Inventory.Cancel" />
</button>
<button
follows="right|bottom"
height="23"
label="Save"
layout="topleft"
left_delta="-106"
name="save_btn"
top_delta="0"
width="100">
<button.commit_callback
function="Inventory.Save" />
</button>
</panel>

View File

@ -0,0 +1,194 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
height="380"
layout="topleft"
name="panel_snapshot_local"
width="490">
<icon
follows="top|left"
height="18"
image_name="Snapshot_Download"
layout="topleft"
left="12"
mouse_opaque="true"
name="title_icon"
top="5"
width="18" />
<text
follows="top|left|right"
font="SansSerifBold"
height="20"
layout="topleft"
left_pad="12"
length="1"
name="title"
right="-10"
text_color="white"
type="string"
top_delta="4">
Save to My Computer
</text>
<view_border
bevel_style="in"
follows="left|top|right"
height="1"
left="10"
layout="topleft"
name="hr"
right="-10"
top_pad="5"
/>
<combo_box
follows="left|top|right"
height="23"
label="Resolution"
layout="topleft"
left_delta="0"
name="local_size_combo"
right="-10"
top_pad="10">
<combo_box.item
label="Current Window"
name="CurrentWindow"
value="[i0,i0]" />
<combo_box.item
label="320x240"
name="320x240"
value="[i320,i240]" />
<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.item
label="1280x1024"
name="1280x1024"
value="[i1280,i1024]" />
<combo_box.item
label="1600x1200"
name="1600x1200"
value="[i1600,i1200]" />
<combo_box.item
label="Custom"
name="Custom"
value="[i-1,i-1]" />
</combo_box>
<spinner
allow_text_entry="false"
decimal_digits="0"
follows="left|top"
height="20"
increment="32"
label="Width"
label_width="40"
layout="topleft"
left="10"
max_val="6016"
min_val="32"
name="local_snapshot_width"
top_pad="10"
width="95" />
<spinner
allow_text_entry="false"
decimal_digits="0"
follows="left|top"
height="20"
increment="32"
label="Height"
label_width="40"
layout="topleft"
left_pad="5"
max_val="6016"
min_val="32"
name="local_snapshot_height"
top_delta="0"
width="95" />
<check_box
bottom_delta="20"
follows="left|top"
label="Constrain proportions"
layout="topleft"
left="10"
name="local_keep_aspect_check" />
<combo_box
follows="left|top"
height="23"
label="Format"
layout="topleft"
left_delta="0"
name="local_format_combo"
top_pad="10"
width="120">
<combo_box.item
label="PNG (Lossless)"
name="PNG"
value="PNG" />
<combo_box.item
label="JPEG"
name="JPEG"
value="JPEG" />
<combo_box.item
label="BMP (Lossless)"
name="BMP"
value="BMP" />
</combo_box>
<slider
decimal_digits="0"
follows="left|top"
height="15"
increment="1"
initial_value="75"
label="Image quality"
label_width="80"
layout="topleft"
left="10"
max_val="100"
name="image_quality_slider"
top_pad="7"
width="200" />
<text
type="string"
follows="left|top"
font="SansSerifSmall"
length="1"
height="14"
layout="topleft"
left_pad="-5"
halign="left"
name="image_quality_level"
top_delta="0"
width="60">
([QLVL])
</text>
<button
follows="right|bottom"
height="23"
label="Cancel"
layout="topleft"
name="cancel_btn"
right="-10"
top="350"
width="100">
<button.commit_callback
function="Local.Cancel" />
</button>
<button
follows="right|bottom"
height="23"
label="Save"
layout="topleft"
left_delta="-106"
name="save_btn"
top_delta="0"
width="100">
<button.commit_callback
function="Local.Save" />
</button>
</panel>

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
follows="all"
height="240"
layout="topleft"
name="panel_snapshot_options"
width="490">
<button
follows="left|top|right"
font="SansSerif"
halign="left"
height="38"
image_overlay="Snapshot_Profile"
image_overlay_alignment="left"
image_top_pad="-2"
imgoverlay_label_space="10"
label="Post to My Profile Feed"
layout="topleft"
left="10"
name="save_to_profile_btn"
pad_left="10"
right="-10"
top="5">
<button.commit_callback
function="Snapshot.SaveToProfile" />
</button>
<button
follows="left|top|right"
font="SansSerif"
halign="left"
height="38"
image_overlay="Snapshot_Email"
image_overlay_alignment="left"
image_top_pad="-2"
imgoverlay_label_space="10"
label="Email"
layout="topleft"
left_delta="0"
name="save_to_email_btn"
pad_left="10"
right="-10"
top_pad="10">
<button.commit_callback
function="Snapshot.SaveToEmail" />
</button>
<button
follows="left|top|right"
font="SansSerif"
halign="left"
height="38"
image_overlay="Snapshot_Inventory"
image_overlay_alignment="left"
image_top_pad="-2"
imgoverlay_label_space="10"
label="Save to My Inventory (L$[AMOUNT])"
layout="topleft"
left_delta="0"
name="save_to_inventory_btn"
pad_left="10"
right="-10"
top_pad="10">
<button.commit_callback
function="Snapshot.SaveToInventory" />
</button>
<button
follows="left|top|right"
font="SansSerif"
halign="left"
height="38"
image_overlay="Snapshot_Download"
image_overlay_alignment="left"
image_top_pad="-2"
imgoverlay_label_space="10"
label="Save to My Computer"
layout="topleft"
left_delta="0"
name="save_to_computer_btn"
pad_left="10"
right="-10"
top_pad="10">
<button.commit_callback
function="Snapshot.SaveToComputer" />
</button>
<panel
background_visible="true"
bg_alpha_color="0.9 1 0.9 1"
bottom="-10"
follows="left|bottom|right"
font="SansSerifLarge"
halign="center"
height="20"
layout="topleft"
left_delta="0"
length="1"
name="succeeded_panel"
right="-10"
type="string"
visible="false">
<text
follows="all"
font="SansSerif"
halign="center"
height="18"
layout="topleft"
left="1"
length="1"
name="succeeded_lbl"
right="-1"
text_color="0.2 0.5 0.2 1"
top="4"
translate="false"
type="string">
Succeeded
</text>
</panel>
<panel
background_visible="true"
bg_alpha_color="1 0.9 0.9 1"
bottom="-10"
follows="left|bottom|right"
font="SansSerifLarge"
halign="center"
height="20"
layout="topleft"
left_delta="0"
length="1"
name="failed_panel"
right="-10"
type="string"
visible="false">
<text
follows="all"
font="SansSerif"
halign="center"
height="18"
layout="topleft"
left="1"
length="1"
name="failed_lbl"
right="-1"
text_color="0.5 0.2 0.2 1"
top="4"
translate="false"
type="string">
Failed
</text>
</panel>
</panel>

View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
height="380"
layout="topleft"
name="panel_snapshot_postcard"
width="490">
<string
name="default_subject">
Postcard from [SECOND_LIFE].
</string>
<string
name="default_message">
Check this out!
</string>
<string
name="upload_message">
Sending...
</string>
<string
name="default_subject">
Postcard from [SECOND_LIFE].
</string>
<string
name="default_message">
Check this out!
</string>
<icon
follows="top|left"
height="18"
image_name="Snapshot_Email"
layout="topleft"
left="12"
mouse_opaque="true"
name="title_icon"
top="5"
width="18" />
<text
follows="top|left|right"
font="SansSerifBold"
height="20"
layout="topleft"
left_pad="12"
length="1"
name="title"
right="-10"
text_color="white"
type="string"
top_delta="3">
Email
</text>
<button
follows="right|top"
height="23"
is_toggle="true"
label="Message"
layout="topleft"
name="message_btn"
right="-82"
top_delta="-7"
width="70">
<button.commit_callback
function="Postcard.Message" />
</button>
<button
follows="right|top"
height="23"
is_toggle="true"
label="Settings"
layout="topleft"
name="settings_btn"
top_delta="0"
right="-10"
width="70">
<button.commit_callback
function="Postcard.Settings" />
</button>
<view_border
bevel_style="in"
follows="left|top|right"
height="1"
left="10"
layout="topleft"
name="hr"
right="-10"
top_pad="5"
/>
<panel_container
follows="all"
height="340"
layout="topleft"
left="0"
name="postcard_panel_container"
default_panel_name="panel_postcard_message"
top_pad="10"
width="490">
<panel
follows="all"
layout="topleft"
name="panel_postcard_message"
filename="panel_postcard_message.xml" />
<panel
follows="all"
layout="topleft"
name="panel_postcard_settings"
filename="panel_postcard_settings.xml" />
</panel_container>
</panel>

View File

@ -0,0 +1,165 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
height="380"
layout="topleft"
name="panel_snapshot_profile"
width="490">
<icon
follows="top|left"
height="18"
image_name="Snapshot_Profile"
layout="topleft"
left="12"
mouse_opaque="true"
name="title_icon"
top="5"
width="18" />
<text
follows="top|left|right"
font="SansSerifBold"
height="20"
layout="topleft"
left_pad="12"
length="1"
name="title"
right="-10"
text_color="white"
type="string"
top_delta="4">
Post to My Profile Feed
</text>
<view_border
bevel_style="in"
follows="left|top|right"
height="1"
left="10"
layout="topleft"
name="hr"
right="-10"
top_pad="5"
/>
<combo_box
follows="left|top"
height="23"
label="Resolution"
layout="topleft"
left_delta="0"
name="profile_size_combo"
top_pad="10"
width="250">
<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.item
label="Custom"
name="Custom"
value="[i-1,i-1]" />
</combo_box>
<spinner
allow_text_entry="false"
decimal_digits="0"
follows="left|top"
height="20"
increment="32"
label="Width"
label_width="40"
layout="topleft"
left="10"
max_val="6016"
min_val="32"
name="profile_snapshot_width"
top_pad="10"
width="95" />
<spinner
allow_text_entry="false"
decimal_digits="0"
follows="left|top"
height="20"
increment="32"
label="Height"
label_width="40"
layout="topleft"
left_pad="5"
max_val="6016"
min_val="32"
name="profile_snapshot_height"
top_delta="0"
width="95" />
<check_box
bottom_delta="20"
label="Constrain proportions"
layout="topleft"
left="10"
name="profile_keep_aspect_check" />
<text
length="1"
follows="top|left|right"
font="SansSerif"
height="16"
layout="topleft"
left="12"
name="caption_label"
right="-10"
top_pad="10"
type="string">
Caption:
</text>
<text_editor
follows="all"
height="170"
layout="topleft"
left_delta="0"
length="1"
max_length="700"
name="caption"
right="-10"
top_pad="5"
type="string"
word_wrap="true">
</text_editor>
<check_box
follows="left|bottom"
initial_value="true"
label="Include location"
layout="topleft"
left_delta="0"
name="add_location_cb"
top_pad="15" />
<button
follows="right|bottom"
height="23"
label="Cancel"
layout="topleft"
name="cancel_btn"
right="-10"
top="350"
width="100">
<button.commit_callback
function="PostToProfile.Cancel" />
</button>
<button
follows="right|bottom"
height="23"
label="Post"
layout="topleft"
left_delta="-106"
name="post_btn"
top_delta="0"
width="100">
<button.commit_callback
function="PostToProfile.Send" />
</button>
</panel>

View File

@ -3724,4 +3724,12 @@ Try enclosing path to the editor with double quotes.
<string name="Wrap">Wrap</string>
<string name="Preview">Preview</string>
<string name="Normal">Normal</string>
<!-- Snapshot image quality levels -->
<string name="snapshot_quality_very_low">Very Low</string>
<string name="snapshot_quality_low">Low</string>
<string name="snapshot_quality_medium">Medium</string>
<string name="snapshot_quality_high">High</string>
<string name="snapshot_quality_very_high">Very High</string>
</strings>