diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index e7a0c5f76a..34e5a0fa2d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -162,6 +162,7 @@ set(viewer_SOURCE_FILES fsnearbychatcontrol.cpp fsnearbychathub.cpp fsnearbychatvoicemonitor.cpp + fsnewitemctrl.cpp fspanelblocklist.cpp fspanelcontactsets.cpp fspanelface.cpp @@ -1022,6 +1023,7 @@ set(viewer_HEADER_FILES fsnearbychatcontrol.h fsnearbychathub.h fsnearbychatvoicemonitor.h + fsnewitemctrl.h fspanelblocklist.h fspanelcontactsets.h fspanelface.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 74c5c756b2..e7004eb708 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -15156,6 +15156,19 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 + + BackupInventoryFlags + + Comment + Store the flags for Show In/New/Gesture inventory + Persist + 1 + Type + S32 + Value + 0 + + ShowObjectUpdates Comment diff --git a/indra/newview/fsnewitemctrl.cpp b/indra/newview/fsnewitemctrl.cpp new file mode 100644 index 0000000000..fb9c25ac9f --- /dev/null +++ b/indra/newview/fsnewitemctrl.cpp @@ -0,0 +1,274 @@ +/** + * @file fsnewitemctrl.cpp + * @brief A singleton controller for handling adding new items to Objects using Build Window's Content tab. + * + * $LicenseInfo:firstyear=2026&license=viewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (c) 2026 minerjr @ The Phoenix Firestorm Project, 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 + * $/LicenseInfo$ + */ + +// [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + +#include "fsnewitemctrl.h" +#include "llinventory.h" +#include "llviewerinventory.h" +#include "llselectmgr.h" +#include "llcontrol.h" // gSavedSettings +#include "llinventorymodel.h" // gInventory +#include "llagentdata.h" // gAgentID + +extern LLControlGroup gSavedSettings; +extern LLInventoryModel gInventory; +extern LLUUID gAgentID; + +FSNewItemCtrl::FSNewItemCtrl() : LLSingleton(), + mState(EAddNewItemState::IDLE), + mItemAssetType(LLAssetType::AT_NONE), + mOriginalItemUUID(), + mNewItemUUID() +{ + +} + +FSNewItemCtrl::~FSNewItemCtrl() +{ + // delete Xxx; +} + +void FSNewItemCtrl::init() +{ + mState = EAddNewItemState::IDLE; + mItemAssetType = LLAssetType::AT_NONE; + mOriginalItemUUID.setNull(); + mNewItemUUID.setNull(); +} + +void FSNewItemCtrl::processStates(LLPanelObjectInventory* panel_object_inv) +{ + // Check if the passed in panel object inventory is valid, and if not, return + if (panel_object_inv == nullptr) + { + return; + } + + LLFolderView* folders = panel_object_inv->getRootFolder(); + + // Idle state, just return as there is nothing to process + if (mState == EAddNewItemState::IDLE) + { + return; + } + // Handle the start of the drag and drop the item from avatar inventory to the object's inventory + // wait until the inventory movement has finished before handling the item appearing in the inventory + else if (mState == EAddNewItemState::DND_INV_TO_OBJECT) + { + if (LLViewerObject* objectp = gObjectList.findObject(panel_object_inv->getTaskUUID())) + { + // If the inveotory is not pending and not dirty, then we want to move to the next step. + if (objectp && !objectp->isInventoryPending() && !objectp->isInventoryDirty()) + { + mState = EAddNewItemState::DND_INV_TO_OBJECT_DONE; + } + } + } + // Handles when the item appears, will select the new item and set it to rename. + // If the item is able to be opened, it will be opened. + else if (mState == EAddNewItemState::DND_INV_TO_OBJECT_DONE) + { + bool inventory_has_focus = panel_object_inv->hasInventory() && folders && gFocusMgr.childHasKeyboardFocus(folders); + + // Restore the show new inventory current settings + restoreInventoryFlags(); + + panel_object_inv->setFocusRoot(true); + + if (!mNewItemUUID.isNull()) + { + // Flag that item needs to be renamed, needs to be done once added to the actual folder. + LLFolderViewItem* current_item = panel_object_inv->getItemByID(mNewItemUUID); + if (current_item && folders) + { + // Set the found + folders->setSelection(current_item, true, inventory_has_focus); + // mFolders->requestArrange(); + folders->startRenamingSelectedItem(); + // If the item is a gesture, notecard, text or script, we need to re-open the item floater to allow floater to + // modify the object content's item and not the one generated in the avatar's inventory. + if (mItemAssetType == LLAssetType::AT_LSL_TEXT || mItemAssetType == LLAssetType::AT_NOTECARD || + mItemAssetType == LLAssetType::AT_GESTURE || mItemAssetType == LLAssetType::AT_MATERIAL) + { + current_item->openItem(); + } + } + } + // Turn off the do action + mState = EAddNewItemState::MOVE_INT_TO_TRASH_START; + } + else if (mState == EAddNewItemState::MOVE_INT_TO_TRASH_START) + { + // Once the object's inventory is done being processed, can switch back to the idle state + if (LLViewerObject* objectp = gObjectList.findObject(panel_object_inv->getTaskUUID())) + { + // If there is no original item (LSL scripts), can go back to normal + if (mOriginalItemUUID.isNull()) + { + onRemoveItemDone(); + } + // Else if the inveotory is not pending and not dirty, then we want to move to the next step. + else if (objectp && !objectp->isInventoryPending() && !objectp->isInventoryDirty()) + { + // Remove the original inventory item and do a callback to set the + // state to the next one once it finishes. + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(FSNewItemCtrl::onRemoveItemDone)); + remove_inventory_item(mOriginalItemUUID, cb); + // Set the state to the move iventory to trash, which will spin until the callback is triggered + mState = EAddNewItemState::MOVE_INT_TO_TRASH; + } + } + } + // No need to MOVE_INT_TO_TRASH as it's handled by the onRemoveItemDone callback method. +} + +// [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab +// static +// Callback method for when an item is removed from the avatar's inventory to reset the internal state +void FSNewItemCtrl::onRemoveItemDone() +{ + // Store the pointer to the FSNewItemCtrl as a static value as it is a singleton and + // saves from having to be called all the time. + static FSNewItemCtrl* self = FSNewItemCtrl::getInstance(); + if (self) + { + // Set the new item state back to idle + self->setState(FSNewItemCtrl::EAddNewItemState::IDLE); + self->callFinishNewItem(); + } +} + +// Call the Finish New Item callback method if it is valid. +void FSNewItemCtrl::callFinishNewItem() +{ + if (mFinishNewItemCallback) + mFinishNewItemCallback(); +} + +void FSNewItemCtrl::onCreateInvDone(LLHandle handle, const LLUUID& new_id, const void_callback_t& cb) +{ + gInventory.notifyObservers(); + LLPanelContents* panel = (LLPanelContents*)handle.get(); + + if (panel && new_id.notNull()) + { + // The the selected object's root object + const bool children_ok = true; + LLPointer object = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(children_ok); + + if (object && new_id.notNull()) + { + // Get the Inventory Item from the new ID passed in + LLViewerInventoryItem* item = gInventory.getItem(new_id); + if (item) + { + // If the item can move to the target object + if (LLToolDragAndDrop::isInventoryDropAcceptable(object, item)) + { + // Set the panel to treat the newest item as a new item and needs to perform an action on it. + startDNDInvToObject(item->getUUID(), cb); + // Drag and Drop the new item into the inventory of the object. + LLToolDragAndDrop::dropInventory(object, item, LLToolDragAndDrop::SOURCE_AGENT, gAgentID); + } + } + else + { + LL_WARNS() << "Could not transfer new item with ID: " << new_id << LL_ENDL; + } + } + } +} + +void FSNewItemCtrl::startDNDInvToObject(const LLUUID& original_UUID, const void_callback_t& cb) +{ + // Store the UUID of the original item drag and dropped by the script + // so once it is finished with, can then next move to the avatar's trash. + mOriginalItemUUID = original_UUID; + // Flag that an action needs to take place on the newest item + mState = EAddNewItemState::DND_INV_TO_OBJECT_START; + + // Set the finish new item callback to the one passed in, defaults to null. + mFinishNewItemCallback = cb; +} + +bool FSNewItemCtrl::checkAgainstLatestObject(const LLPointer &obj) +{ + // If there is a need to do an action on the item, then + if (mState == EAddNewItemState::DND_INV_TO_OBJECT_START) + { + // This is needed to be able to convert the LLPointer to an LLInventoryItem*. + // Issue is the existing methods ends up returning a const pointer, which you then cannnot + // act upon or return with a static method call. + LLInventoryObject* current_object = obj; + LLInventoryItem* current_item = dynamic_cast(current_object); + + // Need to search for the newest item as the new item recieved a new UUID so the one + // from the LLPanelContents.cpp no longer exists. + // Use the CreationDate of the item to determine which is the newer item. + if (current_item && current_item->getCreationDate() > mLatestCreationTime) + { + // Store the latest creation date + mLatestCreationTime = current_item->getCreationDate(); + // Store the current items new UUID and action type (for use to determine if the item needs to be opened) + mNewItemUUID = current_item->getUUID(); + mItemAssetType = current_item->getActualType(); + mLatestCreatedItem = current_item; + + // Return true as there was a newer item was found + return true; + } + } + // Return false as there was no newer item found + return false; +} + +// Store the show invengory flags and disables them. +// Used to hide the item floaters attached to the new avatar items +// so the user does not edit the wrong items. +void FSNewItemCtrl::saveAndClearInventoryFlags() +{ + // Save the show new, in and gesture inventory settings + S32 backup_inventory_flags = 0; + backup_inventory_flags |= S32(gSavedSettings.getBOOL("ShowNewInventory")) * SHOW_NEW_INVENTORY; + backup_inventory_flags |= S32(gSavedSettings.getBOOL("ShowInInventory")) * SHOW_IN_INVENTORY; + backup_inventory_flags |= S32(gSavedSettings.getBOOL("ShowGestureInventory")) * SHOW_GESTURE_INVENTORY; + gSavedSettings.setS32("BackupInventoryFlags", backup_inventory_flags); + + // do not pop up preview floaters when creating new and in inventory items. + gSavedSettings.setBOOL("ShowNewInventory", false); + gSavedSettings.setBOOL("ShowInInventory", false); + gSavedSettings.setBOOL("ShowGestureInventory", false); +} + +// Restores the Show Inventory settings.xml flags. +void FSNewItemCtrl::restoreInventoryFlags() +{ + // Restore the show new inventory current settings + S32 backup_inventory_flags = gSavedSettings.getS32("BackupInventoryFlags"); + gSavedSettings.setBOOL("ShowGestureInventory", bool(backup_inventory_flags & SHOW_GESTURE_INVENTORY)); + gSavedSettings.setBOOL("ShowNewInventory", bool(backup_inventory_flags & SHOW_NEW_INVENTORY)); + gSavedSettings.setBOOL("ShowInInventory", bool(backup_inventory_flags & SHOW_IN_INVENTORY)); +} +// [FIRE-36685] diff --git a/indra/newview/fsnewitemctrl.h b/indra/newview/fsnewitemctrl.h new file mode 100644 index 0000000000..97a477761e --- /dev/null +++ b/indra/newview/fsnewitemctrl.h @@ -0,0 +1,101 @@ +/** + * @file fsnewitemctrl.h + * @brief A singleton controller for handling adding new items to Objects using Build Window's Content tab. + * + * $LicenseInfo:firstyear=2026&license=viewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (c) 2026 minerjr @ The Phoenix Firestorm Project, 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 + * $/LicenseInfo$ + */ + +#ifndef FSNEWITEMCTRL_H +#define FSNEWITEMCTRL_H + +// [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + +#include "llsingleton.h" +#include "llpanelobjectinventory.h" + +class LLPanelContents; + +class FSNewItemCtrl : public LLSingleton +{ + LLSINGLETON(FSNewItemCtrl); + ~FSNewItemCtrl(); + +public: + enum EAddNewItemState + { + IDLE = 0, + DND_INV_TO_OBJECT_START, + DND_INV_TO_OBJECT, + DND_INV_TO_OBJECT_DONE, + MOVE_INT_TO_TRASH_START, + MOVE_INT_TO_TRASH, + MOVE_INT_TO_TRASH_DONE + }; + + static const S32 SHOW_NEW_INVENTORY = 1; + static const S32 SHOW_IN_INVENTORY = 2; + static const S32 SHOW_GESTURE_INVENTORY = 4; + + typedef std::function void_callback_t; + typedef std::function panel_contents_callback_t; + + void init(); + + void processStates(LLPanelObjectInventory* panel_object_inv); + static void onRemoveItemDone(); // Callback + void callFinishNewItem(); + // Used by the LLPanelContents to let this class to enable rename, sticky sort location + // and open the supported window if need be. + void onCreateInvDone(LLHandle handle, const LLUUID& new_id, const void_callback_t& cb = nullptr); + void startDNDInvToObject(const LLUUID& original_UUID, const void_callback_t& cb = nullptr); + void saveAndClearInventoryFlags(); // Saves the Show Inventory settings.xml flags and clears therm + void restoreInventoryFlags();// Restores the Show Inventory settings.xml flags. + + const LLUUID& getNewItemUUID() const { return mNewItemUUID; } + void setNewItemUUID(const LLUUID &new_uuid) { mNewItemUUID = new_uuid; } + + const LLUUID& getOriginalItemUUID() const { return mOriginalItemUUID; } + void setOriginalItemUUID(const LLUUID& new_uuid) { mOriginalItemUUID = new_uuid; } + + const LLAssetType::EType getItemAssetType() const { return mItemAssetType; } + void setItemAssetType(LLAssetType::EType new_type) { mItemAssetType = new_type; } + + EAddNewItemState getState() const { return mState; } + void setState(const EAddNewItemState new_state) { mState = new_state; } + bool checkState(const EAddNewItemState check_state) const { return mState == check_state; } + bool isStateIdle() const { return mState == EAddNewItemState::IDLE; } + + void resetLatestCreationTime() { mLatestCreationTime = 0; } + bool checkAgainstLatestObject(const LLPointer &obj); + + void setFinishNewItemCallback(void_callback_t cb) { mFinishNewItemCallback = cb; } + +protected: + + EAddNewItemState mState; // Flags if there is a item that needs an action performed on it. + LLAssetType::EType mItemAssetType; // Stores the action type of the new item, used for idenifying the idem. + LLUUID mOriginalItemUUID; // Stores the UUID of the item that was first passed to be transfered. UUID is changed when added to object's inventory + LLUUID mNewItemUUID; // The UUID will change when moved so that cannot be used for tracking which item needs to be acted upon. + time_t mLatestCreationTime; // Stores the latest creation time, used for finding the object with the latest version. + LLInventoryItem* mLatestCreatedItem; // Stores the pointer to the latest item found. + void_callback_t mFinishNewItemCallback; // Function pointer used as a callback for when the new item is finished. +}; +// [FIRE-36685] +#endif diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index a0621bb015..0c82d2b310 100644 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -31,6 +31,7 @@ #include "llinventorypanel.h" #include "lltooldraganddrop.h" #include "llfavoritesbar.h" +#include "fsnewitemctrl.h" // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab // // class LLFolderViewModelInventory @@ -333,6 +334,24 @@ bool LLFolderViewModelItemInventory::filter(LLFolderViewFilter& filter) bool LLInventorySort::operator()(const LLFolderViewModelItemInventory* const& a, const LLFolderViewModelItemInventory* const& b) const { + // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + // Store a static pointer to the singleton FSNewItemCtrl so that it only has to be looked up once. + static FSNewItemCtrl* new_item_ctrl = FSNewItemCtrl::getInstance(); + // When new items are created with the Build Widow, want the new item to appear at + // the top of the list so the user can edit the name. + // Stores the UUID of the new item as a static value in the LLPanelObjectInventory. + if (!new_item_ctrl->getNewItemUUID().isNull()) + { + if (a->getUUID() == new_item_ctrl->getNewItemUUID()) + { + return true; + } + else if (b->getUUID() == new_item_ctrl->getNewItemUUID()) + { + return false; + } + } + // [FIRE-36685] // Ignore sort order for landmarks in the Favorites folder. // In that folder, landmarks should be always sorted as in the Favorites bar. See EXT-719 if (a->getSortGroup() == SG_ITEM diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index 227216705e..93cb9b9aa5 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -67,6 +67,7 @@ #include "rlvhandler.h" #include "rlvlocks.h" // [/RLVa:KB] +#include "fsnewitemctrl.h" // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab // // Imported globals @@ -89,6 +90,7 @@ bool LLPanelContents::postBuild() setMouseOpaque(false); childSetAction("button new script",&LLPanelContents::onClickNewScript, this); + childSetAction("button new notecard", &LLPanelContents::onClickNewNotecard, this); // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab childSetAction("button permissions",&LLPanelContents::onClickPermissions, this); childSetAction("btn_reset_scripts", &LLPanelContents::onClickResetScripts, this); // Script reset in edit floater childSetAction("button refresh",&LLPanelContents::onClickRefresh, this); @@ -123,6 +125,13 @@ void LLPanelContents::getState(LLViewerObject *objectp ) { getChildView("button new script")->setEnabled(false); getChildView("btn_reset_scripts")->setEnabled(false); // Script reset in edit floater + // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + getChildView("button new notecard")->setEnabled(false); + // Store a static pointer to the singleton FSNewItemCtrl so that it only has to be looked up once. + static FSNewItemCtrl* new_item_ctrl = FSNewItemCtrl::getInstance(); + // Want to clear the saved New Item UUID as we may click on another object + new_item_ctrl->setNewItemUUID(LLUUID::null); + // [FIRE-36685] return; } @@ -169,6 +178,7 @@ void LLPanelContents::getState(LLViewerObject *objectp ) } getChildView("button new script")->setEnabled(objectIsOK); + getChildView("button new notecard")->setEnabled(objectIsOK); // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab getChildView("btn_reset_scripts")->setEnabled(objectIsOK); // @@ -263,6 +273,12 @@ void LLPanelContents::clearContents() // static void LLPanelContents::onClickNewScript(void *userdata) { + // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + // Store a static pointer to the singleton FSNewItemCtrl so that it only has to be looked up once. + static FSNewItemCtrl* new_item_ctrl = FSNewItemCtrl::getInstance(); + // Get the Panel Contents from the userdata void pointer. + LLPanelContents* self = (LLPanelContents*)userdata; + // [FIRE-36685] const bool children_ok = true; LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(children_ok); if(object) @@ -289,6 +305,10 @@ void LLPanelContents::onClickNewScript(void *userdata) { if (auto custom_script = gInventory.getItem(custom_script_id); custom_script && custom_script->getType() == LLAssetType::AT_LSL_TEXT) { + // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + // Flag the new script to also needs to be scrolled to and opened if needed. + new_item_ctrl->startDNDInvToObject(LLUUID::null, std::bind(&LLPanelContents::onFinishCreateItem, self)); + // [FIRE-36685] LLToolDragAndDrop::dropScript(object, custom_script, true, LLToolDragAndDrop::SOURCE_AGENT, gAgentID); return; } @@ -308,6 +328,10 @@ void LLPanelContents::onClickNewScript(void *userdata) PERM_MOVE | LLFloaterPerms::getNextOwnerPerms("Scripts")); std::string desc; LLViewerAssetType::generateDescriptionFor(LLAssetType::AT_LSL_TEXT, desc); + // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + // Flag the new script to also needs to be scrolled to and opened if needed. + new_item_ctrl->startDNDInvToObject(LLUUID::null, std::bind(&LLPanelContents::onFinishCreateItem, self)); + // [FIRE-36685] LLPointer new_item = new LLViewerInventoryItem( LLUUID::null, @@ -355,3 +379,70 @@ void LLPanelContents::onClickRefresh(void *userdata) LLPanelContents* self = (LLPanelContents*)userdata; self->refresh(); } + +// [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab +// static +void LLPanelContents::onClickNewNotecard(void* userdata) +{ + // Store a static pointer to the singleton FSNewItemCtrl so that it only has to be looked up once. + static FSNewItemCtrl* new_item_ctrl = FSNewItemCtrl::getInstance(); + // Get the Panel Contents from the userdata void pointer. + LLPanelContents* self = (LLPanelContents*)userdata; + // Maintain RLV support for notecard object type being added. + const bool children_ok = true; + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(children_ok); + + // [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a + if (rlv_handler_t::isEnabled()) // Fallback code [see LLPanelContents::getState()] + { + if (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) + { + return; // Disallow creating new scripts in a locked attachment + } + else if ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) + { + if ((isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit())) + return; // .. or in a linkset the avie is sitting on under @unsit=n/@sittp=n + } + } + // [/RLVa:KB] + + // Need to disable the new notecard button to prevent spaming the button and causing inventory issues + self->getChildView("button new notecard")->setEnabled(false); + // Need to save the filter first so it is not lost + std::string save_filter = self->mFilterEditor->getText(); + // Clear the actual filter + self->mFilterEditor->setText(LLStringExplicit("")); + // Update the filter state + self->onFilterEdit(); + // + // Create the LLSD paramater for the new notecard + LLSD component("notecard"); + + // Callback handle to allow for moving the new item to the object from the avatar inventory + // Also moves the new item in the users avatar inventory to the trash. + // Will also open up the dialog for Gesture and Notecards in the object's inventory. + LLHandle handle = self->getHandle(); + std::function callback_item_created = [handle](const LLUUID& new_id) + { + // Call the on Create Inventory Done of the new item controller which will kick off next steps + new_item_ctrl->onCreateInvDone(handle, new_id, std::bind(&LLPanelContents::onFinishCreateItem, (LLPanelContents*)handle.get())); + }; + + // Save and clear the Show Inventroy flags used to prevent the floaters appearing + // when items that have floaters like the Notecard, Gesture, Material and Script + // from opening the temp item in the avatars inventory. + new_item_ctrl->saveAndClearInventoryFlags(); + // Create the new item using the menu system in the user's avatar inventory. + // The callback from above will move the item to the object and remove it from the user's inventory after. + menu_create_inventory_item(NULL, LLUUID::null, component, LLUUID::null, callback_item_created); + // Restore the filter + self->mFilterEditor->setText(LLStringExplicit(save_filter)); +} + +// Callback method for when the item finishes +void LLPanelContents::onFinishCreateItem() +{ + getChildView("button new notecard")->setEnabled(true); +} +// [FIRE-36685] diff --git a/indra/newview/llpanelcontents.h b/indra/newview/llpanelcontents.h index 0398b06a62..7a2c52abb4 100644 --- a/indra/newview/llpanelcontents.h +++ b/indra/newview/llpanelcontents.h @@ -51,8 +51,13 @@ public: void refresh(); void clearContents(); + // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + void onClickAddItemToObject(); // Adds the actual item to the object's Content Inventory. + void onFinishCreateItem(); + // [FIRE-36685] static void onClickNewScript(void*); + static void onClickNewNotecard(void*); // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab static void onClickPermissions(void*); static void onClickResetScripts(void*); // Script reset in edit floater static void onClickRefresh(void*); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index bfec658fa4..e29611fb7f 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -73,6 +73,7 @@ #include "rlvlocks.h" // [/RLVa:KB] #include "llfloaterproperties.h" // Keep legacy properties floater +#include "fsnewitemctrl.h" // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab const LLColor4U DEFAULT_WHITE(255, 255, 255); #include "tea.h" // @@ -1797,6 +1798,12 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li { LLUIColor item_color = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE); + // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + // Store a static pointer to the singleton FSNewItemCtrl so that it only has to be looked up once. + static FSNewItemCtrl* new_item_ctrl = FSNewItemCtrl::getInstance(); + // Reset the latest creation time, to allow for finding the newest item below. + new_item_ctrl->resetLatestCreationTime(); + // [FIRE-36685] // Find all in the first pass std::vector child_categories; for (const LLPointer& obj : *inventory) @@ -1850,6 +1857,10 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li // view = LLUICtrlFactory::create(params); + // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + // Check the current object against the existing newest item + new_item_ctrl->checkAgainstLatestObject(obj); + // [FIRE-36685] } view->addToFolder(folder); @@ -1865,6 +1876,15 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li delete pair; } folder->setChildrenInited(true); + // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + // Switch to the next state if not already done so. + // Check to see if the new item control is in the drag and drop inventory to object start state + if (new_item_ctrl->checkState(FSNewItemCtrl::DND_INV_TO_OBJECT_START)) + { + // If so, can move on to the next state + new_item_ctrl->setState(FSNewItemCtrl::DND_INV_TO_OBJECT); + } + // [FIRE-36685] } void LLPanelObjectInventory::refresh() @@ -2028,6 +2048,12 @@ void LLPanelObjectInventory::idle(void* user_data) { self->updateInventory(); } + // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + // Store a static pointer to the singleton FSNewItemCtrl so that it only has to be looked up once. + static FSNewItemCtrl* new_item_ctrl = FSNewItemCtrl::getInstance(); + // Process the current state using the current LLPanelObjectInveotory + new_item_ctrl->processStates(self); + // [FIRE-36685] } void LLPanelObjectInventory::onFocusLost() diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h index c2141a0d42..0f3dcc57f9 100644 --- a/indra/newview/llpanelobjectinventory.h +++ b/indra/newview/llpanelobjectinventory.h @@ -47,6 +47,9 @@ class LLViewerObject; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener { + // [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab + friend class FSNewItemCtrl; // Need to declare FSNewItemCtrl a friend class to access the protected methods(getItemByID()) + // [FIRE-36685] public: struct Params : public LLInitParam::Block { diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 271b4a5e4d..70119929bf 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -3689,7 +3689,7 @@ Low ↔ Lwst width="295">