diff options
Diffstat (limited to 'indra/newview/llfloaterchangeitemthumbnail.cpp')
-rw-r--r-- | indra/newview/llfloaterchangeitemthumbnail.cpp | 306 |
1 files changed, 240 insertions, 66 deletions
diff --git a/indra/newview/llfloaterchangeitemthumbnail.cpp b/indra/newview/llfloaterchangeitemthumbnail.cpp index ec01571e32..3a9612a354 100644 --- a/indra/newview/llfloaterchangeitemthumbnail.cpp +++ b/indra/newview/llfloaterchangeitemthumbnail.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfloaterchangeitemthumbnail.cpp * @brief LLFloaterChangeItemThumbnail class implementation * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2023, 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$ */ @@ -52,26 +52,32 @@ class LLThumbnailImagePicker : public LLFilePickerThread { public: - LLThumbnailImagePicker(const LLUUID &item_id); - LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id); + LLThumbnailImagePicker(const LLUUID &item_id, LLFloaterSimpleSnapshot::completion_t callback); + LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id, LLFloaterSimpleSnapshot::completion_t callback); ~LLThumbnailImagePicker(); void notify(const std::vector<std::string>& filenames) override; private: LLUUID mInventoryId; LLUUID mTaskId; + LLFloaterSimpleSnapshot::completion_t mCallback; }; -LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id) +LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id, + LLFloaterSimpleSnapshot::completion_t callback) : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE) , mInventoryId(item_id) + , mCallback(callback) { } -LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id) +LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id, + const LLUUID &task_id, + LLFloaterSimpleSnapshot::completion_t callback) : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE) , mInventoryId(item_id) , mTaskId(task_id) + , mCallback(callback) { } @@ -90,13 +96,14 @@ void LLThumbnailImagePicker::notify(const std::vector<std::string>& filenames) { return; } - - LLFloaterSimpleSnapshot::uploadThumbnail(file_path, mInventoryId, mTaskId); + + LLFloaterSimpleSnapshot::uploadThumbnail(file_path, mInventoryId, mTaskId, mCallback); } LLFloaterChangeItemThumbnail::LLFloaterChangeItemThumbnail(const LLSD& key) : LLFloater(key) , mObserverInitialized(false) + , mMultipleThumbnails(false) , mTooltipState(TOOLTIP_NONE) { } @@ -107,15 +114,17 @@ LLFloaterChangeItemThumbnail::~LLFloaterChangeItemThumbnail() removeVOInventoryListener(); } -BOOL LLFloaterChangeItemThumbnail::postBuild() +bool LLFloaterChangeItemThumbnail::postBuild() { mItemNameText = getChild<LLUICtrl>("item_name"); mItemTypeIcon = getChild<LLIconCtrl>("item_type_icon"); mThumbnailCtrl = getChild<LLThumbnailCtrl>("item_thumbnail"); mToolTipTextBox = getChild<LLTextBox>("tooltip_text"); + mMultipleTextBox = getChild<LLTextBox>("multiple_lbl"); LLSD tooltip_text; mToolTipTextBox->setValue(tooltip_text); + mMultipleTextBox->setVisible(false); LLButton *upload_local = getChild<LLButton>("upload_local"); upload_local->setClickedCallback(onUploadLocal, (void*)this); @@ -152,21 +161,55 @@ BOOL LLFloaterChangeItemThumbnail::postBuild() void LLFloaterChangeItemThumbnail::onOpen(const LLSD& key) { - if (!key.has("item_id") && !key.isUUID()) + if (!key.has("item_id") && !key.isUUID() && !key.isArray()) { closeFloater(); } - if (key.isUUID()) + mItemList.clear(); + mMultipleThumbnails = false; + if (key.isArray()) { - mItemId = key.asUUID(); + if (key.size() > 50) + { + // incident avoidance + LLNotificationsUtil::add("ThumbnailSelectionTooLarge"); + closeFloater(); + } + + LLUUID image_id; + for (LLSD::array_const_iterator it = key.beginArray(); it != key.endArray(); ++it) + { + LLInventoryObject* obj = gInventory.getObject(it->asUUID()); + if (obj) + { + if (mItemList.empty()) + { + image_id = obj->getThumbnailUUID(); + } + mItemList.insert(it->asUUID()); + if (image_id != obj->getThumbnailUUID()) + { + mMultipleThumbnails = true; + } + } + } + } + else if (key.isUUID()) + { + mItemList.insert(key.asUUID()); } else { - mItemId = key["item_id"].asUUID(); + mItemList.insert(key["item_id"].asUUID()); mTaskId = key["task_id"].asUUID(); } + if (mItemList.size() == 0) + { + closeFloater(); + } + refreshFromInventory(); } @@ -180,11 +223,11 @@ void LLFloaterChangeItemThumbnail::onMouseEnter(S32 x, S32 y, MASK mask) mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents()); } -BOOL LLFloaterChangeItemThumbnail::handleDragAndDrop( +bool LLFloaterChangeItemThumbnail::handleDragAndDrop( S32 x, S32 y, MASK mask, - BOOL drop, + bool drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, @@ -214,14 +257,14 @@ BOOL LLFloaterChangeItemThumbnail::handleDragAndDrop( LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFloaterChangeItemThumbnail " << getKey() << LL_ENDL; - return TRUE; + return true; } void LLFloaterChangeItemThumbnail::changed(U32 mask) { //LLInventoryObserver - if (mTaskId.notNull() || mItemId.isNull()) + if (mTaskId.notNull() || mItemList.size() == 0) { // Task inventory or not set up yet return; @@ -229,13 +272,13 @@ void LLFloaterChangeItemThumbnail::changed(U32 mask) const std::set<LLUUID>& mChangedItemIDs = gInventory.getChangedIDs(); std::set<LLUUID>::const_iterator it; + const LLUUID expected_id = *mItemList.begin(); for (it = mChangedItemIDs.begin(); it != mChangedItemIDs.end(); it++) { - // set dirty for 'item profile panel' only if changed item is the item for which 'item profile panel' is shown (STORM-288) - if (*it == mItemId) + // check if there's a change we're interested in. + if (*it == expected_id) { - // if there's a change we're interested in. if ((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0) { refreshFromInventory(); @@ -255,6 +298,12 @@ void LLFloaterChangeItemThumbnail::inventoryChanged(LLViewerObject* object, LLInventoryObject* LLFloaterChangeItemThumbnail::getInventoryObject() { + if (mItemList.size() == 0) + { + return NULL; + } + + const LLUUID item_id = *mItemList.begin(); LLInventoryObject* obj = NULL; if (mTaskId.isNull()) { @@ -265,7 +314,7 @@ LLInventoryObject* LLFloaterChangeItemThumbnail::getInventoryObject() mObserverInitialized = true; } - obj = gInventory.getObject(mItemId); + obj = gInventory.getObject(item_id); } else { @@ -278,7 +327,7 @@ LLInventoryObject* LLFloaterChangeItemThumbnail::getInventoryObject() mObserverInitialized = false; } - obj = object->getInventoryObject(mItemId); + obj = object->getInventoryObject(item_id); } } return obj; @@ -337,7 +386,7 @@ void LLFloaterChangeItemThumbnail::refreshFromObject(LLInventoryObject* obj) { setTitle(getString("title_item_thumbnail")); - icon_img = LLInventoryIcon::getIcon(item->getType(), item->getInventoryType(), item->getFlags(), FALSE); + icon_img = LLInventoryIcon::getIcon(item->getType(), item->getInventoryType(), item->getFlags(), false); mRemoveImageBtn->setEnabled(thumbnail_id.notNull() && ((item->getActualType() != LLAssetType::AT_TEXTURE) || (item->getAssetUUID() != thumbnail_id))); } else @@ -357,7 +406,7 @@ void LLFloaterChangeItemThumbnail::refreshFromObject(LLInventoryObject* obj) LLInventoryModel::item_array_t items; // Not LLIsOfAssetType, because we allow links LLIsOutfitTextureType f; - gInventory.getDirectDescendentsOf(mItemId, cats, items, f); + gInventory.getDirectDescendentsOf(*mItemList.begin(), cats, items, f); if (1 == items.size()) { @@ -384,12 +433,44 @@ void LLFloaterChangeItemThumbnail::refreshFromObject(LLInventoryObject* obj) mRemoveImageBtn->setEnabled(thumbnail_id.notNull()); } } - mItemTypeIcon->setImage(icon_img); - mItemNameText->setValue(obj->getName()); + if (mItemList.size() == 1) + { + mItemTypeIcon->setImage(icon_img); + mItemTypeIcon->setVisible(true); + mMultipleTextBox->setVisible(false); + mItemNameText->setValue(obj->getName()); + mItemNameText->setToolTip(std::string()); + } + else + { + mItemTypeIcon->setVisible(false); + mMultipleTextBox->setVisible(mMultipleThumbnails); + mItemNameText->setValue(getString("multiple_item_names")); + + // Display first five names as a tooltip + const S32 ITEMS_TO_SHOW = 5; + std::string items_str; + uuid_set_t::iterator iter = mItemList.begin(); + uuid_set_t::iterator end = mItemList.end(); + for (S32 i = 0; (iter != end) && (i < ITEMS_TO_SHOW); iter++, i++) + { + LLInventoryObject* pobj = gInventory.getObject(*iter); + if (pobj) + { + items_str += pobj->getName(); + items_str += '\n'; + } + } + if (mItemList.size() > ITEMS_TO_SHOW) + { + items_str += "..."; + } + mItemNameText->setToolTip(items_str); + } mThumbnailCtrl->setValue(thumbnail_id); - mCopyToClipboardBtn->setEnabled(thumbnail_id.notNull()); + mCopyToClipboardBtn->setEnabled(thumbnail_id.notNull() && !mMultipleThumbnails); mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents()); // todo: some elements might not support setting thumbnails @@ -401,7 +482,17 @@ void LLFloaterChangeItemThumbnail::onUploadLocal(void *userdata) { LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata; - (new LLThumbnailImagePicker(self->mItemId, self->mTaskId))->getFile(); + LLUUID task_id = self->mTaskId; + uuid_set_t inventory_ids = self->mItemList; + LLHandle<LLFloater> handle = self->getHandle(); + (new LLThumbnailImagePicker( + *self->mItemList.begin(), + self->mTaskId, + [inventory_ids, task_id, handle](const LLUUID& asset_id) + { + onUploadComplete(asset_id, task_id, inventory_ids, handle); + } + ))->getFile(); LLFloater* floaterp = self->mPickerHandle.get(); if (floaterp) @@ -428,7 +519,7 @@ void LLFloaterChangeItemThumbnail::onUploadSnapshot(void *userdata) else { LLSD key; - key["item_id"] = self->mItemId; + key["item_id"] = *self->mItemList.begin(); key["task_id"] = self->mTaskId; LLFloaterSimpleSnapshot* snapshot_floater = (LLFloaterSimpleSnapshot*)LLFloaterReg::showInstance("simple_snapshot", key, true); if (snapshot_floater) @@ -436,6 +527,14 @@ void LLFloaterChangeItemThumbnail::onUploadSnapshot(void *userdata) self->addDependentFloater(snapshot_floater); self->mSnapshotHandle = snapshot_floater->getHandle(); snapshot_floater->setOwner(self); + LLUUID task_id = self->mTaskId; + uuid_set_t inventory_ids = self->mItemList; + LLHandle<LLFloater> handle = self->getHandle(); + snapshot_floater->setComplectionCallback( + [inventory_ids, task_id, handle](const LLUUID& asset_id) + { + onUploadComplete(asset_id, task_id, inventory_ids, handle); + }); } } @@ -532,12 +631,12 @@ void LLFloaterChangeItemThumbnail::onRemove(void *userdata) LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata; LLSD payload; - payload["item_id"] = self->mItemId; + payload["item_id"] = *self->mItemList.begin(); payload["object_id"] = self->mTaskId; LLNotificationsUtil::add("DeleteThumbnail", LLSD(), payload, boost::bind(&LLFloaterChangeItemThumbnail::onRemovalConfirmation, _1, _2, self->getHandle())); } -// static +// static void LLFloaterChangeItemThumbnail::onRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFloater> handle) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -551,7 +650,8 @@ void LLFloaterChangeItemThumbnail::onRemovalConfirmation(const LLSD& notificatio struct ImageLoadedData { LLUUID mThumbnailId; - LLUUID mObjectId; + LLUUID mTaskId; + uuid_set_t mItemIds; LLHandle<LLFloater> mFloaterHandle; bool mSilent; // Keep image reference to prevent deletion on timeout @@ -581,7 +681,8 @@ void LLFloaterChangeItemThumbnail::assignAndValidateAsset(const LLUUID &asset_id mExpectingAssetId = asset_id; } ImageLoadedData *data = new ImageLoadedData(); - data->mObjectId = mItemId; + data->mTaskId = mTaskId; + data->mItemIds = mItemList; data->mThumbnailId = asset_id; data->mFloaterHandle = getHandle(); data->mSilent = silent; @@ -589,11 +690,11 @@ void LLFloaterChangeItemThumbnail::assignAndValidateAsset(const LLUUID &asset_id texturep->setLoadedCallback(onImageDataLoaded, MAX_DISCARD_LEVEL, // Don't need full image, just size data - FALSE, - FALSE, + false, + false, (void*)data, NULL, - FALSE); + false); } else { @@ -647,12 +748,12 @@ bool LLFloaterChangeItemThumbnail::validateAsset(const LLUUID &asset_id) //static void LLFloaterChangeItemThumbnail::onImageDataLoaded( - BOOL success, + bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, - BOOL final, + bool final, void* userdata) { if (!userdata) return; @@ -663,10 +764,13 @@ void LLFloaterChangeItemThumbnail::onImageDataLoaded( if (success) { - // Update the item, set it even if floater is dead + // Update items, set thumnails even if floater is dead if (validateAsset(data->mThumbnailId)) { - setThumbnailId(data->mThumbnailId, data->mObjectId); + for (const LLUUID& id : data->mItemIds) + { + setThumbnailId(data->mThumbnailId, data->mTaskId, id); + } } else if (!data->mSilent) { @@ -690,12 +794,12 @@ void LLFloaterChangeItemThumbnail::onImageDataLoaded( //static void LLFloaterChangeItemThumbnail::onFullImageLoaded( - BOOL success, + bool success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, - BOOL final, + bool final, void* userdata) { if (!userdata) return; @@ -716,11 +820,23 @@ void LLFloaterChangeItemThumbnail::onFullImageLoaded( } else if (src_vi->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX) { - LLFloaterSimpleSnapshot::uploadThumbnail(src, data->mObjectId, LLUUID::null); + LLUUID task_id = data->mTaskId; + uuid_set_t inventory_ids = data->mItemIds; + LLHandle<LLFloater> handle = data->mFloaterHandle; + LLFloaterSimpleSnapshot::uploadThumbnail(src, + *data->mItemIds.begin(), + task_id, + [inventory_ids, task_id, handle](const LLUUID& asset_id) + { + onUploadComplete(asset_id, task_id, inventory_ids, handle); + }); } else { - setThumbnailId(data->mThumbnailId, data->mObjectId); + for (const LLUUID& id : data->mItemIds) + { + setThumbnailId(data->mThumbnailId, data->mTaskId, id); + } } } @@ -745,12 +861,12 @@ void LLFloaterChangeItemThumbnail::showTexturePicker(const LLUUID &thumbnail_id) thumbnail_id, thumbnail_id, thumbnail_id, - FALSE, - TRUE, + false, + true, "SELECT PHOTO", PERM_NONE, PERM_NONE, - FALSE, + false, NULL, PICK_TEXTURE); @@ -770,8 +886,8 @@ void LLFloaterChangeItemThumbnail::showTexturePicker(const LLUUID &thumbnail_id) } ); - texture_floaterp->setLocalTextureEnabled(FALSE); - texture_floaterp->setBakeTextureEnabled(FALSE); + texture_floaterp->setLocalTextureEnabled(false); + texture_floaterp->setBakeTextureEnabled(false); texture_floaterp->setCanApplyImmediately(false); texture_floaterp->setCanApply(false, true, false /*Hide 'preview disabled'*/); texture_floaterp->setMinDimentionsLimits(LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN); @@ -781,7 +897,7 @@ void LLFloaterChangeItemThumbnail::showTexturePicker(const LLUUID &thumbnail_id) floaterp->openFloater(); } - floaterp->setFocus(TRUE); + floaterp->setFocus(true); } void LLFloaterChangeItemThumbnail::onTexturePickerCommit() @@ -838,19 +954,34 @@ void LLFloaterChangeItemThumbnail::onTexturePickerCommit() && (texturep->getCachedRawImageLevel() == 0 || texturep->getRawImageLevel() == 0) && (texturep->isCachedRawImageReady() || texturep->isRawImageValid())) { + LLUUID task_id = mTaskId; + uuid_set_t inventory_ids = mItemList; + LLHandle<LLFloater> handle = getHandle(); + LLFloaterSimpleSnapshot::completion_t callback = + [inventory_ids, task_id, handle](const LLUUID& asset_id) + { + onUploadComplete(asset_id, task_id, inventory_ids, handle); + }; if (texturep->isRawImageValid()) { - LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getRawImage(), mItemId, mTaskId); + LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getRawImage(), + *mItemList.begin(), + mTaskId, + callback); } else { - LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getCachedRawImage(), mItemId, mTaskId); + LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getCachedRawImage(), + *mItemList.begin(), + mTaskId, + callback); } } else { ImageLoadedData* data = new ImageLoadedData(); - data->mObjectId = mItemId; + data->mTaskId = mTaskId; + data->mItemIds = mItemList; data->mThumbnailId = asset_id; data->mFloaterHandle = getHandle(); data->mSilent = false; @@ -860,11 +991,11 @@ void LLFloaterChangeItemThumbnail::onTexturePickerCommit() texturep->setMinDiscardLevel(0); texturep->setLoadedCallback(onFullImageLoaded, 0, // Need best quality - TRUE, - FALSE, + true, + false, (void*)data, NULL, - FALSE); + false); texturep->forceToSaveRawImage(0); } return; @@ -874,6 +1005,41 @@ void LLFloaterChangeItemThumbnail::onTexturePickerCommit() } } +//static +void LLFloaterChangeItemThumbnail::onUploadComplete(const LLUUID& asset_id, + const LLUUID& task_id, + const uuid_set_t& inventory_ids, + LLHandle<LLFloater> handle) +{ + if (asset_id.isNull()) + { + // failure + return; + } + uuid_set_t::iterator iter = inventory_ids.begin(); + uuid_set_t::iterator end = inventory_ids.end(); + if (iter == end) + { + LL_WARNS() << "Received empty item list!" << LL_ENDL; + } + else + { + iter++; // first element was set by upload + for (; iter != end; iter++) + { + setThumbnailId(asset_id, task_id, *iter); + } + } + if (!handle.isDead()) + { + LLFloaterChangeItemThumbnail* floater = (LLFloaterChangeItemThumbnail*)handle.get(); + if (floater) + { + floater->mMultipleThumbnails = false; + floater->mMultipleTextBox->setVisible(false); + } + } +} void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID &new_thumbnail_id) { @@ -889,20 +1055,28 @@ void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID &new_thumbnail_id return; } - setThumbnailId(new_thumbnail_id, mItemId, obj); + for (const LLUUID &id : mItemList) + { + setThumbnailId(new_thumbnail_id, id, obj); + } } -void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id) +void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& task_id, const LLUUID& inv_obj_id) { - LLInventoryObject* obj = gInventory.getObject(object_id); + if (task_id.notNull()) + { + LL_WARNS() << "Not supported" << LL_ENDL; + return; + } + LLInventoryObject* obj = gInventory.getObject(inv_obj_id); if (!obj) { return; } - setThumbnailId(new_thumbnail_id, object_id, obj); + setThumbnailId(new_thumbnail_id, inv_obj_id, obj); } -void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id, LLInventoryObject* obj) +void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& inv_obj_id, LLInventoryObject* obj) { if (obj->getThumbnailUUID() != new_thumbnail_id) { @@ -920,12 +1094,12 @@ void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id LLViewerInventoryCategory* view_folder = dynamic_cast<LLViewerInventoryCategory*>(obj); if (view_folder) { - update_inventory_category(object_id, updates, NULL); + update_inventory_category(inv_obj_id, updates, NULL); } LLViewerInventoryItem* view_item = dynamic_cast<LLViewerInventoryItem*>(obj); if (view_item) { - update_inventory_item(object_id, updates, NULL); + update_inventory_item(inv_obj_id, updates, NULL); } } } |