From 00462c243116e2720acf51ee1f777e69e8189f33 Mon Sep 17 00:00:00 2001 From: Mike Antipov Date: Thu, 8 Apr 2010 12:07:58 +0300 Subject: Fixed normal bug EXT-4347 (Moving object contents to inventory opens files, changes menu) Implementation details: * Added new LLViewerInventoryMoveFromWorldObserver to watch moved items via their Asses UUIDs. It is instantiated only once due to drop events are sent separately for each item while multi-dragging. * Existent LLOpenTaskOffer observer uses it to exclude watched by LLViewerInventoryMoveFromWorldObserver items from own processing. * Removed dependancy on LLPanelPlaces in open_inventory_offer(). Openning of offered LM via group notice moved into an appropriate section (processed by LLOpenTaskGroupOffer) Known Issues: * If Script item is among the dragged items from object to inventory it will be the only selected item in the inventory panel. Reason: it does not have its own Asset UUID and processed via LLOpenTaskOffer when should not. Reviewed by Leyla and Richard at https://codereview.productengine.com/secondlife/r/116/ --HG-- branch : product-engine --- indra/newview/llinventorybridge.cpp | 3 + indra/newview/llinventoryobserver.cpp | 63 ++++++++++ indra/newview/llinventoryobserver.h | 30 +++++ indra/newview/llviewermessage.cpp | 212 ++++++++++++++++++++++++++++++---- indra/newview/llviewermessage.h | 2 + 5 files changed, 285 insertions(+), 25 deletions(-) (limited to 'indra') diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index b552b5ac07..943a851c13 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -3167,6 +3167,9 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } else { + // store dad inventory item to select added one later. See EXT-4347 + set_dad_inventory_item(inv_item, mUUID); + LLNotification::Params params("MoveInventoryFromObject"); params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); LLNotifications::instance().forceResponse(params, 0); diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 83e1bbd5a0..922fcc16c0 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -495,6 +495,69 @@ void LLInventoryExistenceObserver::changed(U32 mask) } } +void LLInventoryMoveFromWorldObserver::changed(U32 mask) +{ + if(!(mask & LLInventoryObserver::ADD)) + { + return; + } + + // nothing is watched + if (mWatchedAssets.size() == 0) + { + return; + } + + LLPointer item = new LLViewerInventoryItem; + LLMessageSystem* msg = gMessageSystem; + S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + for(S32 i = 0; i < num_blocks; ++i) + { + item->unpackMessage(msg, _PREHASH_InventoryData, i); + const LLUUID& asset_uuid = item->getAssetUUID(); + if (item->getUUID().notNull() && asset_uuid.notNull()) + { + if (isAssetWatched(asset_uuid)) + { + LL_DEBUGS("Inventory_Move") << "Found asset UUID: " << asset_uuid << LL_ENDL; + mAddedItems.push_back(item->getUUID()); + } + } + } + + if (mAddedItems.size() == mWatchedAssets.size()) + { + done(); + LL_DEBUGS("Inventory_Move") << "All watched items are added & processed." << LL_ENDL; + mAddedItems.clear(); + + // Unable to clean watched items here due to somebody can require to check them in current frame. + // set dirty state to clean them while next watch cycle. + mIsDirty = true; + } +} + +void LLInventoryMoveFromWorldObserver::watchAsset(const LLUUID& asset_id) +{ + if(asset_id.notNull()) + { + if (mIsDirty) + { + LL_DEBUGS("Inventory_Move") << "Watched items are dirty. Clean them." << LL_ENDL; + mWatchedAssets.clear(); + mIsDirty = false; + } + + mWatchedAssets.push_back(asset_id); + onAssetAdded(asset_id); + } +} + +bool LLInventoryMoveFromWorldObserver::isAssetWatched( const LLUUID& asset_id ) +{ + return std::find(mWatchedAssets.begin(), mWatchedAssets.end(), asset_id) != mWatchedAssets.end(); +} + void LLInventoryAddedObserver::changed(U32 mask) { if(!(mask & LLInventoryObserver::ADD)) diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index ba70552ebc..b710a9d326 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -193,6 +193,36 @@ protected: uuid_vec_t mMIA; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryMovedObserver +// +// This class is used as a base class for doing something when all the +// item for observed asset ids were added into the inventory. +// Derive a class from this class and implement the done() method to do +// something useful. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryMoveFromWorldObserver : public LLInventoryObserver +{ +public: + LLInventoryMoveFromWorldObserver() : mIsDirty(false) {} + virtual void changed(U32 mask); + + void watchAsset(const LLUUID& asset_id); + bool isAssetWatched(const LLUUID& asset_id); + +protected: + virtual void onAssetAdded(const LLUUID& asset_id) {} + virtual void done() = 0; + + typedef std::vector item_ref_t; + item_ref_t mAddedItems; + item_ref_t mWatchedAssets; + +private: + bool mIsDirty; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryAddedObserver // diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index c542459cdb..2b41a83ba5 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -71,7 +71,6 @@ #include "llnotifications.h" #include "llnotificationsutil.h" #include "llpanelgrouplandmoney.h" -#include "llpanelplaces.h" #include "llrecentpeople.h" #include "llscriptfloater.h" #include "llselectmgr.h" @@ -692,6 +691,52 @@ bool join_group_response(const LLSD& notification, const LLSD& response) return false; } + +static void highlight_inventory_items_in_panel(const std::vector& items, LLInventoryPanel *inventory_panel) +{ + if (NULL == inventory_panel) return; + + for (std::vector::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) + { + const LLUUID& item_id = (*item_iter); + if(!highlight_offered_item(item_id)) + { + continue; + } + + LLInventoryItem* item = gInventory.getItem(item_id); + llassert(item); + if (!item) { + continue; + } + + LL_DEBUGS("Inventory_Move") << "Highlighting inventory item: " << item->getName() << ", " << item_id << LL_ENDL; + LLFolderView* fv = inventory_panel->getRootFolder(); + if (fv) + { + LLFolderViewItem* fv_item = fv->getItemByID(item_id); + if (fv_item) + { + LLFolderViewItem* fv_folder = fv_item->getParentFolder(); + if (fv_folder) + { + // Parent folders can be different in case of 2 consecutive drag and drop + // operations when the second one is started before the first one completes. + LL_DEBUGS("Inventory_Move") << "Open folder: " << fv_folder->getName() << LL_ENDL; + fv_folder->setOpen(TRUE); + if (fv_folder->isSelected()) + { + fv->changeSelection(fv_folder, FALSE); + } + } + fv->changeSelection(fv_item, TRUE); + } + } + } +} + static LLNotificationFunctorRegistration jgr_1("JoinGroup", join_group_response); static LLNotificationFunctorRegistration jgr_2("JoinedTooManyGroupsMember", join_group_response); static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_response); @@ -714,6 +759,108 @@ private: std::string mFromName; }; +/** + * Class to observe adding of new items moved from the world to user's inventory to select them in inventory. + * + * We can't create it each time items are moved because "drop" event is sent separately for each + * element even while multi-dragging. We have to have the only instance of the observer. See EXT-4347. + */ +class LLViewerInventoryMoveFromWorldObserver : public LLInventoryMoveFromWorldObserver +{ +public: + LLViewerInventoryMoveFromWorldObserver() + : LLInventoryMoveFromWorldObserver() + , mActivePanel(NULL) + { + + } + + void setMoveIntoFolderID(const LLUUID& into_folder_uuid) {mMoveIntoFolderID = into_folder_uuid; } + +private: + /*virtual */void onAssetAdded(const LLUUID& asset_id) + { + // Store active Inventory panel. + mActivePanel = LLInventoryPanel::getActiveInventoryPanel(); + + // Store selected items (without destination folder) + mSelectedItems.clear(); + mActivePanel->getRootFolder()->getSelectionList(mSelectedItems); + mSelectedItems.erase(mMoveIntoFolderID); + } + + /** + * Selects added inventory items watched by their Asset UUIDs if selection was not changed since + * all items were started to watch (dropped into a folder). + */ + void done() + { + // if selection is not changed since watch started lets hightlight new items. + if (mActivePanel && !isSelectionChanged()) + { + LL_DEBUGS("Inventory_Move") << "Selecting new items..." << LL_ENDL; + mActivePanel->clearSelection(); + highlight_inventory_items_in_panel(mAddedItems, mActivePanel); + } + } + + /** + * Returns true if selected inventory items were changed since moved inventory items were started to watch. + */ + bool isSelectionChanged() + { + const LLInventoryPanel * const current_active_panel = LLInventoryPanel::getActiveInventoryPanel(); + + if (NULL == mActivePanel || current_active_panel != mActivePanel) + { + return true; + } + + // get selected items (without destination folder) + selected_items_t selected_items; + mActivePanel->getRootFolder()->getSelectionList(selected_items); + selected_items.erase(mMoveIntoFolderID); + + // compare stored & current sets of selected items + selected_items_t different_items; + std::set_symmetric_difference(mSelectedItems.begin(), mSelectedItems.end(), + selected_items.begin(), selected_items.end(), std::inserter(different_items, different_items.begin())); + + LL_DEBUGS("Inventory_Move") << "Selected firstly: " << mSelectedItems.size() + << ", now: " << selected_items.size() << ", difference: " << different_items.size() << LL_ENDL; + + return different_items.size() > 0; + } + + LLInventoryPanel *mActivePanel; + typedef std::set selected_items_t; + selected_items_t mSelectedItems; + + /** + * UUID of FolderViewFolder into which watched items are moved. + * + * Destination FolderViewFolder becomes selected while mouse hovering (when dragged items are dropped). + * + * If mouse is moved out it set unselected and number of selected items is changed + * even if selected items in Inventory stay the same. + * So, it is used to update stored selection list. + * + * @see onAssetAdded() + * @see isSelectionChanged() + */ + LLUUID mMoveIntoFolderID; +}; + +LLViewerInventoryMoveFromWorldObserver* gInventoryMoveObserver = NULL; + +void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid) +{ + start_new_inventory_observer(); + + gInventoryMoveObserver->setMoveIntoFolderID(into_folder_uuid); + gInventoryMoveObserver->watchAsset(inv_item->getAssetUUID()); +} + //unlike the FetchObserver for AgentOffer, we only make one //instance of the AddedObserver for TaskOffers //and it never dies. We do this because we don't know the UUID of @@ -724,6 +871,33 @@ class LLOpenTaskOffer : public LLInventoryAddedObserver protected: /*virtual*/ void done() { + for (uuid_vec_t::iterator it = mAdded.begin(); it != mAdded.end();) + { + const LLUUID& item_uuid = *it; + bool was_moved = false; + LLInventoryObject* added_object = gInventory.getObject(item_uuid); + if (added_object) + { + // cast to item to get Asset UUID + LLInventoryItem* added_item = dynamic_cast(added_object); + if (added_item) + { + const LLUUID& asset_uuid = added_item->getAssetUUID(); + if (gInventoryMoveObserver->isAssetWatched(asset_uuid)) + { + LL_DEBUGS("Inventory_Move") << "Found asset UUID: " << asset_uuid << LL_ENDL; + was_moved = true; + } + } + } + + if (was_moved) + { + it = mAdded.erase(it); + } + else ++it; + } + open_inventory_offer(mAdded, ""); mAdded.clear(); } @@ -752,6 +926,13 @@ void start_new_inventory_observer() gNewInventoryObserver = new LLOpenTaskOffer; gInventory.addObserver(gNewInventoryObserver); } + + if (!gInventoryMoveObserver) //inventory move from the world observer + { + // Observer is deleted by gInventory + gInventoryMoveObserver = new LLViewerInventoryMoveFromWorldObserver; + gInventory.addObserver(gInventoryMoveObserver); + } } class LLDiscardAgentOffer : public LLInventoryFetchComboObserver @@ -916,9 +1097,12 @@ void open_inventory_offer(const uuid_vec_t& items, const std::string& from_name) } else if("group_offer" == from_name) { - // do not open inventory when we open group notice attachment because - // we already opened landmark info panel // "group_offer" is passed by LLOpenTaskGroupOffer + // Notification about added landmark will be generated under the "from_name.empty()" called from LLOpenTaskOffer::done(). + LLSD args; + args["type"] = "landmark"; + args["id"] = item_id; + LLSideTray::getInstance()->showPanel("panel_places", args); continue; } @@ -929,28 +1113,6 @@ void open_inventory_offer(const uuid_vec_t& items, const std::string& from_name) args["LANDMARK_NAME"] = item->getName(); args["FOLDER_NAME"] = std::string(parent_folder ? parent_folder->getName() : "unknown"); LLNotificationsUtil::add("LandmarkCreated", args); - // Created landmark is passed to Places panel to allow its editing. In fact panel should be already displayed. - // If the panel is closed we don't reopen it until created landmark is loaded. - //TODO*:: dserduk(7/12/09) remove LLPanelPlaces dependency from here - LLPanelPlaces *places_panel = dynamic_cast(LLSideTray::getInstance()->getPanel("panel_places")); - if (places_panel) - { - // Landmark creation handling is moved to LLPanelPlaces::showAddedLandmarkInfo() - // TODO* LLPanelPlaces dependency is going to be removed. See EXT-4347. - //if("create_landmark" == places_panel->getPlaceInfoType() && !places_panel->getItem()) - //{ - // places_panel->setItem(item); - //} - //else - // we are opening a group notice attachment - if("create_landmark" != places_panel->getPlaceInfoType()) - { - LLSD args; - args["type"] = "landmark"; - args["id"] = item_id; - LLSideTray::getInstance()->showPanel("panel_places", args); - } - } } } break; diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index 4015cca77b..7c021dc05f 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -208,6 +208,8 @@ void open_inventory_offer(const uuid_vec_t& items, const std::string& from_name) // Returns false if item is not found. bool highlight_offered_item(const LLUUID& item_id); +void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid); + struct LLOfferInfo { LLOfferInfo() -- cgit v1.2.3 From 5c1563e2cbee162de52cee321edb8148016865ba Mon Sep 17 00:00:00 2001 From: Dmitry Zaporozhan Date: Thu, 8 Apr 2010 11:46:40 +0300 Subject: (final part) EXT-6564(major) - Fix wearable editing panels Updated Parameter panel: - removed hard coded values - improved panel layout Reviewed by Mike Antipov, Neal Orman - https://codereview.productengine.com/secondlife/r/157/ --HG-- branch : product-engine --- indra/newview/llscrollingpanelparam.cpp | 30 ++++++------- indra/newview/llscrollingpanelparam.h | 5 --- .../skins/default/xui/en/panel_scrolling_param.xml | 51 +++++++++++----------- 3 files changed, 41 insertions(+), 45 deletions(-) (limited to 'indra') diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp index 7980fe1945..a5518d87d4 100644 --- a/indra/newview/llscrollingpanelparam.cpp +++ b/indra/newview/llscrollingpanelparam.cpp @@ -42,17 +42,14 @@ #include "llbutton.h" #include "llsliderctrl.h" #include "llagent.h" +#include "llviewborder.h" #include "llvoavatarself.h" // Constants for LLPanelVisualParam const F32 LLScrollingPanelParam::PARAM_STEP_TIME_THRESHOLD = 0.25f; -const S32 LLScrollingPanelParam::BTN_BORDER = 2; const S32 LLScrollingPanelParam::PARAM_HINT_WIDTH = 128; const S32 LLScrollingPanelParam::PARAM_HINT_HEIGHT = 128; -const S32 LLScrollingPanelParam::PARAM_HINT_LABEL_HEIGHT = 16; -const S32 LLScrollingPanelParam::PARAM_PANEL_WIDTH = 2 * (3* BTN_BORDER + PARAM_HINT_WIDTH + LLPANEL_BORDER_WIDTH); -const S32 LLScrollingPanelParam::PARAM_PANEL_HEIGHT = 2 * BTN_BORDER + PARAM_HINT_HEIGHT + PARAM_HINT_LABEL_HEIGHT + 4 * LLPANEL_BORDER_WIDTH; // LLScrollingPanelParam //static @@ -67,14 +64,17 @@ LLScrollingPanelParam::LLScrollingPanelParam( const LLPanel::Params& panel_param { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_scrolling_param.xml"); + // *HACK To avoid hard coding texture position, lets use border's position for texture. + LLViewBorder* left_border = getChild("left_border"); + static LLUICachedControl slider_ctrl_height ("UISliderctrlHeight", 0); - S32 pos_x = 2 * LLPANEL_BORDER_WIDTH; - S32 pos_y = 3 * LLPANEL_BORDER_WIDTH + slider_ctrl_height; + S32 pos_x = left_border->getRect().mLeft + left_border->getBorderWidth(); + S32 pos_y = left_border->getRect().mBottom + left_border->getBorderWidth(); F32 min_weight = param->getMinWeight(); F32 max_weight = param->getMaxWeight(); mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, (LLViewerVisualParam*) wearable->getVisualParam(param->getID()), min_weight); - pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER; + pos_x = getChild("right_border")->getRect().mLeft + left_border->getBorderWidth(); mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, (LLViewerVisualParam*) wearable->getVisualParam(param->getID()), max_weight ); mHintMin->setAllowsUpdates( FALSE ); @@ -162,6 +162,10 @@ void LLScrollingPanelParam::draw() childSetVisible("less", mHintMin->getVisible()); childSetVisible("more", mHintMax->getVisible()); + // hide borders if texture has been loaded + childSetVisible("left_border", !mHintMin->getVisible()); + childSetVisible("right_border", !mHintMax->getVisible()); + // Draw all the children except for the labels childSetVisible( "min param text", FALSE ); childSetVisible( "max param text", FALSE ); @@ -171,9 +175,7 @@ void LLScrollingPanelParam::draw() gGL.pushUIMatrix(); { const LLRect& r = mHintMin->getRect(); - F32 left = (F32)(r.mLeft + BTN_BORDER); - F32 bot = (F32)(r.mBottom + BTN_BORDER); - gGL.translateUI(left, bot, 0.f); + gGL.translateUI((F32)r.mLeft, (F32)r.mBottom, 0.f); mHintMin->draw(); } gGL.popUIMatrix(); @@ -181,9 +183,7 @@ void LLScrollingPanelParam::draw() gGL.pushUIMatrix(); { const LLRect& r = mHintMax->getRect(); - F32 left = (F32)(r.mLeft + BTN_BORDER); - F32 bot = (F32)(r.mBottom + BTN_BORDER); - gGL.translateUI(left, bot, 0.f); + gGL.translateUI((F32)r.mLeft, (F32)r.mBottom, 0.f); mHintMax->draw(); } gGL.popUIMatrix(); @@ -191,10 +191,10 @@ void LLScrollingPanelParam::draw() // Draw labels on top of the buttons childSetVisible( "min param text", TRUE ); - drawChild(getChild("min param text"), BTN_BORDER, BTN_BORDER); + drawChild(getChild("min param text")); childSetVisible( "max param text", TRUE ); - drawChild(getChild("max param text"), BTN_BORDER, BTN_BORDER); + drawChild(getChild("max param text")); } // static diff --git a/indra/newview/llscrollingpanelparam.h b/indra/newview/llscrollingpanelparam.h index 8c5db64816..fe4ce07166 100644 --- a/indra/newview/llscrollingpanelparam.h +++ b/indra/newview/llscrollingpanelparam.h @@ -75,13 +75,8 @@ public: // Constants for LLPanelVisualParam const static F32 PARAM_STEP_TIME_THRESHOLD; - const static S32 BTN_BORDER; const static S32 PARAM_HINT_WIDTH; const static S32 PARAM_HINT_HEIGHT; - const static S32 PARAM_HINT_LABEL_HEIGHT; - const static S32 PARAM_PANEL_WIDTH; - const static S32 PARAM_PANEL_HEIGHT; - public: LLViewerVisualParam* mParam; diff --git a/indra/newview/skins/default/xui/en/panel_scrolling_param.xml b/indra/newview/skins/default/xui/en/panel_scrolling_param.xml index f9c86fc75b..8042563900 100644 --- a/indra/newview/skins/default/xui/en/panel_scrolling_param.xml +++ b/indra/newview/skins/default/xui/en/panel_scrolling_param.xml @@ -1,6 +1,6 @@ + top="120" + width="120" /> + width="120" /> @@ -40,7 +40,7 @@ follows="left|top" height="16" layout="topleft" - left_pad="6" + left="155" name="Loading...2" top_delta="0" width="128"> @@ -49,30 +49,30 @@ @@ -84,10 +84,10 @@ image_selected="PushButton_Selected" image_unselected="PushButton_Off" layout="topleft" - left="2" + left="7" name="less" tab_stop="false" - top="0" + top="5" width="132" />