diff options
-rw-r--r-- | indra/newview/lllocalbitmaps.cpp | 60 | ||||
-rw-r--r-- | indra/newview/lllocalbitmaps.h | 1 | ||||
-rw-r--r-- | indra/newview/llpanelprofile.cpp | 141 | ||||
-rw-r--r-- | indra/newview/llpanelprofile.h | 10 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/panel_profile_secondlife.xml | 17 |
5 files changed, 165 insertions, 64 deletions
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 5a17332fde..de8db69e19 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -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(); } diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index d5ee7efdc6..c29f3f62f6 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -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); diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 156d2671f4..c19688191b 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -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); + return; + }*/ + if (mHandle->isDead()) + { + return; } - else + std::string file_path = filenames[0]; + if (file_path.empty()) { - imagep->setLoadedCallback(onImageLoaded, - MAX_DISCARD_LEVEL, - FALSE, - FALSE, - new LLHandle<LLPanel>(getHandle()), - NULL, - FALSE); + 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) diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index e87de9f96f..9aab8a087c 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -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; }; diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml index 816b0b8f5c..d8d2749a2b 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml @@ -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" |