diff options
Diffstat (limited to 'indra/newview')
46 files changed, 1337 insertions, 287 deletions
| diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7a70d0b6e6..fc83c16e5d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -233,6 +233,7 @@ set(viewer_SOURCE_FILES      llfloaterimcontainer.cpp      llfloaterinspect.cpp      llfloaterinventorysettings.cpp +    llfloaterinventorythumbnailshelper.cpp      llfloaterjoystick.cpp      llfloaterlagmeter.cpp      llfloaterland.cpp @@ -887,6 +888,7 @@ set(viewer_HEADER_FILES      llfloaterimcontainer.h      llfloaterinspect.h      llfloaterinventorysettings.h +    llfloaterinventorythumbnailshelper.h      llfloaterjoystick.h      llfloaterlagmeter.h      llfloaterland.h diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 3853aaa8fd..b7f452904a 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -4333,6 +4333,10 @@ void LLAgent::teleportRequest(  // Landmark ID = LLUUID::null means teleport home  void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)  { +    if (landmark_asset_id.isNull()) +    { +        gAgentCamera.resetView(); +    }  	mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLandmark(landmark_asset_id));  	startTeleportRequest();  } diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 17e1a27934..f23ce13608 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -1738,10 +1738,6 @@ void AISUpdate::doUpdate()  		LL_DEBUGS("Inventory") << "cat version update " << cat->getName() << " to version " << cat->getVersion() << LL_ENDL;  		if (cat->getVersion() != version)  		{ -			LL_WARNS() << "Possible version mismatch for category " << cat->getName() -					<< ", viewer version " << cat->getVersion() -					<< " AIS version " << version << " !!!Adjusting local version!!!" <<  LL_ENDL; -              // the AIS version should be considered the true version. Adjust               // our local category model to reflect this version number.  Otherwise               // it becomes possible to get stuck with the viewer being out of  @@ -1751,13 +1747,23 @@ void AISUpdate::doUpdate()              // is performed.  This occasionally gets out of sync however.              if (version != LLViewerInventoryCategory::VERSION_UNKNOWN)              { +                LL_WARNS() << "Possible version mismatch for category " << cat->getName() +                    << ", viewer version " << cat->getVersion() +                    << " AIS version " << version << " !!!Adjusting local version!!!" << LL_ENDL;                  cat->setVersion(version);              }              else              {                  // We do not account for update if version is UNKNOWN, so we shouldn't rise version                  // either or viewer will get stuck on descendants count -1, try to refetch folder instead -                cat->fetch(); +                // +                // Todo: proper backoff? + +                LL_WARNS() << "Possible version mismatch for category " << cat->getName() +                    << ", viewer version " << cat->getVersion() +                    << " AIS version " << version << " !!!Rerequesting category!!!" << LL_ENDL; +                const S32 LONG_EXPIRY = 360; +                cat->fetch(LONG_EXPIRY);              }  		}  	} diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 4a43133ff6..ec411a680f 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1712,7 +1712,7 @@ bool LLAppViewer::cleanup()      LLNotifications::instance().clear();  	// workaround for DEV-35406 crash on shutdown -	LLEventPumps::instance().reset(); +	LLEventPumps::instance().reset(true);  	//dump scene loading monitor results  	if (LLSceneMonitor::instanceExists()) diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index cc4f4536a4..3444f50e52 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -177,6 +177,11 @@ LLNotificationChiclet::LLNotificationChiclet(const Params& p)  	LLFloaterNotificationsTabbed::getInstance()->setSysWellChiclet(this);  } +LLNotificationChiclet::~LLNotificationChiclet() +{ +    mNotificationChannel.reset(); +} +  void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)  {  	std::string action = user_data.asString(); diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index 58a797218f..1698fa269a 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -531,8 +531,9 @@ public:  	struct Params : public LLInitParam::Block<Params, LLSysWellChiclet::Params>{};  protected: -	struct ChicletNotificationChannel : public LLNotificationChannel +	class ChicletNotificationChannel : public LLNotificationChannel  	{ +    public:  		ChicletNotificationChannel(LLNotificationChiclet* chiclet)   			: LLNotificationChannel(LLNotificationChannel::Params().filter(filterNotification).name(chiclet->getSessionId().asString()))  			, mChiclet(chiclet) @@ -542,6 +543,7 @@ protected:  			connectToChannel("Offer");  			connectToChannel("Notifications");  		} +        virtual ~ChicletNotificationChannel() {}  		static bool filterNotification(LLNotificationPtr notify);  		// connect counter updaters to the corresponding signals @@ -553,9 +555,10 @@ protected:  	};  	boost::scoped_ptr<ChicletNotificationChannel> mNotificationChannel; -				 -	LLNotificationChiclet(const Params& p); -				 + +    LLNotificationChiclet(const Params& p); +    ~LLNotificationChiclet(); +  	/**  	 * Processes clicks on chiclet menu.  	 */ diff --git a/indra/newview/llfloaterinventorythumbnailshelper.cpp b/indra/newview/llfloaterinventorythumbnailshelper.cpp new file mode 100644 index 0000000000..814f88e9b9 --- /dev/null +++ b/indra/newview/llfloaterinventorythumbnailshelper.cpp @@ -0,0 +1,543 @@ +/** + * @file llfloaterinventorythumbnailshelper.cpp + * @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. + * + * 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 "llaisapi.h" +#include "llclipboard.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llscrolllistctrl.h" +#include "lltexteditor.h" +#include "lluictrlfactory.h" +#include "lluuid.h" + +#include "llfloaterinventorythumbnailshelper.h" + +LLFloaterInventoryThumbnailsHelper::LLFloaterInventoryThumbnailsHelper(const LLSD& key) +    :   LLFloater("floater_inventory_thumbnails_helper") +{ +} + +LLFloaterInventoryThumbnailsHelper::~LLFloaterInventoryThumbnailsHelper() +{ +} + +BOOL LLFloaterInventoryThumbnailsHelper::postBuild() +{ +    mInventoryThumbnailsList = getChild<LLScrollListCtrl>("inventory_thumbnails_list"); +    mInventoryThumbnailsList->setAllowMultipleSelection(true); + +    mOutputLog = getChild<LLTextEditor>("output_log"); +    mOutputLog->setMaxTextLength(0xffff * 0x10); + +    mPasteItemsBtn = getChild<LLUICtrl>("paste_items_btn"); +    mPasteItemsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onPasteItems, this)); +    mPasteItemsBtn->setEnabled(true); + +    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, LLViewerInventoryItem*>::iterator iter = mItemNamesItems.find(name); +    if (iter == mItemNamesItems.end()) +    { +        mItemNamesItems.insert({name, item}); + +        writeToLog( +            STRINGIZE( +                "ITEM " << mItemNamesItems.size() << "> " << +                name << +                std::endl +            ), false); +    } +    else +    { +        // dupe - do not save +    } +} + +// 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()) +    { +        return; +    } + +    writeToLog( +        STRINGIZE( +            "\n==== Pasting items from inventory ====" << +            std::endl +        ), false); + +    std::vector<LLUUID> objects; +    LLClipboard::instance().pasteFromClipboard(objects); +    size_t count = objects.size(); + +    for (size_t i = 0; i < count; i++) +    { +        const LLUUID& entry = objects.at(i); + +        // Check for a folder +        const LLInventoryCategory* cat = gInventory.getCategory(entry); +        if (cat) +        { +            LLInventoryModel::cat_array_t cat_array; +            LLInventoryModel::item_array_t item_array; + +            LLIsType is_object(LLAssetType::AT_OBJECT); +            gInventory.collectDescendentsIf(cat->getUUID(), +                                            cat_array, +                                            item_array, +                                            LLInventoryModel::EXCLUDE_TRASH, +                                            is_object); + +            LLIsType is_bodypart(LLAssetType::AT_BODYPART); +            gInventory.collectDescendentsIf(cat->getUUID(), +                                            cat_array, +                                            item_array, +                                            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); +                recordInventoryItemEntry(item); +            } +        } + +        // 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 || item_type == LLAssetType::AT_CLOTHING) +            { +                recordInventoryItemEntry(item); +            } +        } +    } + +    // 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(); + +    std::map<std::string, LLUUID>::iterator iter = mTextureNamesIDs.find(name); +    if (iter == mTextureNamesIDs.end()) +    { +        LLUUID id = item->getAssetUUID(); +        mTextureNamesIDs.insert({name, id}); + +        writeToLog( +            STRINGIZE( +                "TEXTURE " << mTextureNamesIDs.size() << "> " << +                name << +                //" | " << +                //id.asString() << +                std::endl +            ), false); +    } +    else +    { +        // dupe - do not save +    } +} + +// 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()) +    { +        return; +    } + +    writeToLog( +        STRINGIZE( +            "\n==== Pasting textures from inventory ====" << +            std::endl +        ), false); + +    std::vector<LLUUID> objects; +    LLClipboard::instance().pasteFromClipboard(objects); +    size_t count = objects.size(); + +    for (size_t i = 0; i < count; i++) +    { +        const LLUUID& entry = objects.at(i); + +        const LLInventoryCategory* cat = gInventory.getCategory(entry); +        if (cat) +        { +            LLInventoryModel::cat_array_t cat_array; +            LLInventoryModel::item_array_t item_array; + +            LLIsType is_object(LLAssetType::AT_TEXTURE); +            gInventory.collectDescendentsIf(cat->getUUID(), +                                            cat_array, +                                            item_array, +                                            LLInventoryModel::EXCLUDE_TRASH, +                                            is_object); + +            for (size_t i = 0; i < item_array.size(); i++) +            { +                LLViewerInventoryItem* item = item_array.at(i); +                recordTextureItemEntry(item); +            } +        } + +        LLViewerInventoryItem* item = gInventory.getItem(entry); +        if (item) +        { +            const LLAssetType::EType item_type = item->getType(); +            if (item_type == LLAssetType::AT_TEXTURE) +            { +                recordTextureItemEntry(item); +            } +        } +    } + +    // update the main list view based on what we found +    updateDisplayList(); + +    // update the buttons enabled state based on what we found/saved +    updateButtonStates(); +} + +// Updates the main list of entries in the UI based on what is in the maps/storage +void LLFloaterInventoryThumbnailsHelper::updateDisplayList() +{ +    mInventoryThumbnailsList->deleteAllItems(); + +    std::map<std::string, LLViewerInventoryItem*>::iterator item_iter = mItemNamesItems.begin(); +    while (item_iter != mItemNamesItems.end()) +    { +        std::string item_name = (*item_iter).first; + +        std::string existing_texture_name = std::string(); +        LLUUID existing_thumbnail_id = (*item_iter).second->getThumbnailUUID(); +        if (existing_thumbnail_id != LLUUID::null) +        { +            existing_texture_name = existing_thumbnail_id.asString(); +        } +        else +        { +            existing_texture_name = "none"; +        } + +        std::string new_texture_name = std::string(); +        std::map<std::string, LLUUID>::iterator texture_iter = mTextureNamesIDs.find(item_name); +        if (texture_iter != mTextureNamesIDs.end()) +        { +            new_texture_name = (*texture_iter).first; +        } +        else +        { +            new_texture_name = "missing"; +        } + +        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"; + +        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); + +        ++item_iter; +    } +} + +#if 1 +// *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model. +// temp code in transition +void inventoryThumbnailsHelperCb(LLPointer<LLInventoryCallback> cb, LLUUID id) +{ +    if (cb.notNull()) +    { +        cb->fire(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()) +    { + +        LLSD updates; +        updates["thumbnail"] = LLSD().with("asset_id", thumbnail_asset_id.asString()); + +        LLPointer<LLInventoryCallback> cb; + +        AISAPI::completion_t cr = boost::bind(&inventoryThumbnailsHelperCb, cb, _1); +        AISAPI::UpdateItem(item_id, updates, cr); + +        return true; +    } +    else +    { +        LL_WARNS() << "Unable to write inventory thumbnail because the AIS API is not available" << LL_ENDL; +        return false; +    } +} + +// 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() +{ +    // create and show confirmation (Yes/No) textbox since this is a destructive operation +    LLNotificationsUtil::add("WriteInventoryThumbnailsWarning", 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()) +            { +                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; + +                    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); +                } + +                ++item_iter; +            } + +            updateDisplayList(); +        } +        else +        { +            LL_INFOS() << "Writing new thumbnails was canceled" << LL_ENDL; +        } +    }); +} + +// 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()) +    { +        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 new file mode 100644 index 0000000000..b42a85d1a5 --- /dev/null +++ b/indra/newview/llfloaterinventorythumbnailshelper.h @@ -0,0 +1,82 @@ +/** + * @file llfloaterinventorythumbnailshelper.h + * @author Callum Prentice + * @brief Helper floater for bulk processing of inventory thumbnails tool + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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$ + */ + +#ifndef LL_LLFLOATERINVENTORYTHUMBNAILSHELPER_H +#define LL_LLFLOATERINVENTORYTHUMBNAILSHELPER_H + +#include "llfloater.h" +class LLTextEditor; +class LLScrollListCtrl; +class LLViewerInventoryItem; +class LLUUID; + +class LLFloaterInventoryThumbnailsHelper: +    public LLFloater +{ +        friend class LLFloaterReg; +    private: +        LLFloaterInventoryThumbnailsHelper(const LLSD& key); +        BOOL postBuild() override; +        ~LLFloaterInventoryThumbnailsHelper(); + +        LLScrollListCtrl* mInventoryThumbnailsList; + +        LLTextEditor* mOutputLog; + +        LLUICtrl* mPasteItemsBtn; +        void onPasteItems(); + +        LLUICtrl* mPasteTexturesBtn; +        void onPasteTextures(); + +        LLUICtrl* mWriteThumbnailsBtn; +        void onWriteThumbnails(); + +        LLUICtrl* mLogMissingThumbnailsBtn; +        void onLogMissingThumbnails(); + +        LLUICtrl* mClearThumbnailsBtn; +        void onClearThumbnails(); + +        void recordInventoryItemEntry(LLViewerInventoryItem* item); +        void recordTextureItemEntry(LLViewerInventoryItem* item); +        void updateButtonStates(); +        void updateDisplayList(); +        void writeToLog(std::string logline, bool prepend_newline); + +        std::map<std::string, LLViewerInventoryItem*> mItemNamesItems; +        std::map<std::string, LLUUID> mTextureNamesIDs; + +        enum EListColumnNum +        { +            NAME = 0, +            EXISTING_TEXTURE = 1, +            NEW_TEXTURE = 2 +        }; +}; + +#endif // LL_LLFLOATERINVENTORYTHUMBNAILSHELPER_H diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp index 71b3b16809..6216f4e39a 100644 --- a/indra/newview/llfloatermarketplacelistings.cpp +++ b/indra/newview/llfloatermarketplacelistings.cpp @@ -183,7 +183,8 @@ void LLPanelMarketplaceListings::draw()      // Get the audit button enabled only after the whole inventory is fetched      if (!mAuditBtn->getEnabled())      { -        mAuditBtn->setEnabled(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()); +        LLInventoryModelBackgroundFetch* inst = LLInventoryModelBackgroundFetch::getInstance(); +        mAuditBtn->setEnabled(inst->isEverythingFetched() && !inst->folderFetchActive());      }  	LLPanel::draw(); @@ -410,8 +411,14 @@ BOOL LLFloaterMarketplaceListings::postBuild()  	mCategoryAddedObserver = new LLMarketplaceListingsAddedObserver(this);  	gInventory.addObserver(mCategoryAddedObserver); -    // Fetch aggressively so we can interact with listings right onOpen() -	fetchContents(); + +    // Fetch aggressively so we can interact with listings as soon as possible +    if (!fetchContents()) +    { +        const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); +        LLInventoryModelBackgroundFetch::instance().start(marketplacelistings_id, true); +    } +	  	return TRUE;  } @@ -440,17 +447,19 @@ void LLFloaterMarketplaceListings::onFocusReceived()  	updateView();  } -void LLFloaterMarketplaceListings::fetchContents() +bool LLFloaterMarketplaceListings::fetchContents()  { -	if (mRootFolderId.notNull() && +    if (mRootFolderId.notNull() &&          (LLMarketplaceData::instance().getSLMDataFetched() != MarketplaceFetchCodes::MARKET_FETCH_LOADING) &&          (LLMarketplaceData::instance().getSLMDataFetched() != MarketplaceFetchCodes::MARKET_FETCH_DONE)) -	{ +    {          LLMarketplaceData::instance().setDataFetchedSignal(boost::bind(&LLFloaterMarketplaceListings::updateView, this));          LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_LOADING); -		LLInventoryModelBackgroundFetch::instance().start(mRootFolderId, true); +        LLInventoryModelBackgroundFetch::instance().start(mRootFolderId, true);          LLMarketplaceData::instance().getSLMListings(); -	} +        return true; +    } +    return false;  }  void LLFloaterMarketplaceListings::setRootFolder() diff --git a/indra/newview/llfloatermarketplacelistings.h b/indra/newview/llfloatermarketplacelistings.h index 085e517a9d..78d43f97a9 100644 --- a/indra/newview/llfloatermarketplacelistings.h +++ b/indra/newview/llfloatermarketplacelistings.h @@ -114,8 +114,8 @@ public:  protected:  	void setRootFolder();  	void setPanels(); -	void fetchContents(); -     +    bool fetchContents(); +  	void setStatusString(const std::string& statusString);  	void onClose(bool app_quitting); diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index c8559fc9d3..62e4022ddb 100755 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -327,6 +327,7 @@ void* LLFloaterWorldMap::createWorldMapView(void* data)  BOOL LLFloaterWorldMap::postBuild()  {      mMapView = dynamic_cast<LLWorldMapView*>(getChild<LLPanel>("objects_mapview")); +    mMapView->setPan(0, 0, true);  	LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");  	avatar_combo->selectFirstItem(); diff --git a/indra/newview/llinspecttexture.cpp b/indra/newview/llinspecttexture.cpp index da4e3c0949..76e428b7d0 100644 --- a/indra/newview/llinspecttexture.cpp +++ b/indra/newview/llinspecttexture.cpp @@ -84,7 +84,10 @@ LLToolTip* LLInspectTextureUtil::createInventoryToolTip(LLToolTip::Params p)                          }                      }  				} - +                if ((!p.message.isProvided() || p.message().empty()))  +                { +                    return NULL; +                }  				// No or more than one texture found => show default tooltip  				return LLUICtrlFactory::create<LLToolTip>(p);  			} diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 932a0316dd..f806614e29 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2284,8 +2284,11 @@ BOOL LLFolderBridge::isItemMovable() const  void LLFolderBridge::selectItem()  { -	// Have no fear: the first thing start() does is to test if everything for that folder has been fetched... -	LLInventoryModelBackgroundFetch::instance().start(getUUID(), true); +    LLViewerInventoryCategory* cat = gInventory.getCategory(getUUID()); +    if (cat) +    { +        cat->fetch(); +    }  }  void LLFolderBridge::buildDisplayName() const @@ -2810,7 +2813,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,              is_movable = can_move_folder_to_marketplace(master_folder, dest_folder, inv_cat, tooltip_msg, bundle_size);  		} -		if (is_movable) +		if (is_movable && !move_is_into_landmarks)  		{  			LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);  			is_movable = active_panel != NULL; diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 7b4283e94d..332c6d3085 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -202,12 +202,18 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const          && !LLInventoryModelBackgroundFetch::instance().inventoryFetchInProgress())      {          LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id); -        if ((!cat && folder_id.notNull()) || (cat && cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)) +        if ((!cat && folder_id.notNull()))          { -            // At the moment background fetch only cares about VERSION_UNKNOWN, -            // so do not check isCategoryComplete that compares descendant count +            // Shouldn't happen? Server provides full list of folders on startup              LLInventoryModelBackgroundFetch::instance().start(folder_id, false);          } +        else if (cat && cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) +        { +            // At the moment background fetch only cares about VERSION_UNKNOWN, +            // so do not check isCategoryComplete that compares descendant count, +            // but if that is nesesary, do a forced scheduleFolderFetch. +            cat->fetch(); +        }  	}      if (!checkAgainstFilterThumbnails(folder_id)) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 4aeacae6ed..6662f14b12 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -462,6 +462,13 @@ void copy_inventory_category(LLInventoryModel* model,  	gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID());  } +void copy_cb(const LLUUID& dest_folder, const LLUUID& root_id) +{ +    // Decrement the count in root_id since that one item won't be copied over +    LLMarketplaceData::instance().decrementValidationWaiting(root_id); +    update_folder_cb(dest_folder); +}; +  void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items)  {  	model->notifyObservers(); @@ -480,12 +487,21 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode  		LLMarketplaceData::instance().setValidationWaiting(root_id, count_descendants_items(cat->getUUID()));  	} +    LLPointer<LLInventoryCallback> cb; +    if (root_copy_id.isNull()) +    { +        cb = new LLBoostFuncInventoryCallback(boost::bind(copy_cb, new_cat_uuid, root_id)); +    } +    else +    { +        cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_uuid)); +    } +  	// Copy all the items  	LLInventoryModel::item_array_t item_array_copy = *item_array;  	for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++)  	{  		LLInventoryItem* item = *iter; -		LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_uuid));  		if (item->getIsLinkType())  		{ @@ -500,8 +516,11 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode  				LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *)item;  				gInventory.changeItemParent(viewer_inv_item, new_cat_uuid, true);  			} -			// Decrement the count in root_id since that one item won't be copied over -			LLMarketplaceData::instance().decrementValidationWaiting(root_id); +            if (root_copy_id.isNull()) +            { +                // Decrement the count in root_id since that one item won't be copied over +                LLMarketplaceData::instance().decrementValidationWaiting(root_id); +            }  		}  		else  		{ diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index 68581d04eb..d2056fb44d 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -2402,26 +2402,42 @@ void LLInventoryGallery::startDrag()  {      std::vector<EDragAndDropType> types;      uuid_vec_t ids; +    LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_AGENT;      for (LLUUID& selected_id : mSelectedItemIDs)      {          const LLInventoryItem* item = gInventory.getItem(selected_id);          if (item)          { +            if (item->getPermissions().getOwner() == ALEXANDRIA_LINDEN_ID) +            { +                src = LLToolDragAndDrop::SOURCE_LIBRARY; +            } +              EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(item->getType());              types.push_back(type);              ids.push_back(selected_id);          }          const LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id);         -        if (cat && gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID()) -            && !LLFolderType::lookupIsProtectedType((cat)->getPreferredType())) +        if (cat)          { -            EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(cat->getType()); -            types.push_back(type); -            ids.push_back(selected_id); +            if (gInventory.isObjectDescendentOf(selected_id, gInventory.getLibraryRootFolderID())) +            { +                src = LLToolDragAndDrop::SOURCE_LIBRARY; +                EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(cat->getType()); +                types.push_back(type); +                ids.push_back(selected_id); +            } +            else if (gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID()) +                && !LLFolderType::lookupIsProtectedType((cat)->getPreferredType())) +            { +                EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(cat->getType()); +                types.push_back(type); +                ids.push_back(selected_id); +            }          }      } -    LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, LLToolDragAndDrop::SOURCE_AGENT); +    LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, src);  }  bool LLInventoryGallery::areViewsInitialized() diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 05aa2e423f..205e5f3489 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -3550,6 +3550,9 @@ void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, vo  		gInventoryCallbacks.fire(callback_id, item_id); +        // Message system at the moment doesn't support Thumbnails and potential +        // newer features so just rerequest whole item +        //          // todo: instead of unpacking message fully,          // grab only an item_id, then fetch          LLInventoryModelBackgroundFetch::instance().scheduleItemFetch(item_id, true); @@ -3912,19 +3915,22 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)  	for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit)  	{ -		gInventory.updateCategory(*cit); - -        // Temporary workaround: just fetch the item using AIS to get missing fields. -        // If this works fine we might want to extract ids only from the message -        // then use AIS as a primary fetcher -        LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch((*cit)->getUUID(), true /*force, since it has changes*/); +        gInventory.updateCategory(*cit); +        if ((*cit)->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) +        { +            // Temporary workaround: just fetch the item using AIS to get missing fields. +            // If this works fine we might want to extract 'ids only' from the message +            // then use AIS as a primary fetcher +            LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch((*cit)->getUUID(), true /*force, since it has changes*/); +        } +        // else already called fetch() above  	}  	for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit)  	{  		gInventory.updateItem(*iit);          // Temporary workaround: just fetch the item using AIS to get missing fields. -        // If this works fine we might want to extract ids only from the message +        // If this works fine we might want to extract 'ids only' from the message          // then use AIS as a primary fetcher          LLInventoryModelBackgroundFetch::instance().scheduleItemFetch((*iit)->getUUID(), true);  	} diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 1f410bea10..722447b5d7 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -193,13 +193,16 @@ LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch():      mLastFetchCount(0),      mFetchFolderCount(0),      mAllRecursiveFoldersFetched(false), -	mRecursiveInventoryFetchStarted(false), -	mRecursiveLibraryFetchStarted(false), -	mMinTimeBetweenFetches(0.3f) +    mRecursiveInventoryFetchStarted(false), +    mRecursiveLibraryFetchStarted(false), +    mRecursiveMarketplaceFetchStarted(false), +    mMinTimeBetweenFetches(0.3f)  {}  LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch() -{} +{ +    gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); +}  bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const  { @@ -314,6 +317,23 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive)  				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);  			}  		} +        else if (recursive && cat && cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_LISTINGS) +        { +            if (mFetchFolderQueue.empty() || mFetchFolderQueue.back().mUUID != id) +            { +                if (recursive && AISAPI::isAvailable()) +                { +                    // Request marketplace folder and content separately +                    mFetchFolderQueue.push_front(FetchQueueInfo(id, FT_FOLDER_AND_CONTENT)); +                } +                else +                { +                    mFetchFolderQueue.push_front(FetchQueueInfo(id, recursion_type)); +                } +                gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); +                mRecursiveMarketplaceFetchStarted = true; +            } +        }  		else  		{              if (AISAPI::isAvailable()) @@ -359,8 +379,22 @@ void LLInventoryModelBackgroundFetch::scheduleFolderFetch(const LLUUID& cat_id,          mBackgroundFetchActive = true;          mFolderFetchActive = true; -        // Specific folder requests go to front of queue. -        mFetchFolderQueue.push_front(FetchQueueInfo(cat_id, forced ? FT_FORCED : FT_DEFAULT)); +        if (forced) +        { +            // check if already requested +            if (mForceFetchSet.find(cat_id) == mForceFetchSet.end()) +            { +                mForceFetchSet.insert(cat_id); +                mFetchItemQueue.push_front(FetchQueueInfo(cat_id, FT_FORCED)); +            } +        } +        else +        { +            // Specific folder requests go to front of queue. +            // version presence acts as dupplicate prevention for normal fetches +            mFetchItemQueue.push_front(FetchQueueInfo(cat_id, FT_DEFAULT)); +        } +          gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);      }  } @@ -370,8 +404,21 @@ void LLInventoryModelBackgroundFetch::scheduleItemFetch(const LLUUID& item_id, b      if (mFetchItemQueue.empty() || mFetchItemQueue.front().mUUID != item_id)      {          mBackgroundFetchActive = true; +        if (forced) +        { +            // check if already requested +            if (mForceFetchSet.find(item_id) == mForceFetchSet.end()) +            { +                mForceFetchSet.insert(item_id); +                mFetchItemQueue.push_front(FetchQueueInfo(item_id, FT_FORCED, false)); +            } +        } +        else +        { +            // 'isFinished' being set acts as dupplicate prevention for normal fetches +            mFetchItemQueue.push_front(FetchQueueInfo(item_id, FT_DEFAULT, false)); +        } -        mFetchItemQueue.push_front(FetchQueueInfo(item_id, forced ? FT_FORCED : FT_DEFAULT, false));          gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);      }  } @@ -591,6 +638,7 @@ void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID &request_i          return;      } +    LLViewerInventoryCategory::EFetchType new_state = LLViewerInventoryCategory::FETCH_NONE;      bool request_descendants = false;      if (response_id.isNull()) // Failure      { @@ -608,10 +656,12 @@ void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID &request_i              // set folder's version to prevent viewer from trying to request folder indefinetely              LLViewerInventoryCategory* cat(gInventory.getCategory(request_id)); -            if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) +            if (cat && cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)              {                  cat->setVersion(0);              } +            // back off for a bit in case something tries to force-request immediately +            new_state = LLViewerInventoryCategory::FETCH_FAILED;          }      }      else @@ -664,7 +714,7 @@ void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID &request_i      LLViewerInventoryCategory * cat(gInventory.getCategory(request_id));      if (cat)      { -        cat->setFetching(LLViewerInventoryCategory::FETCH_NONE); +        cat->setFetching(new_state);      }  } @@ -753,7 +803,26 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis()      if (isFolderFetchProcessingComplete() && mFolderFetchActive)      { -        setAllFoldersFetched(); +        if (!mRecursiveInventoryFetchStarted || mRecursiveMarketplaceFetchStarted) +        { +            setAllFoldersFetched(); +        } +        else +        { +            // Intent is for marketplace request to happen after +            // main inventory is done, unless requested by floater +            mRecursiveMarketplaceFetchStarted = true; +            const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); +            if (marketplacelistings_id.notNull()) +            { +                mFetchFolderQueue.push_front(FetchQueueInfo(marketplacelistings_id, FT_FOLDER_AND_CONTENT)); +            } +            else +            { +                setAllFoldersFetched(); +            } +        } +              }      if (isBulkFetchProcessingComplete()) @@ -813,22 +882,8 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc                          if (child_cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_LISTINGS)                          { -                            // special case -                            content_done = false; -                            if (children.empty()) -                            { -                                // fetch marketplace alone -                                // Should it actually be fetched as FT_FOLDER_AND_CONTENT? -                                children.push_back(child_cat->getUUID()); -                                mExpectedFolderIds.push_back(child_cat->getUUID()); -                                child_cat->setFetching(target_state); -                                break; -                            } -                            else -                            { -                                // fetch marketplace alone next run -                                continue; -                            } +                            // special case, marketplace will fetch that as needed +                            continue;                          }                          children.push_back(child_cat->getUUID()); @@ -902,10 +957,10 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc                          mExpectedFolderIds.push_back(cat_id);                          EFetchType type = fetch_info.mFetchType; -                        LLUUID cat_id = cat->getUUID(); -                        AISAPI::completion_t cb = [cat_id , type](const LLUUID& response_id) +                        LLUUID cat_cb_id = cat_id; +                        AISAPI::completion_t cb = [cat_cb_id, type](const LLUUID& response_id)                          { -                            LLInventoryModelBackgroundFetch::instance().onAISFolderCalback(cat_id , response_id , type); +                            LLInventoryModelBackgroundFetch::instance().onAISFolderCalback(cat_cb_id, response_id , type);                          };                          AISAPI::ITEM_TYPE item_type = AISAPI::INVENTORY; @@ -964,6 +1019,11 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc              AISAPI::FetchItem(fetch_info.mUUID, AISAPI::INVENTORY, ais_simple_item_callback);          }      } + +    if (fetch_info.mFetchType == FT_FORCED) +    { +        mForceFetchSet.erase(fetch_info.mUUID); +    }  }  // Bundle up a bunch of requests to send all at once. diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h index a712fc7604..989968be53 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.h +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -76,7 +76,6 @@ public:      void incrFetchFolderCount(S32 fetching);  	bool isBulkFetchProcessingComplete() const; -    bool isFolderFetchProcessingComplete() const;  	void setAllFoldersFetched();      typedef boost::function<void()> folders_fetched_callback_t; @@ -86,6 +85,7 @@ public:  	void addRequestAtBack(const LLUUID & id, bool recursive, bool is_category);  protected: +    bool isFolderFetchProcessingComplete() const;      typedef enum {          FT_DEFAULT = 0, @@ -122,6 +122,7 @@ protected:  private:   	bool mRecursiveInventoryFetchStarted;  	bool mRecursiveLibraryFetchStarted; +    bool mRecursiveMarketplaceFetchStarted; // AIS3 specific  	bool mAllRecursiveFoldersFetched;      typedef boost::signals2::signal<void()> folders_fetched_signal_t;      folders_fetched_signal_t mFoldersFetchedSignal; @@ -136,6 +137,7 @@ private:  	F32 mMinTimeBetweenFetches;  	fetch_queue_t mFetchFolderQueue;      fetch_queue_t mFetchItemQueue; +    uuid_set_t mForceFetchSet;      std::list<LLUUID> mExpectedFolderIds; // for debug, should this track time?  }; diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index fe067b621a..b0617e5b6c 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -356,7 +356,6 @@ void LLInventoryFetchItemsObserver::startFetch()                  {                      // Start fetching whole folder since we need all items                      LLInventoryModelBackgroundFetch::getInstance()->scheduleFolderFetch(folder.first, true); -                  }                  else                  { diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp index 583742f970..1f4418f119 100644 --- a/indra/newview/llmachineid.cpp +++ b/indra/newview/llmachineid.cpp @@ -85,11 +85,11 @@ void LLWMIMethods::initCOMObjects()      // Step 1: --------------------------------------------------      // Initialize COM. ------------------------------------------ -    mHR = CoInitializeEx(0, COINIT_MULTITHREADED); +    mHR = CoInitializeEx(0, COINIT_APARTMENTTHREADED);      if (FAILED(mHR))      { +        // if result S_FALSE, it's already initialized          LL_DEBUGS("AppInit") << "Failed to initialize COM library. Error code = 0x" << std::hex << mHR << LL_ENDL; -        return;      }      // Step 2: -------------------------------------------------- diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 8784f403cb..d27ee941a6 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -611,27 +611,17 @@ private:      static void onIdleProcessQueue(void *userdata);      // doesn't hold just marketplace related ids -    static std::set<LLUUID> sAddQueue;      static std::set<LLUUID> sStructureQueue;      static bool sProcessingQueue;  }; -std::set<LLUUID> LLMarketplaceInventoryObserver::sAddQueue;  std::set<LLUUID> LLMarketplaceInventoryObserver::sStructureQueue;  bool LLMarketplaceInventoryObserver::sProcessingQueue = false;  void LLMarketplaceInventoryObserver::changed(U32 mask)  { -	if (mask & LLInventoryObserver::ADD && LLMarketplaceData::instance().hasValidationWaiting()) -	{ -        // When things are added to the marketplace, we might need to re-validate and fix the containing listings -        // just add whole list even if it contains items and non-marketplace folders -        const std::set<LLUUID>& changed_items = gInventory.getChangedIDs(); -        sAddQueue.insert(changed_items.begin(), changed_items.end()); -	} -     -	if (mask & (LLInventoryObserver::INTERNAL | LLInventoryObserver::STRUCTURE)) -	{ +    if (mask & (LLInventoryObserver::INTERNAL | LLInventoryObserver::STRUCTURE)) +    {          // When things are changed in the inventory, this can trigger a host of changes in the marketplace listings folder:          // * stock counts changing : no copy items coming in and out will change the stock count on folders          // * version and listing folders : moving those might invalidate the marketplace data itself @@ -641,7 +631,7 @@ void LLMarketplaceInventoryObserver::changed(U32 mask)          sStructureQueue.insert(changed_items.begin(), changed_items.end());  	} -    if (!sProcessingQueue && (!sAddQueue.empty() || !sStructureQueue.empty())) +    if (!sProcessingQueue && !sStructureQueue.empty())      {          gIdleCallbacks.addFunction(onIdleProcessQueue, NULL);          // can do without sProcessingQueue, but it's usufull for simplicity and reliability @@ -655,40 +645,6 @@ void LLMarketplaceInventoryObserver::onIdleProcessQueue(void *userdata)      const U64 MAX_PROCESSING_TIME = 1000;      U64 stop_time = start_time + MAX_PROCESSING_TIME; -    if (!sAddQueue.empty()) -    { -        // Make a copy of sAddQueue since decrementValidationWaiting -        // can theoretically add more items -        std::set<LLUUID> add_queue(sAddQueue); -        sAddQueue.clear(); - -        std::set<LLUUID>::const_iterator id_it = add_queue.begin(); -        std::set<LLUUID>::const_iterator id_end = add_queue.end(); -        // First, count the number of items in this list... -        S32 count = 0; -        for (; id_it != id_end; ++id_it) -        { -            LLInventoryObject* obj = gInventory.getObject(*id_it); -            if (obj && (LLAssetType::AT_CATEGORY != obj->getType())) -            { -                count++; -            } -        } -        // Then, decrement the folders of that amount -        // Note that of all of those, only one folder will be a listing folder (if at all). -        // The other will be ignored by the decrement method. -        id_it = add_queue.begin(); -        for (; id_it != id_end; ++id_it) -        { -            LLInventoryObject* obj = gInventory.getObject(*id_it); -            if (obj && (LLAssetType::AT_CATEGORY == obj->getType())) -            { -                // can trigger notifyObservers -                LLMarketplaceData::instance().decrementValidationWaiting(obj->getUUID(), count); -            } -        } -    } -      while (!sStructureQueue.empty() && LLTimer::getTotalTime() < stop_time)      {          std::set<LLUUID>::const_iterator id_it = sStructureQueue.begin(); @@ -722,7 +678,7 @@ void LLMarketplaceInventoryObserver::onIdleProcessQueue(void *userdata)          sStructureQueue.erase(id_it);      } -    if (LLApp::isExiting() || (sAddQueue.empty() && sStructureQueue.empty())) +    if (LLApp::isExiting() || sStructureQueue.empty())      {          // Nothing to do anymore          gIdleCallbacks.deleteFunction(onIdleProcessQueue, NULL); diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index de988555c5..b26aabca4f 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -1155,22 +1155,13 @@ LLContextMenu* LLOutfitGalleryContextMenu::createMenu()      registrar.add("Outfit.Delete", boost::bind(LLOutfitGallery::onRemoveOutfit, selected_id));      registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2));      registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitGalleryContextMenu::onThumbnail, this, selected_id)); +    registrar.add("Outfit.Save", boost::bind(&LLOutfitGalleryContextMenu::onSave, this, selected_id));      enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitGalleryContextMenu::onEnable, this, _2));      enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitGalleryContextMenu::onVisible, this, _2));      return createFromFile("menu_gallery_outfit_tab.xml");  } -void LLOutfitGalleryContextMenu::onThumbnail(const LLUUID& outfit_cat_id) -{ -    LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList); -    if (gallery && outfit_cat_id.notNull()) -    { -        LLSD data(outfit_cat_id); -        LLFloaterReg::showInstance("change_item_thumbnail", data); -    } -} -  void LLOutfitGalleryContextMenu::onCreate(const LLSD& data)  {      LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(data.asString()); @@ -1205,7 +1196,6 @@ void LLOutfitGalleryGearMenu::onUpdateItemsVisibility()      mMenu->setItemVisible("expand", FALSE);      mMenu->setItemVisible("collapse", FALSE);      mMenu->setItemVisible("thumbnail", have_selection); -    mMenu->setItemVisible("sepatator3", TRUE);      mMenu->setItemVisible("sort_folders_by_name", TRUE);      LLOutfitListGearMenuBase::onUpdateItemsVisibility();  } diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h index 9915752962..b18151599f 100644 --- a/indra/newview/lloutfitgallery.h +++ b/indra/newview/lloutfitgallery.h @@ -195,17 +195,13 @@ public:      friend class LLOutfitGallery;      LLOutfitGalleryContextMenu(LLOutfitListBase* outfit_list) -    : LLOutfitContextMenu(outfit_list), -    mOutfitList(outfit_list){} +    : LLOutfitContextMenu(outfit_list){}  protected:      /* virtual */ LLContextMenu* createMenu();      bool onEnable(LLSD::String param);      bool onVisible(LLSD::String param); -    void onThumbnail(const LLUUID& outfit_cat_id);      void onCreate(const LLSD& data); -private: -    LLOutfitListBase*	mOutfitList;  }; diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 5c7792b0df..676444397f 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -37,6 +37,7 @@  #include "llappearancemgr.h"  #include "llfloaterreg.h"  #include "llfloatersidepanelcontainer.h" +#include "llinspecttexture.h"  #include "llinventoryfunctions.h"  #include "llinventorymodel.h"  #include "llmenubutton.h" @@ -62,7 +63,7 @@ bool LLOutfitTabNameComparator::compare(const LLAccordionCtrlTab* tab1, const LL      return (LLStringUtil::compareDict(name1, name2) < 0);  } -struct outfit_accordion_tab_params : public LLInitParam::Block<outfit_accordion_tab_params, LLAccordionCtrlTab::Params> +struct outfit_accordion_tab_params : public LLInitParam::Block<outfit_accordion_tab_params, LLOutfitAccordionCtrlTab::Params>  {  	Mandatory<LLWearableItemsList::Params> wearable_list; @@ -144,7 +145,8 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id)      std::string name = cat->getName();      outfit_accordion_tab_params tab_params(get_accordion_tab_params()); -    LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(tab_params); +    tab_params.cat_id = cat_id; +    LLOutfitAccordionCtrlTab *tab = LLUICtrlFactory::create<LLOutfitAccordionCtrlTab>(tab_params);      if (!tab) return;      LLWearableItemsList* wearable_list = LLUICtrlFactory::create<LLWearableItemsList>(tab_params.wearable_list);      wearable_list->setShape(tab->getLocalRect()); @@ -1028,6 +1030,8 @@ LLContextMenu* LLOutfitContextMenu::createMenu()      registrar.add("Outfit.Edit", boost::bind(editOutfit));      registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));      registrar.add("Outfit.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList)); +    registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitContextMenu::onThumbnail, this, selected_id)); +    registrar.add("Outfit.Save", boost::bind(&LLOutfitContextMenu::onSave, this, selected_id));      enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitContextMenu::onEnable, this, _2));      enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitContextMenu::onVisible, this, _2)); @@ -1092,6 +1096,31 @@ void LLOutfitContextMenu::renameOutfit(const LLUUID& outfit_cat_id)      LLAppearanceMgr::instance().renameOutfit(outfit_cat_id);  } +void LLOutfitContextMenu::onThumbnail(const LLUUID &outfit_cat_id) +{ +    if (outfit_cat_id.notNull()) +    { +        LLSD data(outfit_cat_id); +        LLFloaterReg::showInstance("change_item_thumbnail", data); +    } +} + +void LLOutfitContextMenu::onSave(const LLUUID &outfit_cat_id) +{ +    if (outfit_cat_id.notNull()) +    { +        LLNotificationsUtil::add("ConfirmOverwriteOutfit", LLSD(), LLSD(), +            [outfit_cat_id](const LLSD ¬if, const LLSD &resp) +        { +            S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); +            if (opt == 0) +            { +                LLAppearanceMgr::getInstance()->onOutfitFolderCreated(outfit_cat_id, true); +            } +        }); +    } +} +  LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist)      :   mOutfitList(olist),          mMenu(NULL) @@ -1110,6 +1139,7 @@ LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist)      registrar.add("Gear.Expand", boost::bind(&LLOutfitListBase::onExpandAllFolders, mOutfitList));      registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenuBase::onAdd, this)); +    registrar.add("Gear.Save", boost::bind(&LLOutfitListGearMenuBase::onSave, this));      registrar.add("Gear.Thumbnail", boost::bind(&LLOutfitListGearMenuBase::onThumbnail, this));      registrar.add("Gear.SortByName", boost::bind(&LLOutfitListGearMenuBase::onChangeSortOrder, this)); @@ -1135,8 +1165,7 @@ void LLOutfitListGearMenuBase::onUpdateItemsVisibility()      if (!mMenu) return;      bool have_selection = getSelectedOutfitID().notNull(); -    mMenu->setItemVisible("sepatator1", have_selection); -    mMenu->setItemVisible("sepatator2", have_selection); +    mMenu->setItemVisible("wear_separator", have_selection);      mMenu->arrangeAndClear(); // update menu height  } @@ -1181,6 +1210,20 @@ void LLOutfitListGearMenuBase::onAdd()      }  } +void LLOutfitListGearMenuBase::onSave() +{ +    const LLUUID &selected_id = getSelectedOutfitID(); +    LLNotificationsUtil::add("ConfirmOverwriteOutfit", LLSD(), LLSD(), +        [selected_id](const LLSD ¬if, const LLSD &resp) +    { +        S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); +        if (opt == 0) +        { +            LLAppearanceMgr::getInstance()->onOutfitFolderCreated(selected_id, true); +        } +    }); +} +  void LLOutfitListGearMenuBase::onTakeOff()  {      // Take off selected outfit. @@ -1234,15 +1277,6 @@ bool LLOutfitListGearMenuBase::onVisible(LLSD::String param)          return false;      } -    // *TODO This condition leads to menu item behavior inconsistent with -    // "Wear" button behavior and should be modified or removed. -    bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == selected_outfit_id; - -    if ("wear" == param) -    { -        return !is_worn; -    } -      return true;  } @@ -1270,10 +1304,29 @@ void LLOutfitListGearMenu::onUpdateItemsVisibility()      if (!mMenu) return;      mMenu->setItemVisible("expand", TRUE);      mMenu->setItemVisible("collapse", TRUE); -    mMenu->setItemVisible("thumbnail", FALSE); // Never visible? -    mMenu->setItemVisible("sepatator3", FALSE); +    mMenu->setItemVisible("thumbnail", getSelectedOutfitID().notNull());      mMenu->setItemVisible("sort_folders_by_name", FALSE);      LLOutfitListGearMenuBase::onUpdateItemsVisibility();  } +BOOL LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask) +{ +    if (y >= getLocalRect().getHeight() - getHeaderHeight())  +    { +        LLSD params; +        params["inv_type"] = LLInventoryType::IT_CATEGORY; +        params["thumbnail_id"] = gInventory.getCategory(mFolderID)->getThumbnailUUID(); +        params["item_id"] = mFolderID; + +        LLToolTipMgr::instance().show(LLToolTip::Params() +                                    .message(getToolTip()) +                                    .sticky_rect(calcScreenRect()) +                                    .delay_time(LLView::getTooltipTimeout()) +                                    .create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1)) +                                    .create_params(params)); +        return TRUE; +    } + +    return LLAccordionCtrlTab::handleToolTip(x, y, mask); +}  // EOF diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index 66b3165169..6eeccddb07 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -31,6 +31,7 @@  #include "llpanel.h"  // newview +#include "llaccordionctrltab.h"  #include "llinventorymodel.h"  #include "lllistcontextmenu.h"  #include "llpanelappearancetab.h" @@ -147,6 +148,9 @@ protected:      static void renameOutfit(const LLUUID& outfit_cat_id); +    void onThumbnail(const LLUUID &outfit_cat_id); +    void onSave(const LLUUID &outfit_cat_id); +  private:      LLOutfitListBase*	mOutfitList;  }; @@ -178,6 +182,7 @@ private:      void onAdd();      void onTakeOff();      void onRename(); +    void onSave();      void onCreate(const LLSD& data);      bool onEnable(LLSD::String param);      bool onVisible(LLSD::String param); @@ -193,7 +198,27 @@ protected:      /*virtual*/ void onUpdateItemsVisibility();  }; -/** +class LLOutfitAccordionCtrlTab : public LLAccordionCtrlTab +{ +public: +    struct Params : public LLInitParam::Block<Params, LLAccordionCtrlTab::Params> +    { +        Optional<LLUUID> cat_id; +        Params() : cat_id("cat_id") {} +    }; + +    virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); + + protected: +    LLOutfitAccordionCtrlTab(const LLOutfitAccordionCtrlTab::Params &p)  +        : LLAccordionCtrlTab(p),  +          mFolderID(p.cat_id) +    {} +    friend class LLUICtrlFactory; + +    LLUUID mFolderID; +}; +  /**   * @class LLOutfitsList   *   * A list of agents's outfits from "My Outfits" inventory category diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index b938b30479..3ed444a5af 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -1067,6 +1067,12 @@ void LLTeleportHistoryPanel::onGearMenuAction(const LLSD& userdata)          LLLandmarkActions::getSLURLfromPosGlobal(globalPos,              boost::bind(&LLTeleportHistoryPanel::gotSLURLCallback, _1));      } +    else if ("remove" == command_name) +    { +        LLTeleportHistoryStorage::getInstance()->removeItem(index); +        LLTeleportHistoryStorage::getInstance()->save(); +        showTeleportHistory(); +    }  }  bool LLTeleportHistoryPanel::isActionEnabled(const LLSD& userdata) const @@ -1121,7 +1127,8 @@ bool LLTeleportHistoryPanel::isActionEnabled(const LLSD& userdata) const      if ("teleport" == command_name          || "view" == command_name          || "show_on_map" == command_name -        || "copy_slurl" == command_name) +        || "copy_slurl" == command_name +        || "remove" == command_name)      {          if (!mLastSelectedFlatlList)          { diff --git a/indra/newview/llperfstats.cpp b/indra/newview/llperfstats.cpp index 64e66d520b..8718f7e7b0 100644 --- a/indra/newview/llperfstats.cpp +++ b/indra/newview/llperfstats.cpp @@ -69,7 +69,7 @@ namespace LLPerfStats      {          assert_main_thread();          // these following variables are proxies for pipeline statics we do not need a two way update (no llviewercontrol handler) -        if( tuningFlag & NonImpostors ){ gSavedSettings.setU32("IndirectMaxNonImpostors", nonImpostors); }; +        if( tuningFlag & NonImpostors ){ gSavedSettings.setU32("RenderAvatarMaxNonImpostors", nonImpostors); };          if( tuningFlag & ReflectionDetail ){ gSavedSettings.setS32("RenderReflectionDetail", reflectionDetail); };          if( tuningFlag & FarClip ){ gSavedSettings.setF32("RenderFarClip", farClip); };          if( tuningFlag & UserMinDrawDistance ){ gSavedSettings.setF32("AutoTuneRenderFarClipMin", userMinDrawDistance); }; @@ -378,7 +378,7 @@ namespace LLPerfStats              auto count = countNearbyAvatars(std::min(LLPipeline::RenderFarClip, tunables.userImpostorDistance));              if( count != tunables.nonImpostors )              { -                tunables.updateNonImposters( (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER ); +                tunables.updateNonImposters( (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : 0 );                  LL_DEBUGS("AutoTune") << "There are " << count << "avatars within " << std::min(LLPipeline::RenderFarClip, tunables.userImpostorDistance) << "m of the camera" << LL_ENDL;              }          } diff --git a/indra/newview/llplacesinventorypanel.cpp b/indra/newview/llplacesinventorypanel.cpp index 1c14acd843..f3455bb4f0 100644 --- a/indra/newview/llplacesinventorypanel.cpp +++ b/indra/newview/llplacesinventorypanel.cpp @@ -120,3 +120,13 @@ S32	LLPlacesInventoryPanel::notify(const LLSD& info)  	}  	return 0;  } + +BOOL LLPlacesInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, +                                                      EAcceptance *accept, std::string &tooltip_msg) +{ +    if (mAcceptsDragAndDrop)  +    { +        return LLInventoryPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); +    } +    return FALSE; +} diff --git a/indra/newview/llplacesinventorypanel.h b/indra/newview/llplacesinventorypanel.h index 3c27964ec5..81b623b045 100644 --- a/indra/newview/llplacesinventorypanel.h +++ b/indra/newview/llplacesinventorypanel.h @@ -47,11 +47,14 @@ public:  	LLPlacesInventoryPanel(const Params& p);  	~LLPlacesInventoryPanel(); -    LLFolderView * createFolderRoot(LLUUID root_id ); +    LLFolderView * createFolderRoot(LLUUID root_id ) override;  	void saveFolderState();  	void restoreFolderState(); -	virtual S32	notify(const LLSD& info) ; +	virtual S32	notify(const LLSD& info) override; + +    BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, +                            EAcceptance *accept, std::string &tooltip_msg) override;  private:  	LLSaveFolderState*			mSavedFolderState; diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 3a08f748d6..359f2c5b1c 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -86,6 +86,7 @@  #include "llfloaterimsession.h"  #include "llfloaterinspect.h"  #include "llfloaterinventorysettings.h" +#include "llfloaterinventorythumbnailshelper.h"  #include "llfloaterjoystick.h"  #include "llfloaterlagmeter.h"  #include "llfloaterland.h" @@ -247,6 +248,7 @@ public:                  "group_picker",                  "hud",                  "incoming_call", +                "inventory_thumbnails_helper",                  "linkreplace",                  "mem_leaking",                  "marketplace_validation", @@ -333,7 +335,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("build", "floater_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTools>);  	LLFloaterReg::add("build_options", "floater_build_options.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuildOptions>);  	LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBump>); - +      	LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>);  	LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCameraPresets>);  	LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>); @@ -380,6 +382,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>);  	LLFloaterReg::add("inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>);  	LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>); +    LLFloaterReg::add("inventory_thumbnails_helper", "floater_inventory_thumbnails_helper.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterInventoryThumbnailsHelper>);  	LLFloaterReg::add("item_properties", "floater_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>);      LLFloaterReg::add("task_properties", "floater_task_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>);      LLFloaterReg::add("inventory_settings", "floater_inventory_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventorySettings>); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 0a0a19d095..b9a7c9448f 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -668,15 +668,14 @@ void LLViewerInventoryCategory::setVersion(S32 version)  	mVersion = version;  } -bool LLViewerInventoryCategory::fetch() +bool LLViewerInventoryCategory::fetch(S32 expiry_seconds)  {  	if((VERSION_UNKNOWN == getVersion())  	   && mDescendentsRequested.hasExpired())	//Expired check prevents multiple downloads.  	{  		LL_DEBUGS(LOG_INV) << "Fetching category children: " << mName << ", UUID: " << mUUID << LL_ENDL; -		const F32 FETCH_TIMER_EXPIRY = 10.0f;  		mDescendentsRequested.reset(); -		mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY); +		mDescendentsRequested.setTimerExpirySec(expiry_seconds);  		std::string url;  		if (gAgent.getRegion()) @@ -685,7 +684,7 @@ bool LLViewerInventoryCategory::fetch()  		}  		else  		{ -			LL_WARNS(LOG_INV) << "agent region is null" << LL_ENDL; +			LL_WARNS_ONCE(LOG_INV) << "agent region is null" << LL_ENDL;  		}  		if (!url.empty() || AISAPI::isAvailable())  		{ @@ -709,7 +708,13 @@ LLViewerInventoryCategory::EFetchType LLViewerInventoryCategory::getFetching()  void LLViewerInventoryCategory::setFetching(LLViewerInventoryCategory::EFetchType fetching)  { -    if (fetching > mFetching) // allow a switch from normal to recursive +    if (fetching == FETCH_FAILED) +    { +        const F32 FETCH_FAILURE_EXPIRY = 60.0f; +        mDescendentsRequested.setTimerExpirySec(FETCH_FAILURE_EXPIRY); +        mFetching = fetching; +    } +    else if (fetching > mFetching) // allow a switch from normal to recursive      {          if (mDescendentsRequested.hasExpired() || (mFetching == FETCH_NONE))          { diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index e043285ffb..0d0ccc6643 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -209,13 +209,15 @@ public:  	S32 getVersion() const;  	void setVersion(S32 version); -	// Returns true if a fetch was issued (not nessesary in progress). -	bool fetch(); +    // Returns true if a fetch was issued (not nessesary in progress). +    // no requests will happen during expiry_seconds even if fetch completed +    bool fetch(S32 expiry_seconds = 10);      typedef enum {          FETCH_NONE = 0,          FETCH_NORMAL,          FETCH_RECURSIVE, +        FETCH_FAILED, // back off      } EFetchType;      EFetchType getFetching();      // marks as fetch being in progress or as done diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index ada898b98c..55e43352bc 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4158,6 +4158,12 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)  					LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id);  					for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it)  					{ +						if (anim_it->first != object_id) +						{ +							// elements with the same key are always contiguous, bail if we went past the +							// end of this object's animations +							break; +						}  						if (anim_it->second == animation_id)  						{  							anim_found = TRUE; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 5bc7523be1..a53bd982d4 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -2043,6 +2043,7 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)  			{  				LL_WARNS() << objectp->mID << " has self as parent, skipping!"   					<< LL_ENDL; +                ++iter;  				continue;  			} diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 7b24b9ee02..f12fc3babc 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -834,7 +834,11 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id)  	for (AnimSourceIterator motion_it = mAnimationSources.find(source_id); motion_it != mAnimationSources.end(); )  	{  		gAgent.sendAnimationRequest(motion_it->second, ANIM_REQUEST_STOP); -		mAnimationSources.erase(motion_it++); +		mAnimationSources.erase(motion_it); +		// Must find() after each erase() to deal with potential iterator invalidation +		// This also ensures that we don't go past the end of this source's animations +		// into those of another source. +		motion_it = mAnimationSources.find(source_id);  	} 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 new file mode 100644 index 0000000000..aa3500bac2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_inventory_thumbnails_helper.xml @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater +  legacy_header_height="18" +  can_resize="false" +  height="600" +  layout="topleft" +  min_height="175" +  min_width="500" +  name="contents" +  help_topic="contents" +  title="Inventory Thumbnails Helper" +  width="800"> +    <scroll_list +       top="20" +       height="350" +       draw_stripes="true" +       draw_heading="true" +       follows="all" +       layout="topleft" +       left="8" +       multi_select="true" +       name="inventory_thumbnails_list" +       right="-8" +       tool_tip="Paste items from your inventory"> +        <scroll_list.columns +             dynamic_width="true" +             label="Inventory Item" +             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="New Texture" +             name="new_texture" +             relative_width="0.3" /> +    </scroll_list> +    <text_editor +      top="375" +      height="140" +      follows="all" +      left="8" +      right="-8" +      name="output_log" +      font="Monospace" +      text_color="0.1 0.5 0.1 1.0" +      width="480"> +    </text_editor> +    <button +      follows="left|bottom" +      height="20" +      label="Paste items from Inventory" +      layout="topleft" +      left="10" +      name="paste_items_btn" +      bottom="-60" +      width="235" /> +    <button +      follows="left|bottom" +      height="20" +      label="Paste textures from Inventory" +      layout="topleft" +      left_delta="0" +      name="paste_textures_btn" +      top_delta="26	" +      width="235" /> +    <button +      follows="left|bottom" +      height="20" +      label="Write Thumbnails" +      layout="topleft" +      left_delta="0" +      name="write_thumbnails_btn" +      top_delta="26	" +      width="235" /> +    <button +      follows="left|bottom" +      height="20" +      label="Log items with no thumbnail" +      layout="bottomleft" +      right="-10" +      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/menu_gallery_inventory.xml b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml index d82c453e5f..8cf0479b27 100644 --- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml @@ -35,7 +35,7 @@       layout="topleft"       name="Folder Wearables Separator" />      <menu_item_call -     label="Replace Current Outfit" +     label="Replace current outfit"       layout="topleft"       name="Replace Outfit">          <menu_item_call.on_click @@ -43,7 +43,7 @@           parameter="replaceoutfit" />      </menu_item_call>      <menu_item_call -     label="Add To Current Outfit" +     label="Add folder items"       layout="topleft"       name="Add To Outfit">          <menu_item_call.on_click @@ -51,7 +51,7 @@           parameter="addtooutfit" />      </menu_item_call>      <menu_item_call -     label="Remove From Current Outfit" +     label="Take off folder items"       layout="topleft"       name="Remove From Outfit">          <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml index 0ca505dd5d..c93a92b2b7 100755 --- a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml @@ -3,7 +3,7 @@      layout="topleft"      name="Outfit">      <menu_item_call -        label="Wear - Replace Current Outfit" +        label="Replace current outfit"          layout="topleft"          name="wear_replace">          <on_click @@ -16,7 +16,7 @@          parameter="wear_replace" />      </menu_item_call>      <menu_item_call -        label="Wear - Add to Current Outfit" +        label="Add outfit items"          layout="topleft"          name="wear_add">          <on_click @@ -29,7 +29,7 @@          parameter="wear_add" />      </menu_item_call>      <menu_item_call -        label="Take Off - Remove from Current Outfit" +        label="Take off outfit items"          layout="topleft"          name="take_off">          <on_click @@ -41,17 +41,60 @@          function="Outfit.OnVisible"          parameter="take_off" />      </menu_item_call> +    <menu_item_separator/>      <menu_item_call -     label="Image..." -     layout="topleft" -     name="thumbnail"> +        label="Image..." +        layout="topleft" +        name="thumbnail"> +        <on_click +        function="Outfit.Thumbnail" /> +    </menu_item_call> +    <menu_item_call +        label="Edit outfit" +        layout="topleft" +        name="edit"> +        <on_click +        function="Outfit.Edit" /> +        <on_visible +        function="Outfit.OnVisible" +        parameter="edit" /> +    </menu_item_call> +    <menu_item_call +        label="Rename outfit" +        layout="topleft" +        name="rename"> +        <on_click +        function="Outfit.Rename" /> +        <on_enable +        function="Outfit.OnEnable" +        parameter="rename" /> +    </menu_item_call> +    <menu_item_call +        label="Save to this outfit" +        layout="topleft" +        name="save"> +        <on_click +         function="Outfit.Save" /> +    </menu_item_call> +    <menu_item_separator> +        <on_visible +        function="Outfit.OnVisible" +        parameter="delete" /> +    </menu_item_separator> +    <menu_item_call +        label="Delete outfit" +        layout="topleft" +        name="delete">          <on_click -         function="Outfit.Thumbnail" /> +        function="Outfit.Delete" /> +        <on_visible +        function="Outfit.OnVisible" +        parameter="delete" />      </menu_item_call> -    <menu_item_separator name="sepatator1" /> +    <menu_item_separator/>      <menu          height="175" -        label="New Clothes" +        label="New clothes"          layout="topleft"          left_delta="0"          mouse_opaque="false" @@ -157,7 +200,7 @@      </menu>      <menu          height="85" -        label="New Body Parts" +        label="New body parts"          layout="topleft"          left_delta="0"          mouse_opaque="false" @@ -197,35 +240,4 @@              parameter="eyes" />          </menu_item_call>      </menu> -    <menu_item_separator name="sepatator2" /> -    <menu_item_call -        label="Edit Outfit" -        layout="topleft" -        name="edit"> -        <on_click -        function="Outfit.Edit" /> -        <on_visible -        function="Outfit.OnVisible" -        parameter="edit" /> -    </menu_item_call> -    <menu_item_call -        label="Rename Outfit" -        layout="topleft" -        name="rename"> -        <on_click -        function="Outfit.Rename" /> -        <on_enable -        function="Outfit.OnEnable" -        parameter="rename" /> -    </menu_item_call> -    <menu_item_call -        label="Delete Outfit" -        layout="topleft" -        name="delete"> -        <on_click -        function="Outfit.Delete" /> -        <on_visible -        function="Outfit.OnVisible" -        parameter="delete" /> -    </menu_item_call>  </context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 0295ef8ccd..324c08e68e 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -264,7 +264,7 @@       layout="topleft"       name="Folder Wearables Separator" />      <menu_item_call -     label="Replace Current Outfit" +     label="Replace current outfit"       layout="topleft"       name="Replace Outfit">          <menu_item_call.on_click @@ -272,7 +272,7 @@           parameter="replaceoutfit" />      </menu_item_call>      <menu_item_call -     label="Add To Current Outfit" +     label="Add folder items"       layout="topleft"       name="Add To Outfit">          <menu_item_call.on_click @@ -280,7 +280,7 @@           parameter="addtooutfit" />      </menu_item_call>      <menu_item_call -     label="Remove From Current Outfit" +     label="Take off folder items"       layout="topleft"       name="Remove From Outfit">          <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml index e216962d12..e7a453766b 100644 --- a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml @@ -4,7 +4,7 @@   visible="false"   name="Gear Outfit">      <menu_item_call -     label="Wear - Replace Current Outfit" +     label="Replace current outfit"       layout="topleft"       name="wear">          <on_click @@ -17,7 +17,7 @@           parameter="wear" />      </menu_item_call>      <menu_item_call -     label="Wear - Add to Current Outfit" +     label="Add outfit items"       layout="topleft"       name="wear_add">          <on_click @@ -25,9 +25,11 @@          <on_enable           function="Gear.OnEnable"           parameter="wear_add" /> +        <on_visible +         function="Gear.OnVisible"/>      </menu_item_call>      <menu_item_call -     label="Take Off - Remove from Current Outfit" +     label="Take off outfit items"       layout="topleft"       name="take_off">          <on_click @@ -39,19 +41,88 @@           function="Gear.OnVisible"           parameter="take_off" />      </menu_item_call> +    <menu_item_separator name="wear_separator" />      <menu_item_call       label="Image..."       layout="topleft"       name="thumbnail"> +       <on_click +        function="Gear.Thumbnail" /> +    </menu_item_call> +    <menu_item_call +     label="Rename outfit" +     layout="topleft" +     name="rename"> +        <on_click +         function="Gear.Rename" /> +        <on_enable +         function="Gear.OnEnable" +         parameter="rename" /> +        <on_visible +         function="Gear.OnVisible" +         parameter="rename" /> +    </menu_item_call> +    <menu_item_call +     label="Save to this outfit" +     layout="topleft" +     name="save"> +        <on_click +         function="Gear.Save" /> +        <on_visible +         function="Gear.OnVisible"/> +    </menu_item_call> +    <menu_item_separator> +        <on_visible +        function="Gear.OnVisible" +        parameter="delete" /> +    </menu_item_separator> +    <menu_item_call +     label="Delete outfit" +     layout="topleft" +     name="delete_outfit"> +        <on_click +         function="Gear.Delete" /> +        <on_enable +         function="Gear.OnEnable" +         parameter="delete" /> +        <on_visible +         function="Gear.OnVisible" +         parameter="delete" /> +    </menu_item_call> +    <menu_item_separator> +        <on_visible +         function="Gear.OnVisible"/> +    </menu_item_separator> +    <menu_item_check +     label="Sort folders always by name" +     layout="topleft" +     name="sort_folders_by_name"> +        <on_click +         function="Gear.SortByName" /> +        <on_check +         function="CheckControl" +         parameter="OutfitGallerySortByName" /> +    </menu_item_check> +        <menu_item_call +     label="Expand all folders" +     layout="topleft" +     name="expand"> +        <on_click +         function="Gear.Expand" /> +    </menu_item_call> +    <menu_item_call +     label="Collapse all folders" +     layout="topleft" +     name="collapse">          <on_click -         function="Gear.Thumbnail" /> +         function="Gear.Collapse" />      </menu_item_call> -  <menu_item_separator name="sepatator1" /> +  <menu_item_separator/>              <!-- copied (with minor modifications) from menu_inventory_add.xml -->              <!--  *TODO: generate dynamically? -->              <menu               height="175" -             label="New Clothes" +             label="New clothes"               layout="topleft"               left_delta="0"               mouse_opaque="false" @@ -165,7 +236,7 @@              </menu>              <menu               height="85" -             label="New Body Parts" +             label="New body parts"               layout="topleft"               left_delta="0"               mouse_opaque="false" @@ -206,57 +277,4 @@                  </menu_item_call>              </menu>              <!-- copied from menu_inventory_add.xml --> - -    <menu_item_separator name="sepatator2" /> -    <menu_item_call -     label="Expand all folders" -     layout="topleft" -     name="expand"> -        <on_click -         function="Gear.Expand" /> -    </menu_item_call> -    <menu_item_call -     label="Collapse all folders" -     layout="topleft" -     name="collapse"> -        <on_click -         function="Gear.Collapse" /> -    </menu_item_call> -    <menu_item_call -     label="Rename Outfit" -     layout="topleft" -     name="rename"> -        <on_click -         function="Gear.Rename" /> -        <on_enable -         function="Gear.OnEnable" -         parameter="rename" /> -        <on_visible -         function="Gear.OnVisible" -         parameter="rename" /> -    </menu_item_call> -    <menu_item_call -     label="Delete Outfit" -     layout="topleft" -     name="delete_outfit"> -        <on_click -         function="Gear.Delete" /> -        <on_enable -         function="Gear.OnEnable" -         parameter="delete" /> -        <on_visible -         function="Gear.OnVisible" -         parameter="delete" /> -    </menu_item_call> -    <menu_item_separator name="sepatator3" /> -    <menu_item_check -     label="Sort Folders Always by Name" -     layout="topleft" -     name="sort_folders_by_name"> -        <on_click -         function="Gear.SortByName" /> -        <on_check -         function="CheckControl" -         parameter="OutfitGallerySortByName" /> -    </menu_item_check>  </toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml index 8c8bb29baf..522e41df42 100644 --- a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml @@ -3,7 +3,7 @@   layout="topleft"   name="Outfit">      <menu_item_call -     label="Wear - Replace Current Outfit" +     label="Replace current outfit"       layout="topleft"       name="wear_replace">          <on_click @@ -16,7 +16,7 @@           parameter="wear_replace" />      </menu_item_call>      <menu_item_call -     label="Wear - Add to Current Outfit" +     label="Add outfit items"       layout="topleft"       name="wear_add">          <on_click @@ -29,7 +29,7 @@           parameter="wear_add" />      </menu_item_call>      <menu_item_call -     label="Take Off - Remove from Current Outfit" +     label="Take off outfit items"       layout="topleft"       name="take_off">          <on_click @@ -41,19 +41,26 @@           function="Outfit.OnVisible"           parameter="take_off" />      </menu_item_call> +    <menu_item_separator />      <menu_item_call -     label="Edit Outfit" -     layout="topleft" -     name="edit"> +        label="Image..." +        layout="topleft" +        name="thumbnail"> +        <on_click +        function="Outfit.Thumbnail" /> +    </menu_item_call> +    <menu_item_call +        label="Edit outfit" +        layout="topleft" +        name="edit">          <on_click           function="Outfit.Edit" />          <on_visible           function="Outfit.OnVisible"           parameter="edit" />      </menu_item_call> -    <menu_item_separator />      <menu_item_call -     label="Rename Outfit" +     label="Rename outfit"       layout="topleft"       name="rename">          <on_click @@ -63,7 +70,19 @@           parameter="rename" />      </menu_item_call>      <menu_item_call -     label="Delete Outfit" +     label="Save to this outfit" +     layout="topleft" +     name="save"> +        <on_click +         function="Outfit.Save" /> +    </menu_item_call> +    <menu_item_separator> +        <on_visible +        function="Outfit.OnVisible" +        parameter="delete" /> +    </menu_item_separator> +    <menu_item_call +     label="Delete outfit"       layout="topleft"       name="delete">          <on_click diff --git a/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml index 153e5a70a9..9bbfdd4291 100644 --- a/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml @@ -49,4 +49,17 @@           function="TeleportHistory.GearMenu.Enable"           parameter="copy_slurl" />      </menu_item_call> +    <menu_item_separator +     layout="topleft" /> +    <menu_item_call +     label="Remove from history" +     layout="topleft" +     name="remove_from_history"> +        <on_click +         function="TeleportHistory.GearMenu.Action" +         parameter="remove" /> +        <on_enable +         function="TeleportHistory.GearMenu.Enable" +         parameter="remove" /> +    </menu_item_call>  </toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 660f4b62c7..7ff3f3c2b3 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3530,6 +3530,21 @@ function="World.EnvPreset"               function="Advanced.WebContentTest"               parameter="http://duckduckgo.com"/>            </menu_item_call> +            <menu_item_call +             label="Inventory Thumbnails Helper" +             name="Inventory Thumbnails Helper" +				shortcut="control|alt|shift|X"> +                <menu_item_call.on_click +                 function="Floater.Show" +                 parameter="inventory_thumbnails_helper" /> +            </menu_item_call> +            <menu_item_call +           label="FB Connect Test" +           name="FB Connect Test"> +            <menu_item_call.on_click +             function="Advanced.WebContentTest" +             parameter="https://cryptic-ridge-1632.herokuapp.com/"/> +          </menu_item_call>            <menu_item_call               label="Dump SelectMgr"               name="Dump SelectMgr"> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index d642ea162c..4d0c7712cd 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -12261,6 +12261,50 @@ Would you like to save them first?         notext="No"         yestext="Yes"/>    </notification> + +  <notification +   icon="alertmodal.tga" +   name="ConfirmOverwriteOutfit" +   type="alertmodal"> +      <unique/> +This will replace the items in the +selected outfit with the items you +are wearing now. +      <tag>confirm</tag> +      <usetemplate +       ignoretext="Confirm before overwriting outfit" +       name="okcancelignore" +       notext="Cancel" +       yestext="Save"/> +  </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> + +  <notification +    icon="alertmodal.tga" +    name="WriteInventoryThumbnailsWarning" +    type="alertmodal"> +        You are about to overwrite thumbnail images for some or all of 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>    <notification      icon="notifytip.tga" diff --git a/indra/newview/skins/default/xui/en/panel_settings_water.xml b/indra/newview/skins/default/xui/en/panel_settings_water.xml index f19629df26..da2f915425 100644 --- a/indra/newview/skins/default/xui/en/panel_settings_water.xml +++ b/indra/newview/skins/default/xui/en/panel_settings_water.xml @@ -65,7 +65,7 @@                  Density Exponent:              </text>              <slider -                    decimal_digits="1" +                    decimal_digits="2"                      follows="left|top"                      height="16"                      increment="0.01" | 
