SL-16937 New Profile capability, image uploader for testing

This commit is mostly to simplify cap testing for server side. Plan is to remove LLLocalBitmap and draw texture more directly instead
master
Andrey Kleshchev 2022-03-30 18:32:42 +03:00
parent cd61dbe6ee
commit 8f6d149fad
5 changed files with 166 additions and 65 deletions

View File

@ -919,6 +919,36 @@ LLLocalBitmapMgr::~LLLocalBitmapMgr()
mBitmapList.clear();
}
LLUUID LLLocalBitmapMgr::addUnit(const std::string &filename)
{
if (!checkTextureDimensions(filename))
{
return LLUUID::null;
}
LLLocalBitmap* unit = new LLLocalBitmap(filename);
if (unit->getValid())
{
mBitmapList.push_back(unit);
return unit->getTrackingID();
}
else
{
LL_WARNS() << "Attempted to add invalid or unreadable image file, attempt cancelled.\n"
<< "Filename: " << filename << LL_ENDL;
LLSD notif_args;
notif_args["FNAME"] = filename;
LLNotificationsUtil::add("LocalBitmapsVerifyFail", notif_args);
delete unit;
unit = NULL;
}
return LLUUID::null;
}
bool LLLocalBitmapMgr::addUnit()
{
bool add_successful = false;
@ -931,32 +961,10 @@ bool LLLocalBitmapMgr::addUnit()
std::string filename = picker.getFirstFile();
while(!filename.empty())
{
if(!checkTextureDimensions(filename))
{
filename = picker.getNextFile();
continue;
}
LLLocalBitmap* unit = new LLLocalBitmap(filename);
if (unit->getValid())
{
mBitmapList.push_back(unit);
add_successful = true;
}
else
{
LL_WARNS() << "Attempted to add invalid or unreadable image file, attempt cancelled.\n"
<< "Filename: " << filename << LL_ENDL;
LLSD notif_args;
notif_args["FNAME"] = filename;
LLNotificationsUtil::add("LocalBitmapsVerifyFail", notif_args);
delete unit;
unit = NULL;
}
if (addUnit(filename).notNull())
{
add_successful = true;
}
filename = picker.getNextFile();
}

View File

@ -116,6 +116,7 @@ class LLLocalBitmapMgr : public LLSingleton<LLLocalBitmapMgr>
~LLLocalBitmapMgr();
public:
bool addUnit();
LLUUID addUnit(const std::string &filename);
void delUnit(LLUUID tracking_id);
bool checkTextureDimensions(std::string filename);

View File

@ -58,6 +58,7 @@
#include "llcallingcard.h"
#include "llcommandhandler.h"
#include "llfloaterreg.h"
#include "llfilepicker.h"
#include "llfirstuse.h"
#include "llgroupactions.h"
#include "llmutelist.h"
@ -68,6 +69,7 @@
#include "lltrans.h"
#include "llviewercontrol.h"
#include "llviewermenu.h" //is_agent_mappable
#include "llviewermenufile.h"
#include "llviewertexturelist.h"
#include "llvoiceclient.h"
#include "llweb.h"
@ -324,17 +326,20 @@ void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::s
if (!status)
{
LL_WARNS("AvatarProperties") << "Failed to get uploader cap " << status.toString() << LL_ENDL;
LLFile::remove(path_to_image);
return;
}
if (!result.has("uploader"))
{
LL_WARNS("AvatarProperties") << "Failed to get uploader cap, response contains no data." << LL_ENDL;
LLFile::remove(path_to_image);
return;
}
std::string uploader_cap = result["uploader"].asString();
if (uploader_cap.empty())
{
LL_WARNS("AvatarProperties") << "Failed to get uploader cap, cap invalid." << LL_ENDL;
LLFile::remove(path_to_image);
return;
}
@ -350,6 +355,7 @@ void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::s
if (!instream.is_open())
{
LL_WARNS("AvatarProperties") << "Failed to open file " << path_to_image << LL_ENDL;
LLFile::remove(path_to_image);
return;
}
length = instream.tellg();
@ -367,6 +373,7 @@ void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::s
if (!status)
{
LL_WARNS("AvatarProperties") << "Failed to upload image " << status.toString() << LL_ENDL;
LLFile::remove(path_to_image);
return;
}
@ -380,6 +387,7 @@ void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::s
{
LL_WARNS("AvatarProperties") << "Failed to upload image " << result << LL_ENDL;
}
LLFile::remove(path_to_image);
return;
}
@ -575,6 +583,8 @@ LLPanelProfileSecondLife::~LLPanelProfileSecondLife()
{
mAvatarNameCacheConnection.disconnect();
}
clearUploadProfileImagePath();
}
BOOL LLPanelProfileSecondLife::postBuild()
@ -582,7 +592,7 @@ BOOL LLPanelProfileSecondLife::postBuild()
mStatusText = getChild<LLTextBox>("status");
mGroupList = getChild<LLGroupList>("group_list");
mShowInSearchCheckbox = getChild<LLCheckBoxCtrl>("show_in_search_checkbox");
mSecondLifePic = getChild<LLTextureCtrl>("2nd_life_pic");
mSecondLifePic = getChild<LLIconCtrl>("2nd_life_pic");
mSecondLifePicLayout = getChild<LLPanel>("image_stack");
mDescriptionEdit = getChild<LLTextBase>("sl_description_edit");
mTeleportButton = getChild<LLButton>("teleport");
@ -610,7 +620,7 @@ BOOL LLPanelProfileSecondLife::postBuild()
mUnblockButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onClickToggleBlock, this));
mGroupInviteButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onGroupInvite,this));
mDisplayNameButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onClickSetName, this));
mSecondLifePic->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onCommitTexture, this));
mSecondLifePic->setMouseUpCallback(boost::bind(&LLPanelProfileSecondLife::onPickTexture, this));
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit;
commit.add("Profile.CopyName", [this](LLUICtrl*, const LLSD& userdata) { onCommitMenu(userdata); });
@ -650,8 +660,6 @@ void LLPanelProfileSecondLife::onOpen(const LLSD& key)
mGroupList->setShowNone(!own_profile);
mGiveInvPanel->setVisible(!own_profile);
mSecondLifePic->setOpenTexPreview(!own_profile);
if (own_profile && !getEmbedded())
{
// Group list control cannot toggle ForAgent loading
@ -693,10 +701,11 @@ void LLPanelProfileSecondLife::apply(LLAvatarData* data)
LLSD params = LLSDMap();
// we have an image, check if it is local. Server won't recognize local ids.
if (data->image_id != mSecondLifePic->getImageAssetID()
&& !LLLocalBitmapMgr::getInstance()->isLocal(mSecondLifePic->getImageAssetID()))
if (data->image_id != mImageAssetId
&& mImageFile.empty()
&& !LLLocalBitmapMgr::getInstance()->isLocal(mImageAssetId))
{
params["sl_image_id"] = mSecondLifePic->getImageAssetID();
params["sl_image_id"] = mImageAssetId;
}
if (data->about_text != mDescriptionEdit->getValue().asString())
{
@ -721,12 +730,19 @@ void LLPanelProfileSecondLife::apply(LLAvatarData* data)
}
// Only if image is local
if (data->image_id != mSecondLifePic->getImageAssetID()
&& LLLocalBitmapMgr::getInstance()->isLocal(mSecondLifePic->getImageAssetID()))
if (!mImageFile.empty())
{
// todo: temporary file, connect to UI
std::string file_path = gDirUtilp->findSkinnedFilename("textures", "icons/Default_Outfit_Photo.png");
launch_profile_image_coro(PROFILE_IMAGE_SL, file_path);
std::string cap_url = gAgent.getRegionCapability(PROFILE_IMAGE_UPLOAD_CAP);
if (!cap_url.empty())
{
LLCoros::instance().launch("postAgentUserImageCoro",
boost::bind(post_profile_image_coro, cap_url, PROFILE_IMAGE_SL, mImageFile));
mImageFile.clear(); // coro should do the deleting
}
else
{
LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", no cap found" << LL_ENDL;
}
}
}
}
@ -773,7 +789,7 @@ void LLPanelProfileSecondLife::resetData()
getChild<LLUICtrl>("partner_text")->setValue(LLStringUtil::null);
// Set default image and 1:1 dimensions for it
mSecondLifePic->setValue(mSecondLifePic->getDefaultImageAssetID());
mSecondLifePic->setValue("Generic_Person_Large");
LLRect imageRect = mSecondLifePicLayout->getRect();
mSecondLifePicLayout->reshape(imageRect.getHeight(), imageRect.getHeight());
@ -782,6 +798,7 @@ void LLPanelProfileSecondLife::resetData()
mCopyMenuButton->setVisible(FALSE);
mGroups.clear();
mGroupList->setGroups(mGroups);
clearUploadProfileImagePath();
}
void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avatar_data)
@ -845,6 +862,37 @@ void LLPanelProfileSecondLife::onAvatarNameCache(const LLUUID& agent_id, const L
mCopyMenuButton->setVisible(TRUE);
}
void LLPanelProfileSecondLife::setUploadProfileImagePath(const std::string &path, const std::string &orig_path)
{
clearUploadProfileImagePath();
// todo: display this in floater,
// LLIconCtrl can't show a path, only by id or name, so may be draw directly or add as a local bitmap?
// LLLocalBitmap* unit = new LLLocalBitmap(path);
// assign a local texture to view in viewer
// Todo: remove LLLocalBitmap and just draw texture instead
// orig_path was used instead of path, since LLLocalBitmapMgr does not support j2c
LLUUID tracking_id = LLLocalBitmapMgr::getInstance()->addUnit(orig_path);
if (tracking_id.isNull())
{
// todo: error handling
return;
}
mImageFile = path;
mImageAssetId = LLLocalBitmapMgr::getInstance()->getWorldID(tracking_id);
mSecondLifePic->setValue(mImageAssetId);
}
void LLPanelProfileSecondLife::clearUploadProfileImagePath()
{
if (!mImageFile.empty())
{
LLFile::remove(mImageFile); //todo: supress errors, may be not need to remove if it becomes a LLLocalBitmap
}
mImageFile.clear();
}
void LLPanelProfileSecondLife::fillCommonData(const LLAvatarData* avatar_data)
{
// Refresh avatar id in cache with new info to prevent re-requests
@ -862,7 +910,8 @@ void LLPanelProfileSecondLife::fillCommonData(const LLAvatarData* avatar_data)
std::string register_date = getString("RegisterDateFormat", args);
getChild<LLUICtrl>("register_date")->setValue(register_date );
mDescriptionEdit->setValue(avatar_data->about_text);
mSecondLifePic->setValue(avatar_data->image_id);
mImageAssetId = avatar_data->image_id;
mSecondLifePic->setValue(mImageAssetId);
//Don't bother about boost level, picker will set it
LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(avatar_data->image_id);
@ -1119,23 +1168,63 @@ void LLPanelProfileSecondLife::onClickSetName()
LLFirstUse::setDisplayName(false);
}
void LLPanelProfileSecondLife::onCommitTexture()
class LLProfileImagePicker : public LLFilePickerThread
{
LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(mSecondLifePic->getImageAssetID());
if (imagep->getFullHeight())
public:
LLProfileImagePicker(LLHandle<LLPanel> *handle);
~LLProfileImagePicker();
virtual void notify(const std::vector<std::string>& filenames);
private:
LLHandle<LLPanel> *mHandle;
};
LLProfileImagePicker::LLProfileImagePicker(LLHandle<LLPanel> *handle)
: LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE),
mHandle(handle)
{
}
LLProfileImagePicker::~LLProfileImagePicker()
{
delete mHandle;
}
void LLProfileImagePicker::notify(const std::vector<std::string>& filenames)
{
/*if (LLAppViewer::instance()->quitRequested())
{
onImageLoaded(true, imagep);
}
else
return;
}*/
if (mHandle->isDead())
{
imagep->setLoadedCallback(onImageLoaded,
MAX_DISCARD_LEVEL,
FALSE,
FALSE,
new LLHandle<LLPanel>(getHandle()),
NULL,
FALSE);
return;
}
std::string file_path = filenames[0];
if (file_path.empty())
{
return;
}
// generate a temp texture file for coroutine
std::string temp_file = gDirUtilp->getTempFilename();
U32 codec = LLImageBase::getCodecFromExtension(gDirUtilp->getExtension(file_path));
const S32 MAX_DIM = 256;
if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, MAX_DIM))
{
// todo: error handling
return;
}
LLPanelProfileSecondLife* panel = static_cast<LLPanelProfileSecondLife*>(mHandle->get());
panel->setUploadProfileImagePath(temp_file, file_path);
}
void LLPanelProfileSecondLife::onPickTexture()
{
(new LLProfileImagePicker(new LLHandle<LLPanel>(getHandle())))->getFile();
}
void LLPanelProfileSecondLife::onCommitMenu(const LLSD& userdata)

View File

@ -46,6 +46,7 @@
class LLAvatarName;
class LLCheckBoxCtrl;
class LLIconCtrl;
class LLTabContainer;
class LLTextBox;
class LLTextureCtrl;
@ -102,6 +103,9 @@ public:
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
void setUploadProfileImagePath(const std::string &path, const std::string &orig_path);
void clearUploadProfileImagePath();
friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);
protected:
@ -178,7 +182,7 @@ protected:
private:
/*virtual*/ void updateButtons();
void onClickSetName();
void onCommitTexture();
void onPickTexture();
void onCommitMenu(const LLSD& userdata);
void onAvatarNameCacheSetName(const LLUUID& id, const LLAvatarName& av_name);
@ -190,7 +194,7 @@ private:
LLTextBox* mStatusText;
LLGroupList* mGroupList;
LLCheckBoxCtrl* mShowInSearchCheckbox;
LLTextureCtrl* mSecondLifePic;
LLIconCtrl* mSecondLifePic;
LLPanel* mSecondLifePicLayout;
LLTextBase* mDescriptionEdit;
LLButton* mTeleportButton;
@ -207,6 +211,8 @@ private:
LLPanel* mGiveInvPanel;
bool mVoiceStatus;
std::string mImageFile;
LLUUID mImageAssetId;
boost::signals2::connection mAvatarNameCacheConnection;
};

View File

@ -177,19 +177,16 @@
auto_resize="false"
user_resize="false"
>
<!-- 23 pixels (BTN_HEIGHT_SMALL) are reserved by label field of texture and shouldn't be visible-->
<texture_picker
<icon
name="2nd_life_pic"
image_name="Generic_Person_Large"
layout="topleft"
follows="all"
top="0"
left="0"
right="-1"
height="180"
follows="all"
layout="topleft"
allow_no_texture="true"
default_image_name="None"
fallback_image="Generic_Person_Large"
/>
width="157"
height="157"/>
</layout_panel>
<layout_panel
name="label_stack"