diff options
7 files changed, 383 insertions, 181 deletions
diff --git a/indra/newview/llfloaterbulkythumbs.cpp b/indra/newview/llfloaterbulkythumbs.cpp index 9ffb71b394..02adf90acf 100644 --- a/indra/newview/llfloaterbulkythumbs.cpp +++ b/indra/newview/llfloaterbulkythumbs.cpp @@ -70,6 +70,10 @@ BOOL LLFloaterBulkyThumbs::postBuild()      mWriteThumbnailsBtn->setCommitCallback(boost::bind(&LLFloaterBulkyThumbs::onWriteThumbnails, this));      mWriteThumbnailsBtn->setEnabled(false); +    mDisplayThumbnaillessItemsBtn = getChild<LLUICtrl>("display_thumbless_items"); +    mDisplayThumbnaillessItemsBtn->setCommitCallback(boost::bind(&LLFloaterBulkyThumbs::onDisplayThumbnaillessItems, this)); +    mDisplayThumbnaillessItemsBtn->setEnabled(true); +      return true;  } @@ -96,6 +100,18 @@ void LLFloaterBulkyThumbs::recordInventoryItemEntry(LLViewerInventoryItem* item)      {          // dupe - do not save      } + +    if (item->getThumbnailUUID() == LLUUID::null) +    { +        mOutputLog->appendText( +            STRINGIZE( +                "ITEM " << mItemNamesIDs.size() << "> " << +                name << +                " has no thumbnail" << +                //id.asString() << +                std::endl +            ), false); +    }  }  void LLFloaterBulkyThumbs::onPasteItems() @@ -139,6 +155,13 @@ void LLFloaterBulkyThumbs::onPasteItems()                                              LLInventoryModel::EXCLUDE_TRASH,                                              is_bodypart); +            LLIsType is_clothing(LLAssetType::AT_CLOTHING); +            gInventory.collectDescendentsIf(cat->getUUID(), +                                            cat_array, +                                            item_array, +                                            LLInventoryModel::EXCLUDE_TRASH, +                                            is_clothing); +              for (size_t i = 0; i < item_array.size(); i++)              {                  LLViewerInventoryItem* item = item_array.at(i); @@ -150,7 +173,7 @@ void LLFloaterBulkyThumbs::onPasteItems()          if (item)          {              const LLAssetType::EType item_type = item->getType(); -            if (item_type == LLAssetType::AT_OBJECT || item_type == LLAssetType::AT_BODYPART) +            if (item_type == LLAssetType::AT_OBJECT || item_type == LLAssetType::AT_BODYPART || item_type == LLAssetType::AT_CLOTHING)              {                  recordInventoryItemEntry(item);              } @@ -388,3 +411,33 @@ void LLFloaterBulkyThumbs::onWriteThumbnails()      }      mOutputLog->setCursorAndScrollToEnd();  } + +void LLFloaterBulkyThumbs::onDisplayThumbnaillessItems() +{ +    //std::map<std::string, LLUUID>::iterator item_iter = mItemNamesIDs.begin(); +    //size_t index = 1; + +    //mOutputLog->appendText("======= Items with no thumbnail =======", false); + +    //while (item_iter != mItemNamesIDs.end()) +    //{ +    //    std::string item_name = (*item_iter).first; + +    //    //mOutputLog->appendText( +    //    //    STRINGIZE( +    //    //        "MATCHING ITEM (" << index++  << "/" << mItemNamesIDs.size() << ") " << item_name << "> " +    //    //    ), false); + +    //    std::map<std::string, LLUUID>::iterator texture_iter = mTextureNamesIDs.find(item_name); +    //    if (texture_iter == mTextureNamesIDs.end()) +    //    { +    //        mOutputLog->appendText( +    //            STRINGIZE( +    //                "MISSING:" << + +    //                std::endl +    //            ), false); + +    //    } +    //} +} diff --git a/indra/newview/llfloaterbulkythumbs.h b/indra/newview/llfloaterbulkythumbs.h index 75657002b3..10133553a6 100644 --- a/indra/newview/llfloaterbulkythumbs.h +++ b/indra/newview/llfloaterbulkythumbs.h @@ -57,6 +57,9 @@ class LLFloaterBulkyThumbs:          LLUICtrl* mWriteThumbnailsBtn;          void onWriteThumbnails(); +        LLUICtrl* mDisplayThumbnaillessItemsBtn; +        void onDisplayThumbnaillessItems(); +          void recordInventoryItemEntry(LLViewerInventoryItem* item);          void recordTextureItemEntry(LLViewerInventoryItem* item); diff --git a/indra/newview/llfloaterinventorythumbnailshelper.cpp b/indra/newview/llfloaterinventorythumbnailshelper.cpp index 9697fc3d51..15e1c88572 100644 --- a/indra/newview/llfloaterinventorythumbnailshelper.cpp +++ b/indra/newview/llfloaterinventorythumbnailshelper.cpp @@ -3,6 +3,9 @@   * @author Callum Prentice   * @brief LLFloaterInventoryThumbnailsHelper class implementation   * + * Usage instructions and some brief notes can be found in Confluence here: + * https://lindenlab.atlassian.net/wiki/spaces/~174746736/pages/2928672843/Inventory+Thumbnail+Helper+Tool + *    * $LicenseInfo:firstyear=2008&license=viewerlgpl$   * Second Life Viewer Source Code   * Copyright (C) 2010, Linden Research, Inc. @@ -25,23 +28,20 @@   * $/LicenseInfo$   */ -/** - * Floater that appears when buying an object, giving a preview - * of its contents and their permissions. - */ -  #include "llviewerprecompiledheaders.h" -#include "llfloaterinventorythumbnailshelper.h" -#include "lluictrlfactory.h" +#include "llaisapi.h"  #include "llclipboard.h" -#include "llinventorymodel.h"  #include "llinventoryfunctions.h" -#include "lltexteditor.h" +#include "llinventorymodel.h" +#include "llnotifications.h" +#include "llnotificationsutil.h"  #include "llscrolllistctrl.h" -#include "llmediactrl.h" +#include "lltexteditor.h" +#include "lluictrlfactory.h"  #include "lluuid.h" -#include "llaisapi.h" + +#include "llfloaterinventorythumbnailshelper.h"  LLFloaterInventoryThumbnailsHelper::LLFloaterInventoryThumbnailsHelper(const LLSD& key)      :   LLFloater("floater_inventory_thumbnails_helper") @@ -54,66 +54,53 @@ LLFloaterInventoryThumbnailsHelper::~LLFloaterInventoryThumbnailsHelper()  BOOL LLFloaterInventoryThumbnailsHelper::postBuild()  { -    mPasteItemsBtn = getChild<LLUICtrl>("paste_items_btn"); -    mPasteItemsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onPasteItems, this)); - -    mPasteTexturesBtn = getChild<LLUICtrl>("paste_textures_btn"); -    mPasteTexturesBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onPasteTextures, this)); +    mInventoryThumbnailsList = getChild<LLScrollListCtrl>("inventory_thumbnails_list"); +    mInventoryThumbnailsList->setAllowMultipleSelection(true);      mOutputLog = getChild<LLTextEditor>("output_log");      mOutputLog->setMaxTextLength(0xffff * 0x10); -    //mMergeItemsTexturesBtn = getChild<LLUICtrl>("merge_items_textures"); -    //mMergeItemsTexturesBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onMergeItemsTextures, this)); -    //mMergeItemsTexturesBtn->setEnabled(false); +    mPasteItemsBtn = getChild<LLUICtrl>("paste_items_btn"); +    mPasteItemsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onPasteItems, this)); +    mPasteItemsBtn->setEnabled(true); -    mInventoryThumbnailsList = getChild<LLScrollListCtrl>("inventory_thumbnails_list"); -    mInventoryThumbnailsList->setAllowMultipleSelection(true); -    mInventoryThumbnailsList->deleteAllItems(); +    mPasteTexturesBtn = getChild<LLUICtrl>("paste_textures_btn"); +    mPasteTexturesBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onPasteTextures, this)); +    mPasteTexturesBtn->setEnabled(true);      mWriteThumbnailsBtn = getChild<LLUICtrl>("write_thumbnails_btn");      mWriteThumbnailsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onWriteThumbnails, this));      mWriteThumbnailsBtn->setEnabled(false); +    mLogMissingThumbnailsBtn = getChild<LLUICtrl>("log_missing_thumbnails_btn"); +    mLogMissingThumbnailsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onLogMissingThumbnails, this)); +    mLogMissingThumbnailsBtn->setEnabled(false); + +    mClearThumbnailsBtn = getChild<LLUICtrl>("clear_thumbnails_btn"); +    mClearThumbnailsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onClearThumbnails, this)); +    mClearThumbnailsBtn->setEnabled(false); +      return true;  } +// Records an entry in the pasted items - saves it to a map and writes it to the log +// window for later confirmation/validation - since it uses a map, duplicates (based on +// the name) are discarded  void LLFloaterInventoryThumbnailsHelper::recordInventoryItemEntry(LLViewerInventoryItem* item)  {      const std::string name = item->getName(); -    std::map<std::string, LLUUID>::iterator iter = mItemNamesIDs.find(name); -    if (iter == mItemNamesIDs.end()) +    std::map<std::string, LLViewerInventoryItem*>::iterator iter = mItemNamesItems.find(name); +    if (iter == mItemNamesItems.end())      { -        LLUUID id = item->getUUID(); -        mItemNamesIDs.insert({name, id}); +        mItemNamesItems.insert({name, item}); -        mOutputLog->appendText( +        writeToLog(              STRINGIZE( -                "ITEM " << mItemNamesIDs.size() << "> " << +                "ITEM " << mItemNamesItems.size() << "> " <<                  name << -                //" | " << -                //id.asString() <<                  std::endl              ), false); - -        // TODO: use this ID to get name of texture and display that -        const LLUUID current_thumbnail_id = item->getThumbnailUUID(); - -        std::string texture_display = std::string("Not Present"); -        if (!current_thumbnail_id.isNull()) -        { -            texture_display = current_thumbnail_id.asString(); -        } - -        LLSD row; -        row["columns"][0]["column"] = "name"; -        row["columns"][0]["type"] = "text"; -        row["columns"][0]["value"] = name; -        row["columns"][1]["column"] = "texture"; -        row["columns"][1]["type"] = "text"; -        row["columns"][1]["value"] = texture_display; -        mInventoryThumbnailsList->addElement(row);      }      else      { @@ -121,6 +108,10 @@ void LLFloaterInventoryThumbnailsHelper::recordInventoryItemEntry(LLViewerInvent      }  } +// Called when the user has copied items from their inventory and selects the Paste Items button +// in the UI - iterates over items and folders and saves details of each one. +// The first use of this tool is for updating NUX items and as such, only looks for OBJECTS, +// CLOTHING and BODYPARTS - later versions of this tool should make that selection editable.  void LLFloaterInventoryThumbnailsHelper::onPasteItems()  {      if (!LLClipboard::instance().hasContents()) @@ -128,7 +119,7 @@ void LLFloaterInventoryThumbnailsHelper::onPasteItems()          return;      } -    mOutputLog->appendText( +    writeToLog(          STRINGIZE(              "\n==== Pasting items from inventory ====" <<              std::endl @@ -142,6 +133,7 @@ void LLFloaterInventoryThumbnailsHelper::onPasteItems()      {          const LLUUID& entry = objects.at(i); +        // Check for a folder          const LLInventoryCategory* cat = gInventory.getCategory(entry);          if (cat)          { @@ -162,6 +154,13 @@ void LLFloaterInventoryThumbnailsHelper::onPasteItems()                                              LLInventoryModel::EXCLUDE_TRASH,                                              is_bodypart); +            LLIsType is_clothing(LLAssetType::AT_CLOTHING); +            gInventory.collectDescendentsIf(cat->getUUID(), +                                            cat_array, +                                            item_array, +                                            LLInventoryModel::EXCLUDE_TRASH, +                                            is_clothing); +              for (size_t i = 0; i < item_array.size(); i++)              {                  LLViewerInventoryItem* item = item_array.at(i); @@ -169,20 +168,28 @@ void LLFloaterInventoryThumbnailsHelper::onPasteItems()              }          } +        // Check for an item          LLViewerInventoryItem* item = gInventory.getItem(entry);          if (item)          {              const LLAssetType::EType item_type = item->getType(); -            if (item_type == LLAssetType::AT_OBJECT || item_type == LLAssetType::AT_BODYPART) +            if (item_type == LLAssetType::AT_OBJECT || item_type == LLAssetType::AT_BODYPART || item_type == LLAssetType::AT_CLOTHING)              {                  recordInventoryItemEntry(item);              }          }      } -    mOutputLog->setCursorAndScrollToEnd(); +    // update the main list view based on what we found +    updateDisplayList(); + +    // update the buttons enabled state based on what we found/saved +    updateButtonStates();  } +// Records a entry in the pasted textures - saves it to a map and writes it to the log +// window for later confirmation/validation - since it uses a map, duplicates (based on +// the name) are discarded  void LLFloaterInventoryThumbnailsHelper::recordTextureItemEntry(LLViewerInventoryItem* item)  {      const std::string name = item->getName(); @@ -193,7 +200,7 @@ void LLFloaterInventoryThumbnailsHelper::recordTextureItemEntry(LLViewerInventor          LLUUID id = item->getAssetUUID();          mTextureNamesIDs.insert({name, id}); -        mOutputLog->appendText( +        writeToLog(              STRINGIZE(                  "TEXTURE " << mTextureNamesIDs.size() << "> " <<                  name << @@ -208,6 +215,8 @@ void LLFloaterInventoryThumbnailsHelper::recordTextureItemEntry(LLViewerInventor      }  } +// Called when the user has copied textures from their inventory and selects the Paste Textures +// button in the UI - iterates over textures and folders and saves details of each one.  void LLFloaterInventoryThumbnailsHelper::onPasteTextures()  {      if (!LLClipboard::instance().hasContents()) @@ -215,7 +224,7 @@ void LLFloaterInventoryThumbnailsHelper::onPasteTextures()          return;      } -    mOutputLog->appendText( +    writeToLog(          STRINGIZE(              "\n==== Pasting textures from inventory ====" <<              std::endl @@ -260,105 +269,65 @@ void LLFloaterInventoryThumbnailsHelper::onPasteTextures()          }      } -    mOutputLog->setCursorAndScrollToEnd(); +    // update the main list view based on what we found +    updateDisplayList(); -    populateThumbnailNames(); +    // update the buttons enabled state based on what we found/saved +    updateButtonStates();  } - -void LLFloaterInventoryThumbnailsHelper::populateThumbnailNames() +// Updates the main list of entries in the UI based on what is in the maps/storage +void LLFloaterInventoryThumbnailsHelper::updateDisplayList()  { -    std::map<std::string, LLUUID>::iterator item_iter = mItemNamesIDs.begin(); +    mInventoryThumbnailsList->deleteAllItems(); -    while (item_iter != mItemNamesIDs.end()) +    std::map<std::string, LLViewerInventoryItem*>::iterator item_iter = mItemNamesItems.begin(); +    while (item_iter != mItemNamesItems.end())      {          std::string item_name = (*item_iter).first; -        std::map<std::string, LLUUID>::iterator texture_iter = mTextureNamesIDs.find(item_name); -        if (texture_iter != mTextureNamesIDs.end()) +        std::string existing_texture_name = std::string(); +        LLUUID existing_thumbnail_id = (*item_iter).second->getThumbnailUUID(); +        if (existing_thumbnail_id != LLUUID::null)          { -            const bool case_sensitive = true; -            LLScrollListItem* entry = mInventoryThumbnailsList->getItemByLabel(item_name, case_sensitive); - -            const std::string texture_name = (*texture_iter).first; -            entry->getColumn(1)->setValue(LLSD(texture_name)); +            existing_texture_name = existing_thumbnail_id.asString(); +        } +        else +        { +            existing_texture_name = "none";          } -        ++item_iter; -    } -} - -void LLFloaterInventoryThumbnailsHelper::mergeItemsTextures() -{ -    mOutputLog->appendText( -        STRINGIZE( -            "\n==== Matching items and textures for " << -            mItemNamesIDs.size() << -            " entries ====" << -            std::endl -        ), false); - -    std::map<std::string, LLUUID>::iterator item_iter = mItemNamesIDs.begin(); -    size_t index = 1; - -    while (item_iter != mItemNamesIDs.end()) -    { -        std::string item_name = (*item_iter).first; - -        mOutputLog->appendText( -            STRINGIZE( -                "MATCHING ITEM (" << index++  << "/" << mItemNamesIDs.size() << ") " << item_name << "> " -            ), false); - +        std::string new_texture_name = std::string();          std::map<std::string, LLUUID>::iterator texture_iter = mTextureNamesIDs.find(item_name);          if (texture_iter != mTextureNamesIDs.end())          { -            mOutputLog->appendText( -                STRINGIZE( -                    "MATCHED" << -                    std::endl -                ), false); - -            mNameItemIDTextureId.insert({item_name, {(*item_iter).second, (*texture_iter).second}}); +            new_texture_name = (*texture_iter).first;          }          else          { -            mOutputLog->appendText( -                STRINGIZE( -                    "NO MATCH FOUND" << -                    std::endl -                ), false); +            new_texture_name = "missing";          } -        ++item_iter; -    } +        LLSD row; +        row["columns"][EListColumnNum::NAME]["column"] = "item_name"; +        row["columns"][EListColumnNum::NAME]["type"] = "text"; +        row["columns"][EListColumnNum::NAME]["value"] = item_name; +        row["columns"][EListColumnNum::NAME]["font"]["name"] = "Monospace"; -    mOutputLog->appendText( -        STRINGIZE( -            "==== Matched list of items and textures has " << -            mNameItemIDTextureId.size() << -            " entries ====" << -            std::endl -        ), true); - -    //std::map<std::string, std::pair< LLUUID, LLUUID>>::iterator iter = mNameItemIDTextureId.begin(); -    //while (iter != mNameItemIDTextureId.end()) -    //{ -    //    std::string output_line = (*iter).first; -    //    output_line += "\n"; -    //    output_line += "item ID: "; -    //    output_line += ((*iter).second).first.asString(); -    //    output_line += "\n"; -    //    output_line += "thumbnail texture ID: "; -    //    output_line += ((*iter).second).second.asString(); -    //    output_line +=  "\n"; -    //    mOutputLog->appendText(output_line, true); - -    //    ++iter; -    //} -    mOutputLog->setCursorAndScrollToEnd(); +        row["columns"][EListColumnNum::EXISTING_TEXTURE]["column"] = "existing_texture"; +        row["columns"][EListColumnNum::EXISTING_TEXTURE]["type"] = "text"; +        row["columns"][EListColumnNum::EXISTING_TEXTURE]["font"]["name"] = "Monospace"; +        row["columns"][EListColumnNum::EXISTING_TEXTURE]["value"] = existing_texture_name; + +        row["columns"][EListColumnNum::NEW_TEXTURE]["column"] = "new_texture"; +        row["columns"][EListColumnNum::NEW_TEXTURE]["type"] = "text"; +        row["columns"][EListColumnNum::NEW_TEXTURE]["font"]["name"] = "Monospace"; +        row["columns"][EListColumnNum::NEW_TEXTURE]["value"] = new_texture_name; + +        mInventoryThumbnailsList->addElement(row); -    mWriteThumbnailsBtn->setEnabled(true); +        ++item_iter; +    }  }  #if 1 @@ -373,6 +342,9 @@ void inventoryThumbnailsHelperCb(LLPointer<LLInventoryCallback> cb, LLUUID id)  }  #endif +// Makes calls to the AIS v3 API to record the local changes made to the thumbnails. +// If this is not called, the operations (e.g. set thumbnail or clear thumbnail) +// appear to work but do not push the changes back to the inventory (local cache view only)  bool writeInventoryThumbnailID(LLUUID item_id, LLUUID thumbnail_asset_id)  {      if (AISAPI::isAvailable()) @@ -395,40 +367,164 @@ bool writeInventoryThumbnailID(LLUUID item_id, LLUUID thumbnail_asset_id)      }  } +// Called when the Write Thumbanils button is pushed. Iterates over the name/item and +// name/.texture maps and where it finds a common name, extracts what is needed and +// writes the thumbnail accordingly.  void LLFloaterInventoryThumbnailsHelper::onWriteThumbnails()  { -    mOutputLog->appendText( -        STRINGIZE( -            "\n==== Writing thumbnails for " << -            mNameItemIDTextureId.size() << -            " entries ====" << -            std::endl -        ), false); +    std::map<std::string, LLViewerInventoryItem*>::iterator item_iter = mItemNamesItems.begin(); +    while (item_iter != mItemNamesItems.end()) +    { +        std::string item_name = (*item_iter).first; + +        std::map<std::string, LLUUID>::iterator texture_iter = mTextureNamesIDs.find(item_name); +        if (texture_iter != mTextureNamesIDs.end()) +        { +            LLUUID item_id = (*item_iter).second->getUUID(); + +            LLUUID thumbnail_asset_id = (*texture_iter).second; -    std::map<std::string, std::pair< LLUUID, LLUUID>>::iterator iter = mNameItemIDTextureId.begin(); -    size_t index = 1; +            writeToLog( +                STRINGIZE( +                    "WRITING THUMB " << +                    (*item_iter).first << +                    "\n" << +                    "item ID: " << +                    item_id << +                    "\n" << +                    "thumbnail texture ID: " << +                    thumbnail_asset_id << +                    "\n" +                ), true); + + +            (*item_iter).second->setThumbnailUUID(thumbnail_asset_id); + +            // This additional step (notifying AIS API) is required +            // to make the changes persist outside of the local cache +            writeInventoryThumbnailID(item_id, thumbnail_asset_id); +        } -    while (iter != mNameItemIDTextureId.end()) +        ++item_iter; +    } + +    updateDisplayList(); +} + +// Called when the Log Items with Missing Thumbnails is selected. This merely writes +// a list of all the items for which the thumbnail ID is Null. Typical use case is to +// copy from the log window, pasted to Slack to illustrate which items are missing +// a thumbnail +void LLFloaterInventoryThumbnailsHelper::onLogMissingThumbnails() +{ +    std::map<std::string, LLViewerInventoryItem*>::iterator item_iter = mItemNamesItems.begin(); +    while (item_iter != mItemNamesItems.end())      { -        mOutputLog->appendText( -            STRINGIZE( -                "WRITING THUMB (" << index++  << "/" << mNameItemIDTextureId.size() << ")> " << -                (*iter).first << -                "\n" << -                "item ID: " << -                ((*iter).second).first.asString() << -                "\n" << -                "thumbnail texture ID: " << -                ((*iter).second).second.asString() << -                "\n" -            ), true); - -        LLUUID item_id = ((*iter).second).first; -        LLUUID thumbnail_asset_id = ((*iter).second).second; - -        writeInventoryThumbnailID(item_id, thumbnail_asset_id); - -        ++iter; +        LLUUID thumbnail_id = (*item_iter).second->getThumbnailUUID(); + +        if (thumbnail_id == LLUUID::null) +        { +            writeToLog( +                STRINGIZE( +                    "Missing thumbnail: " << +                    (*item_iter).first << +                    std::endl +                ), true); +        } + +        ++item_iter; +    } +} + +// Called when the Clear Thumbnail button is selected.  Code to perform the clear (really +// just writing a NULL UUID into the thumbnail field) is behind an "Are you Sure?" dialog +// since it cannot be undone and potentinally, you could remove the thumbnails from your +// whole inventory this way. +void LLFloaterInventoryThumbnailsHelper::onClearThumbnails() +{ +    // create and show confirmation (Yes/No) textbox since this is a destructive operation +    LLNotificationsUtil::add("ClearInventoryThumbnailsWarning", LLSD(), LLSD(), +                             [&](const LLSD & notif, const LLSD & resp) +    { +        S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); +        if (opt == 0) +        { +            std::map<std::string, LLViewerInventoryItem*>::iterator item_iter = mItemNamesItems.begin(); +            while (item_iter != mItemNamesItems.end()) +            { +                (*item_iter).second->setThumbnailUUID(LLUUID::null); + +                // This additional step (notifying AIS API) is required +                // to make the changes persist outside of the local cache +                const LLUUID item_id = (*item_iter).second->getUUID(); +                writeInventoryThumbnailID(item_id, LLUUID::null); + +                ++item_iter; +            } + +            updateDisplayList(); +        } +        else +        { +            LL_INFOS() << "Clearing on thumbnails was canceled" << LL_ENDL; +        } +    }); +} + +// Update the endabled state of some of the UI buttons based on what has +// been recorded so far.  For example, if there are no valid item/texture pairs, +// then the Write Thumbnails button is not enabled. +void LLFloaterInventoryThumbnailsHelper::updateButtonStates() +{ +    size_t found_count = 0; + +    std::map<std::string, LLViewerInventoryItem*>::iterator item_iter = mItemNamesItems.begin(); +    while (item_iter != mItemNamesItems.end()) +    { +        std::string item_name = (*item_iter).first; + +        std::map<std::string, LLUUID>::iterator texture_iter = mTextureNamesIDs.find(item_name); +        if (texture_iter != mTextureNamesIDs.end()) +        { +            found_count++; +        } + +        ++item_iter; +    } + +    // the "Write Thumbnails" button is only enabled when there is at least one +    // item with a matching texture ready to be written to the thumbnail field +    if (found_count > 0) +    { +        mWriteThumbnailsBtn->setEnabled(true);      } +    else +    { +        mWriteThumbnailsBtn->setEnabled(false); +    } + +    // The "Log Missing Items" and "Clear Thumbnails" buttons are only enabled +    // when there is at least 1 item that was pasted from inventory (doesn't need +    // to have a matching texture for these operations) +    if (mItemNamesItems.size() > 0) +    { +        mLogMissingThumbnailsBtn->setEnabled(true); +        mClearThumbnailsBtn->setEnabled(true); +    } +    else +    { +        mLogMissingThumbnailsBtn->setEnabled(false); +        mClearThumbnailsBtn->setEnabled(false); +    } +} + +// Helper function for writing a line to the log window. Currently the only additional +// feature is that it scrolls to the bottom each time a line is written but it +// is envisaged that other common actions will be added here eventually - E.G. write eavh +// line to the Second Life log too for example. +void LLFloaterInventoryThumbnailsHelper::writeToLog(std::string logline, bool prepend_newline) +{ +    mOutputLog->appendText(logline, prepend_newline); +      mOutputLog->setCursorAndScrollToEnd();  } diff --git a/indra/newview/llfloaterinventorythumbnailshelper.h b/indra/newview/llfloaterinventorythumbnailshelper.h index ec83d5b7e0..b42a85d1a5 100644 --- a/indra/newview/llfloaterinventorythumbnailshelper.h +++ b/indra/newview/llfloaterinventorythumbnailshelper.h @@ -1,7 +1,7 @@  /**   * @file llfloaterinventorythumbnailshelper.h   * @author Callum Prentice - * @brief Helper floater for bulk processing of inventory thumbnails + * @brief Helper floater for bulk processing of inventory thumbnails tool   *   * $LicenseInfo:firstyear=2008&license=viewerlgpl$   * Second Life Viewer Source Code @@ -31,7 +31,6 @@  #include "llfloater.h"  class LLTextEditor;  class LLScrollListCtrl; -class LLMediaCtrl;  class LLViewerInventoryItem;  class LLUUID; @@ -46,27 +45,38 @@ class LLFloaterInventoryThumbnailsHelper:          LLScrollListCtrl* mInventoryThumbnailsList; +        LLTextEditor* mOutputLog; +          LLUICtrl* mPasteItemsBtn;          void onPasteItems();          LLUICtrl* mPasteTexturesBtn;          void onPasteTextures(); -        LLTextEditor* mOutputLog; - -        void mergeItemsTextures(); -          LLUICtrl* mWriteThumbnailsBtn;          void onWriteThumbnails(); +        LLUICtrl* mLogMissingThumbnailsBtn; +        void onLogMissingThumbnails(); + +        LLUICtrl* mClearThumbnailsBtn; +        void onClearThumbnails(); +          void recordInventoryItemEntry(LLViewerInventoryItem* item);          void recordTextureItemEntry(LLViewerInventoryItem* item); -        void populateThumbnailNames(); +        void updateButtonStates(); +        void updateDisplayList(); +        void writeToLog(std::string logline, bool prepend_newline); -        std::map<std::string, LLUUID> mItemNamesIDs; +        std::map<std::string, LLViewerInventoryItem*> mItemNamesItems;          std::map<std::string, LLUUID> mTextureNamesIDs; -        std::map<std::string, std::pair< LLUUID, LLUUID>> mNameItemIDTextureId; +        enum EListColumnNum +        { +            NAME = 0, +            EXISTING_TEXTURE = 1, +            NEW_TEXTURE = 2 +        };  };  #endif // LL_LLFLOATERINVENTORYTHUMBNAILSHELPER_H diff --git a/indra/newview/skins/default/xui/en/floater_bulky_thumbs.xml b/indra/newview/skins/default/xui/en/floater_bulky_thumbs.xml index e94717f947..d23fd1247f 100644 --- a/indra/newview/skins/default/xui/en/floater_bulky_thumbs.xml +++ b/indra/newview/skins/default/xui/en/floater_bulky_thumbs.xml @@ -44,14 +44,23 @@        left="10"        name="merge_items_textures"        bottom="8" -      width="200" /> +      width="100" />      <button        follows="left|bottom"        height="20"        label="Write Thumbnails"        layout="bottomleft" -      left="250" +      left="150"        name="write_items_thumbnails"        bottom="8" -      width="200" /> +      width="100" /> +    <button +      follows="left|bottom" +      height="20" +      label="Missing Thumbnails" +      layout="bottomleft" +      left="250" +      name="display_thumbless_items" +      bottom="8" +      width="100" />  </floater>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/floater_inventory_thumbnails_helper.xml b/indra/newview/skins/default/xui/en/floater_inventory_thumbnails_helper.xml index 512bce2475..aa3500bac2 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory_thumbnails_helper.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory_thumbnails_helper.xml @@ -9,7 +9,7 @@    name="contents"    help_topic="contents"    title="Inventory Thumbnails Helper" -  width="500"> +  width="800">      <scroll_list         top="20"         height="350" @@ -23,14 +23,20 @@         right="-8"         tool_tip="Paste items from your inventory">          <scroll_list.columns +             dynamic_width="true"               label="Inventory Item" -             name="name" -             relative_width="0.40" /> +             name="item_name" +             relative_width="0.4" /> +        <scroll_list.columns +             dynamic_width="true" +             label="Existing Texture" +             name="existing_texture" +             relative_width="0.3" />          <scroll_list.columns               dynamic_width="true" -             label="Texture Name" -             name="texture" -             relative_width="0.6" /> +             label="New Texture" +             name="new_texture" +             relative_width="0.3" />      </scroll_list>      <text_editor        top="375" @@ -73,10 +79,21 @@      <button        follows="left|bottom"        height="20" -      label="List items with no thumb" +      label="Log items with no thumbnail"        layout="bottomleft"        right="-10" -      name="list_items_no_thumb_btn" +      name="log_missing_thumbnails_btn"        bottom="60"        width="235" /> +    <button +      follows="left|bottom" +      height="20" +      label="Clear thumbnails from pasted items" +      layout="bottomleft" +      right="-10" +      name="clear_thumbnails_btn" +      top_delta="26" +      width="235" /> + +  </floater>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index ef720e65e3..45020163ef 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -12074,4 +12074,18 @@ Would you like to save them first?         yestext="Yes"/>    </notification> +    <notification +  icon="alertmodal.tga" +  name="ClearInventoryThumbnailsWarning" +  type="alertmodal"> +        You are about to remove thumbnail images from the inventory items in the list. This change cannot be undone. + +        Would you like to proceed? +        <tag>confirm</tag> +        <usetemplate +         name="okcancelbuttons" +         notext="No" +         yestext="Yes"/> +    </notification> +      </notifications>  | 
