summaryrefslogtreecommitdiff
path: root/indra/newview/llfloaterchangeitemthumbnail.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llfloaterchangeitemthumbnail.cpp')
-rw-r--r--indra/newview/llfloaterchangeitemthumbnail.cpp956
1 files changed, 956 insertions, 0 deletions
diff --git a/indra/newview/llfloaterchangeitemthumbnail.cpp b/indra/newview/llfloaterchangeitemthumbnail.cpp
new file mode 100644
index 0000000000..780130039b
--- /dev/null
+++ b/indra/newview/llfloaterchangeitemthumbnail.cpp
@@ -0,0 +1,956 @@
+/**
+ * @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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterchangeitemthumbnail.h"
+
+#include "llbutton.h"
+#include "llclipboard.h"
+#include "lliconctrl.h"
+#include "llinventoryfunctions.h"
+#include "llinventoryicon.h"
+#include "llinventorymodel.h"
+#include "llinventoryobserver.h"
+#include "llfloaterreg.h"
+#include "llfloatersimplesnapshot.h"
+#include "lllineeditor.h"
+#include "llnotificationsutil.h"
+#include "lltextbox.h"
+#include "lltexturectrl.h"
+#include "llthumbnailctrl.h"
+#include "llviewerfoldertype.h"
+#include "llviewermenufile.h"
+#include "llviewerobjectlist.h"
+#include "llviewertexturelist.h"
+#include "llwindow.h"
+
+
+class LLThumbnailImagePicker : public LLFilePickerThread
+{
+public:
+ LLThumbnailImagePicker(const LLUUID &item_id);
+ LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id);
+ ~LLThumbnailImagePicker();
+ void notify(const std::vector<std::string>& filenames) override;
+
+private:
+ LLUUID mInventoryId;
+ LLUUID mTaskId;
+};
+
+LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id)
+ : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE)
+ , mInventoryId(item_id)
+{
+}
+
+LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id)
+ : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE)
+ , mInventoryId(item_id)
+ , mTaskId(task_id)
+{
+}
+
+LLThumbnailImagePicker::~LLThumbnailImagePicker()
+{
+}
+
+void LLThumbnailImagePicker::notify(const std::vector<std::string>& filenames)
+{
+ if (filenames.empty())
+ {
+ return;
+ }
+ std::string file_path = filenames[0];
+ if (file_path.empty())
+ {
+ return;
+ }
+
+ LLFloaterSimpleSnapshot::uploadThumbnail(file_path, mInventoryId, mTaskId);
+}
+
+LLFloaterChangeItemThumbnail::LLFloaterChangeItemThumbnail(const LLSD& key)
+ : LLFloater(key)
+ , mObserverInitialized(false)
+ , mTooltipState(TOOLTIP_NONE)
+{
+}
+
+LLFloaterChangeItemThumbnail::~LLFloaterChangeItemThumbnail()
+{
+ gInventory.removeObserver(this);
+ removeVOInventoryListener();
+}
+
+BOOL LLFloaterChangeItemThumbnail::postBuild()
+{
+ mItemNameText = getChild<LLUICtrl>("item_name");
+ mItemTypeIcon = getChild<LLIconCtrl>("item_type_icon");
+ mThumbnailCtrl = getChild<LLThumbnailCtrl>("item_thumbnail");
+ mToolTipTextBox = getChild<LLTextBox>("tooltip_text");
+
+ LLSD tooltip_text;
+ mToolTipTextBox->setValue(tooltip_text);
+
+ LLButton *upload_local = getChild<LLButton>("upload_local");
+ upload_local->setClickedCallback(onUploadLocal, (void*)this);
+ upload_local->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_UPLOAD_LOCAL));
+ upload_local->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_UPLOAD_LOCAL));
+
+ LLButton *upload_snapshot = getChild<LLButton>("upload_snapshot");
+ upload_snapshot->setClickedCallback(onUploadSnapshot, (void*)this);
+ upload_snapshot->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_UPLOAD_SNAPSHOT));
+ upload_snapshot->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_UPLOAD_SNAPSHOT));
+
+ LLButton *use_texture = getChild<LLButton>("use_texture");
+ use_texture->setClickedCallback(onUseTexture, (void*)this);
+ use_texture->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_USE_TEXTURE));
+ use_texture->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_USE_TEXTURE));
+
+ mCopyToClipboardBtn = getChild<LLButton>("copy_to_clipboard");
+ mCopyToClipboardBtn->setClickedCallback(onCopyToClipboard, (void*)this);
+ mCopyToClipboardBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_COPY_TO_CLIPBOARD));
+ mCopyToClipboardBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_COPY_TO_CLIPBOARD));
+
+ mPasteFromClipboardBtn = getChild<LLButton>("paste_from_clipboard");
+ mPasteFromClipboardBtn->setClickedCallback(onPasteFromClipboard, (void*)this);
+ mPasteFromClipboardBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_COPY_FROM_CLIPBOARD));
+ mPasteFromClipboardBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_COPY_FROM_CLIPBOARD));
+
+ mRemoveImageBtn = getChild<LLButton>("remove_image");
+ mRemoveImageBtn->setClickedCallback(onRemove, (void*)this);
+ mRemoveImageBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_REMOVE));
+ mRemoveImageBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_REMOVE));
+
+ return LLFloater::postBuild();
+}
+
+void LLFloaterChangeItemThumbnail::onOpen(const LLSD& key)
+{
+ if (!key.has("item_id") && !key.isUUID())
+ {
+ closeFloater();
+ }
+
+ if (key.isUUID())
+ {
+ mItemId = key.asUUID();
+ }
+ else
+ {
+ mItemId = key["item_id"].asUUID();
+ mTaskId = key["task_id"].asUUID();
+ }
+
+ refreshFromInventory();
+}
+
+void LLFloaterChangeItemThumbnail::onFocusReceived()
+{
+ mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
+}
+
+void LLFloaterChangeItemThumbnail::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
+}
+
+BOOL LLFloaterChangeItemThumbnail::handleDragAndDrop(
+ S32 x,
+ S32 y,
+ MASK mask,
+ BOOL drop,
+ EDragAndDropType cargo_type,
+ void *cargo_data,
+ EAcceptance *accept,
+ std::string& tooltip_msg)
+{
+ if (cargo_type == DAD_TEXTURE)
+ {
+ LLInventoryItem *item = (LLInventoryItem *)cargo_data;
+ if (item->getAssetUUID().notNull())
+ {
+ if (drop)
+ {
+ assignAndValidateAsset(item->getAssetUUID());
+ }
+
+ *accept = ACCEPT_YES_SINGLE;
+ }
+ else
+ {
+ *accept = ACCEPT_NO;
+ }
+ }
+ else
+ {
+ *accept = ACCEPT_NO;
+ }
+
+ LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFloaterChangeItemThumbnail " << getKey() << LL_ENDL;
+
+ return TRUE;
+}
+
+void LLFloaterChangeItemThumbnail::changed(U32 mask)
+{
+ //LLInventoryObserver
+
+ if (mTaskId.notNull() || mItemId.isNull())
+ {
+ // Task inventory or not set up yet
+ return;
+ }
+
+ const std::set<LLUUID>& mChangedItemIDs = gInventory.getChangedIDs();
+ std::set<LLUUID>::const_iterator it;
+
+ 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)
+ {
+ // if there's a change we're interested in.
+ if ((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
+ {
+ refreshFromInventory();
+ }
+ }
+ }
+}
+
+void LLFloaterChangeItemThumbnail::inventoryChanged(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void* user_data)
+{
+ //LLVOInventoryListener
+ refreshFromInventory();
+}
+
+LLInventoryObject* LLFloaterChangeItemThumbnail::getInventoryObject()
+{
+ LLInventoryObject* obj = NULL;
+ if (mTaskId.isNull())
+ {
+ // it is in agent inventory
+ if (!mObserverInitialized)
+ {
+ gInventory.addObserver(this);
+ mObserverInitialized = true;
+ }
+
+ obj = gInventory.getObject(mItemId);
+ }
+ else
+ {
+ LLViewerObject* object = gObjectList.findObject(mTaskId);
+ if (object)
+ {
+ if (!mObserverInitialized)
+ {
+ registerVOInventoryListener(object, NULL);
+ mObserverInitialized = false;
+ }
+
+ obj = object->getInventoryObject(mItemId);
+ }
+ }
+ return obj;
+}
+
+void LLFloaterChangeItemThumbnail::refreshFromInventory()
+{
+ LLInventoryObject* obj = getInventoryObject();
+ if (!obj)
+ {
+ closeFloater();
+ }
+
+ if (obj)
+ {
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ bool in_trash = gInventory.isObjectDescendentOf(obj->getUUID(), trash_id);
+ if (in_trash && obj->getUUID() != trash_id)
+ {
+ // Close properties when moving to trash
+ // Aren't supposed to view properties from trash
+ closeFloater();
+ }
+ else
+ {
+ refreshFromObject(obj);
+ }
+ }
+ else
+ {
+ closeFloater();
+ }
+}
+
+class LLIsOutfitTextureType : public LLInventoryCollectFunctor
+{
+public:
+ LLIsOutfitTextureType() {}
+ virtual ~LLIsOutfitTextureType() {}
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+};
+
+bool LLIsOutfitTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ return item && (item->getType() == LLAssetType::AT_TEXTURE);
+}
+
+void LLFloaterChangeItemThumbnail::refreshFromObject(LLInventoryObject* obj)
+{
+ LLUIImagePtr icon_img;
+ LLUUID thumbnail_id = obj->getThumbnailUUID();
+
+ LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(obj);
+ if (item)
+ {
+ setTitle(getString("title_item_thumbnail"));
+
+ 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
+ {
+ LLViewerInventoryCategory* cat = dynamic_cast<LLViewerInventoryCategory*>(obj);
+
+ if (cat)
+ {
+ setTitle(getString("title_folder_thumbnail"));
+ icon_img = LLUI::getUIImage(LLViewerFolderType::lookupIconName(cat->getPreferredType(), true));
+
+ if (thumbnail_id.isNull() && (cat->getPreferredType() == LLFolderType::FT_OUTFIT))
+ {
+ // Legacy support, check if there is an image inside
+
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ // Not LLIsOfAssetType, because we allow links
+ LLIsOutfitTextureType f;
+ gInventory.getDirectDescendentsOf(mItemId, cats, items, f);
+
+ if (1 == items.size())
+ {
+ LLViewerInventoryItem* item = items.front();
+ if (item && item->getIsLinkType())
+ {
+ item = item->getLinkedItem();
+ }
+ if (item)
+ {
+ thumbnail_id = item->getAssetUUID();
+ if (thumbnail_id.notNull())
+ {
+ // per SL-19188, set this image as a thumbnail
+ LL_INFOS() << "Setting image " << thumbnail_id
+ << " from outfit as a thumbnail for inventory object " << obj->getUUID()
+ << LL_ENDL;
+ assignAndValidateAsset(thumbnail_id, true);
+ }
+ }
+ }
+ }
+
+ mRemoveImageBtn->setEnabled(thumbnail_id.notNull());
+ }
+ }
+ mItemTypeIcon->setImage(icon_img);
+ mItemNameText->setValue(obj->getName());
+
+ mThumbnailCtrl->setValue(thumbnail_id);
+
+ mCopyToClipboardBtn->setEnabled(thumbnail_id.notNull());
+ mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
+
+ // todo: some elements might not support setting thumbnails
+ // since they already have them
+ // It is unclear how system folders should function
+}
+
+void LLFloaterChangeItemThumbnail::onUploadLocal(void *userdata)
+{
+ LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+
+ (new LLThumbnailImagePicker(self->mItemId, self->mTaskId))->getFile();
+
+ LLFloater* floaterp = self->mPickerHandle.get();
+ if (floaterp)
+ {
+ floaterp->closeFloater();
+ }
+ floaterp = self->mSnapshotHandle.get();
+ if (floaterp)
+ {
+ floaterp->closeFloater();
+ }
+}
+
+void LLFloaterChangeItemThumbnail::onUploadSnapshot(void *userdata)
+{
+ LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+
+ LLFloater* floaterp = self->mSnapshotHandle.get();
+ // Show the dialog
+ if (floaterp)
+ {
+ floaterp->openFloater();
+ }
+ else
+ {
+ LLSD key;
+ key["item_id"] = self->mItemId;
+ key["task_id"] = self->mTaskId;
+ LLFloaterSimpleSnapshot* snapshot_floater = (LLFloaterSimpleSnapshot*)LLFloaterReg::showInstance("simple_snapshot", key, true);
+ if (snapshot_floater)
+ {
+ self->addDependentFloater(snapshot_floater);
+ self->mSnapshotHandle = snapshot_floater->getHandle();
+ snapshot_floater->setOwner(self);
+ }
+ }
+
+ floaterp = self->mPickerHandle.get();
+ if (floaterp)
+ {
+ floaterp->closeFloater();
+ }
+}
+
+void LLFloaterChangeItemThumbnail::onUseTexture(void *userdata)
+{
+ LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+ LLInventoryObject* obj = self->getInventoryObject();
+ if (obj)
+ {
+ self->showTexturePicker(obj->getThumbnailUUID());
+ }
+
+ LLFloater* floaterp = self->mSnapshotHandle.get();
+ if (floaterp)
+ {
+ floaterp->closeFloater();
+ }
+}
+
+void LLFloaterChangeItemThumbnail::onCopyToClipboard(void *userdata)
+{
+ LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+ LLInventoryObject* obj = self->getInventoryObject();
+ if (obj)
+ {
+ LLClipboard::instance().reset();
+ LLClipboard::instance().addToClipboard(obj->getThumbnailUUID(), LLAssetType::AT_NONE);
+ self->mPasteFromClipboardBtn->setEnabled(true);
+ }
+}
+
+void LLFloaterChangeItemThumbnail::onPasteFromClipboard(void *userdata)
+{
+ LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+ std::vector<LLUUID> objects;
+ LLClipboard::instance().pasteFromClipboard(objects);
+ if (objects.size() > 0)
+ {
+ LLUUID potential_uuid = objects[0];
+ LLUUID asset_id;
+
+ if (potential_uuid.notNull())
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(potential_uuid);
+ if (item)
+ {
+ // no point checking snapshot?
+ if (item->getType() == LLAssetType::AT_TEXTURE)
+ {
+ bool copy = item->getPermissions().allowCopyBy(gAgent.getID());
+ bool xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID());
+
+ if (copy && xfer)
+ {
+ asset_id = item->getAssetUUID();
+ }
+ else
+ {
+ LLNotificationsUtil::add("ThumbnailInsufficientPermissions");
+ return;
+ }
+ }
+ }
+ else
+ {
+ // assume that this is a texture
+ asset_id = potential_uuid;
+ }
+ }
+
+ LLInventoryObject* obj = self->getInventoryObject();
+ if (obj && obj->getThumbnailUUID() == asset_id)
+ {
+ // nothing to do
+ return;
+ }
+ if (asset_id.notNull())
+ {
+ self->assignAndValidateAsset(asset_id);
+ }
+ // else show 'buffer has no texture' warning?
+ }
+}
+
+void LLFloaterChangeItemThumbnail::onRemove(void *userdata)
+{
+ LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
+
+ LLSD payload;
+ payload["item_id"] = self->mItemId;
+ payload["object_id"] = self->mTaskId;
+ LLNotificationsUtil::add("DeleteThumbnail", LLSD(), payload, boost::bind(&LLFloaterChangeItemThumbnail::onRemovalConfirmation, _1, _2, self->getHandle()));
+}
+
+// static
+void LLFloaterChangeItemThumbnail::onRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFloater> handle)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0 && !handle.isDead() && !handle.get()->isDead())
+ {
+ LLFloaterChangeItemThumbnail* self = (LLFloaterChangeItemThumbnail*)handle.get();
+ self->setThumbnailId(LLUUID::null);
+ }
+}
+
+struct ImageLoadedData
+{
+ LLUUID mThumbnailId;
+ LLUUID mObjectId;
+ LLHandle<LLFloater> mFloaterHandle;
+ bool mSilent;
+ // Keep image reference to prevent deletion on timeout
+ LLPointer<LLViewerFetchedTexture> mTexturep;
+};
+
+void LLFloaterChangeItemThumbnail::assignAndValidateAsset(const LLUUID &asset_id, bool silent)
+{
+ LLPointer<LLViewerFetchedTexture> texturep = LLViewerTextureManager::getFetchedTexture(asset_id);
+ if (texturep->isMissingAsset())
+ {
+ LL_WARNS() << "Attempted to assign missing asset " << asset_id << LL_ENDL;
+ if (!silent)
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ }
+ }
+ else if (texturep->getFullWidth() == 0)
+ {
+ if (silent)
+ {
+ mExpectingAssetId = LLUUID::null;
+ }
+ else
+ {
+ // don't warn user multiple times if some textures took their time
+ mExpectingAssetId = asset_id;
+ }
+ ImageLoadedData *data = new ImageLoadedData();
+ data->mObjectId = mItemId;
+ data->mThumbnailId = asset_id;
+ data->mFloaterHandle = getHandle();
+ data->mSilent = silent;
+ data->mTexturep = texturep;
+
+ texturep->setLoadedCallback(onImageDataLoaded,
+ MAX_DISCARD_LEVEL, // Don't need full image, just size data
+ FALSE,
+ FALSE,
+ (void*)data,
+ NULL,
+ FALSE);
+ }
+ else
+ {
+ if (validateAsset(asset_id))
+ {
+ setThumbnailId(asset_id);
+ }
+ else if (!silent)
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ }
+ }
+}
+bool LLFloaterChangeItemThumbnail::validateAsset(const LLUUID &asset_id)
+{
+ if (asset_id.isNull())
+ {
+ return false;
+ }
+
+ LLPointer<LLViewerFetchedTexture> texturep = LLViewerTextureManager::findFetchedTexture(asset_id, TEX_LIST_STANDARD);
+
+ if (!texturep)
+ {
+ return false;
+ }
+
+ if (texturep->isMissingAsset())
+ {
+ return false;
+ }
+
+ if (texturep->getFullWidth() != texturep->getFullHeight())
+ {
+ return false;
+ }
+
+ if (texturep->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX
+ || texturep->getFullHeight() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX)
+ {
+ return false;
+ }
+
+ if (texturep->getFullWidth() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN
+ || texturep->getFullHeight() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN)
+ {
+ return false;
+ }
+ return true;
+}
+
+//static
+void LLFloaterChangeItemThumbnail::onImageDataLoaded(
+ BOOL success,
+ LLViewerFetchedTexture *src_vi,
+ LLImageRaw* src,
+ LLImageRaw* aux_src,
+ S32 discard_level,
+ BOOL final,
+ void* userdata)
+{
+ if (!userdata) return;
+
+ if (!final && success) return; //not done yet
+
+ ImageLoadedData* data = (ImageLoadedData*)userdata;
+
+ if (success)
+ {
+ // Update the item, set it even if floater is dead
+ if (validateAsset(data->mThumbnailId))
+ {
+ setThumbnailId(data->mThumbnailId, data->mObjectId);
+ }
+ else if (!data->mSilent)
+ {
+ // Should this only appear if floater is alive?
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ }
+ }
+
+ // Update floater
+ if (!data->mSilent && !data->mFloaterHandle.isDead())
+ {
+ LLFloaterChangeItemThumbnail* self = static_cast<LLFloaterChangeItemThumbnail*>(data->mFloaterHandle.get());
+ if (self && self->mExpectingAssetId == data->mThumbnailId)
+ {
+ self->mExpectingAssetId = LLUUID::null;
+ }
+ }
+
+ delete data;
+}
+
+//static
+void LLFloaterChangeItemThumbnail::onFullImageLoaded(
+ BOOL success,
+ LLViewerFetchedTexture* src_vi,
+ LLImageRaw* src,
+ LLImageRaw* aux_src,
+ S32 discard_level,
+ BOOL final,
+ void* userdata)
+{
+ if (!userdata) return;
+
+ if (!final && success) return; //not done yet
+
+ ImageLoadedData* data = (ImageLoadedData*)userdata;
+
+ if (success)
+ {
+ if (src_vi->getFullWidth() != src_vi->getFullHeight()
+ || src_vi->getFullWidth() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN)
+ {
+ if (!data->mSilent)
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ }
+ }
+ else if (src_vi->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX)
+ {
+ LLFloaterSimpleSnapshot::uploadThumbnail(src, data->mObjectId, LLUUID::null);
+ }
+ else
+ {
+ setThumbnailId(data->mThumbnailId, data->mObjectId);
+ }
+ }
+
+ delete data;
+}
+
+void LLFloaterChangeItemThumbnail::showTexturePicker(const LLUUID &thumbnail_id)
+{
+ // show hourglass cursor when loading inventory window
+ getWindow()->setCursor(UI_CURSOR_WAIT);
+
+ LLFloater* floaterp = mPickerHandle.get();
+ // Show the dialog
+ if (floaterp)
+ {
+ floaterp->openFloater();
+ }
+ else
+ {
+ floaterp = new LLFloaterTexturePicker(
+ this,
+ thumbnail_id,
+ thumbnail_id,
+ thumbnail_id,
+ FALSE,
+ TRUE,
+ "SELECT PHOTO",
+ PERM_NONE,
+ PERM_NONE,
+ PERM_NONE,
+ FALSE,
+ NULL);
+
+ mPickerHandle = floaterp->getHandle();
+
+ LLFloaterTexturePicker* texture_floaterp = dynamic_cast<LLFloaterTexturePicker*>(floaterp);
+ if (texture_floaterp)
+ {
+ //texture_floaterp->setTextureSelectedCallback();
+ //texture_floaterp->setOnUpdateImageStatsCallback();
+ texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLPickerSource, const LLUUID&, const LLUUID&)
+ {
+ if (op == LLTextureCtrl::TEXTURE_SELECT)
+ {
+ onTexturePickerCommit();
+ }
+ }
+ );
+
+ 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);
+
+ addDependentFloater(texture_floaterp);
+ }
+
+ floaterp->openFloater();
+ }
+ floaterp->setFocus(TRUE);
+}
+
+void LLFloaterChangeItemThumbnail::onTexturePickerCommit()
+{
+ LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mPickerHandle.get();
+
+ if (floaterp)
+ {
+ LLUUID asset_id = floaterp->getAssetID();
+
+ if (asset_id.isNull())
+ {
+ setThumbnailId(asset_id);
+ return;
+ }
+
+ LLInventoryObject* obj = getInventoryObject();
+ if (obj && obj->getThumbnailUUID() == asset_id)
+ {
+ // nothing to do
+ return;
+ }
+
+ LLPointer<LLViewerFetchedTexture> texturep = LLViewerTextureManager::findFetchedTexture(asset_id, TEX_LIST_STANDARD);
+ if (!texturep)
+ {
+ LL_WARNS() << "Image " << asset_id << " doesn't exist" << LL_ENDL;
+ return;
+ }
+
+ if (texturep->isMissingAsset())
+ {
+ LL_WARNS() << "Image " << asset_id << " is missing" << LL_ENDL;
+ return;
+ }
+
+ if (texturep->getFullWidth() != texturep->getFullHeight())
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ return;
+ }
+
+ if (texturep->getFullWidth() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN
+ && texturep->getFullWidth() > 0)
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ return;
+ }
+
+ if (texturep->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX
+ || texturep->getFullWidth() == 0)
+ {
+ if (texturep->isFullyLoaded()
+ && (texturep->getCachedRawImageLevel() == 0 || texturep->getRawImageLevel() == 0)
+ && (texturep->isCachedRawImageReady() || texturep->isRawImageValid()))
+ {
+ if (texturep->isRawImageValid())
+ {
+ LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getRawImage(), mItemId, mTaskId);
+ }
+ else
+ {
+ LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getCachedRawImage(), mItemId, mTaskId);
+ }
+ }
+ else
+ {
+ ImageLoadedData* data = new ImageLoadedData();
+ data->mObjectId = mItemId;
+ data->mThumbnailId = asset_id;
+ data->mFloaterHandle = getHandle();
+ data->mSilent = false;
+ data->mTexturep = texturep;
+
+ texturep->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
+ texturep->setMinDiscardLevel(0);
+ texturep->setLoadedCallback(onFullImageLoaded,
+ 0, // Need best quality
+ TRUE,
+ FALSE,
+ (void*)data,
+ NULL,
+ FALSE);
+ texturep->forceToSaveRawImage(0);
+ }
+ return;
+ }
+
+ setThumbnailId(asset_id);
+ }
+}
+
+
+void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID &new_thumbnail_id)
+{
+ LLInventoryObject* obj = getInventoryObject();
+ if (!obj)
+ {
+ return;
+ }
+
+ if (mTaskId.notNull())
+ {
+ LL_ERRS() << "Not implemented yet" << LL_ENDL;
+ return;
+ }
+
+ setThumbnailId(new_thumbnail_id, mItemId, obj);
+}
+
+void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id)
+{
+ LLInventoryObject* obj = gInventory.getObject(object_id);
+ if (!obj)
+ {
+ return;
+ }
+
+ setThumbnailId(new_thumbnail_id, object_id, obj);
+}
+void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id, LLInventoryObject* obj)
+{
+ if (obj->getThumbnailUUID() != new_thumbnail_id)
+ {
+ LLSD updates;
+ if (new_thumbnail_id.notNull())
+ {
+ // At the moment server expects id as a string
+ updates["thumbnail"] = LLSD().with("asset_id", new_thumbnail_id.asString());
+ }
+ else
+ {
+ // No thumbnail isntead of 'null id thumbnail'
+ updates["thumbnail"] = LLSD();
+ }
+ LLViewerInventoryCategory* view_folder = dynamic_cast<LLViewerInventoryCategory*>(obj);
+ if (view_folder)
+ {
+ update_inventory_category(object_id, updates, NULL);
+ }
+ LLViewerInventoryItem* view_item = dynamic_cast<LLViewerInventoryItem*>(obj);
+ if (view_item)
+ {
+ update_inventory_item(object_id, updates, NULL);
+ }
+ }
+}
+
+void LLFloaterChangeItemThumbnail::onButtonMouseEnter(LLUICtrl* button, const LLSD& param, EToolTipState state)
+{
+ mTooltipState = state;
+
+ std::string tooltip_text;
+ std::string tooltip_name = "tooltip_" + button->getName();
+ if (hasString(tooltip_name))
+ {
+ tooltip_text = getString(tooltip_name);
+ }
+
+ mToolTipTextBox->setValue(tooltip_text);
+}
+
+void LLFloaterChangeItemThumbnail::onButtonMouseLeave(LLUICtrl* button, const LLSD& param, EToolTipState state)
+{
+ if (mTooltipState == state)
+ {
+ mTooltipState = TOOLTIP_NONE;
+ LLSD tooltip_text;
+ mToolTipTextBox->setValue(tooltip_text);
+ }
+}
+