From 50eb27a04d193ef145f8879e12d8a82089a66891 Mon Sep 17 00:00:00 2001 From: Alexei Arabadji Date: Tue, 8 Jun 2010 15:36:48 +0300 Subject: EXT-7644 FIXED Implemented functionality for locking outfit modification controls and used it for 'save outfit' action. 1 Added functionality for locking outfit in LLAppearanceMgr. Outfit should be locked when outfit related operation is started(now it is used for updateBaseOutfit) and unlocked when operation completed or timeout is exceeded. 2 Added outfit saved and outfit lock changed signals to LLOutfitObserver. 3 Updated LLPanelOutfitsInventory and LLPanelOutfitEdit with functionality of controlling 'save outfit' controls state('save outfit' controls should be enabled only if outfit isn't locked and outfit is dirty). 4 Renamed action label of method LLPanelOutfitsInventory::isActionEnabled "make_outfit" to "save_outfit". --HG-- branch : product-engine --- indra/newview/app_settings/settings.xml | 11 +++++ indra/newview/llappearancemgr.cpp | 67 +++++++++++++++++++++++++++++++ indra/newview/llappearancemgr.h | 14 +++++++ indra/newview/lloutfitobserver.cpp | 15 ++++++- indra/newview/lloutfitobserver.h | 14 +++++++ indra/newview/llpaneloutfitedit.cpp | 6 ++- indra/newview/llpaneloutfitsinventory.cpp | 10 +++-- 7 files changed, 130 insertions(+), 7 deletions(-) (limited to 'indra') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 864a79c38a..52e987dac9 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -11417,5 +11417,16 @@ Value 1 + OutfitOperationsTimeout + + Comment + Timeout for outfit related operations. + Persist + 1 + Type + S32 + Value + 180 + diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index a899926938..135629bb8d 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -38,11 +38,13 @@ #include "llagentwearables.h" #include "llappearancemgr.h" #include "llcommandhandler.h" +#include "lleventtimer.h" #include "llgesturemgr.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" #include "llinventoryobserver.h" #include "llnotificationsutil.h" +#include "lloutfitobserver.h" #include "llpaneloutfitsinventory.h" #include "llselectmgr.h" #include "llsidepanelappearance.h" @@ -55,6 +57,34 @@ char ORDER_NUMBER_SEPARATOR('@'); +class LLOutfitUnLockTimer: public LLEventTimer +{ +public: + LLOutfitUnLockTimer(F32 period) : LLEventTimer(period) + { + // restart timer on BOF changed event + LLOutfitObserver::instance().addBOFChangedCallback(boost::bind( + &LLOutfitUnLockTimer::reset, this)); + stop(); + } + + /*virtual*/ + BOOL tick() + { + if(mEventTimer.hasExpired()) + { + LLAppearanceMgr::instance().setOutfitLocked(false); + } + return FALSE; + } + void stop() { mEventTimer.stop(); } + void start() { mEventTimer.start(); } + void reset() { mEventTimer.reset(); } + BOOL getStarted() { return mEventTimer.getStarted(); } + + LLTimer& getEventTimer() { return mEventTimer;} +}; + // support for secondlife:///app/appearance SLapps class LLAppearanceHandler : public LLCommandHandler { @@ -762,6 +792,27 @@ void LLAppearanceMgr::onOutfitRename(const LLSD& notification, const LLSD& respo } } +void LLAppearanceMgr::setOutfitLocked(bool locked) +{ + if (mOutfitLocked == locked) + { + return; + } + + mOutfitLocked = locked; + if (locked) + { + mUnlockOutfitTimer->reset(); + mUnlockOutfitTimer->start(); + } + else + { + mUnlockOutfitTimer->stop(); + } + + LLOutfitObserver::instance().notifyOutfitLockChanged(); +} + void LLAppearanceMgr::addCategoryToCurrentOutfit(const LLUUID& cat_id) { LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); @@ -1810,6 +1861,14 @@ void LLAppearanceMgr::onFirstFullyVisible() bool LLAppearanceMgr::updateBaseOutfit() { + if (isOutfitLocked()) + { + // don't allow modify locked outfit + llassert(!isOutfitLocked()); + return false; + } + setOutfitLocked(true); + const LLUUID base_outfit_id = getBaseOutfitUUID(); if (base_outfit_id.isNull()) return false; @@ -2138,6 +2197,14 @@ LLAppearanceMgr::LLAppearanceMgr(): mAttachmentInvLinkEnabled(false), mOutfitIsDirty(false) { + LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); + + // unlock outfit on save operation completed + outfit_observer.addCOFSavedCallback(boost::bind( + &LLAppearanceMgr::setOutfitLocked, this, false)); + + mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32( + "OutfitOperationsTimeout"))); } LLAppearanceMgr::~LLAppearanceMgr() diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index f1beef5857..2227a43cd8 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -42,10 +42,12 @@ class LLWearable; class LLWearableHoldingPattern; class LLInventoryCallback; +class LLOutfitUnLockTimer; class LLAppearanceMgr: public LLSingleton { friend class LLSingleton; + friend class LLOutfitUnLockTimer; public: typedef std::vector wearables_by_type_t; @@ -162,6 +164,8 @@ public: // COF is processed if cat_id is not specified void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null); + bool isOutfitLocked() { return mOutfitLocked; } + protected: LLAppearanceMgr(); ~LLAppearanceMgr(); @@ -186,10 +190,20 @@ private: static void onOutfitRename(const LLSD& notification, const LLSD& response); + void setOutfitLocked(bool locked); + std::set mRegisteredAttachments; bool mAttachmentInvLinkEnabled; bool mOutfitIsDirty; + /** + * Lock for blocking operations on outfit until server reply or timeout exceed + * to avoid unsynchronized outfit state or performing duplicate operations. + */ + bool mOutfitLocked; + + std::auto_ptr mUnlockOutfitTimer; + ////////////////////////////////////////////////////////////////////////////////// // Item-specific convenience functions public: diff --git a/indra/newview/lloutfitobserver.cpp b/indra/newview/lloutfitobserver.cpp index 848b595613..5652a98981 100644 --- a/indra/newview/lloutfitobserver.cpp +++ b/indra/newview/lloutfitobserver.cpp @@ -56,9 +56,9 @@ void LLOutfitObserver::changed(U32 mask) if (!gInventory.isInventoryUsable()) return; - bool panel_updated = checkCOF(); + bool COF_changed = checkCOF(); - if (!panel_updated) + if (!COF_changed) { checkBaseOutfit(); } @@ -87,6 +87,7 @@ bool LLOutfitObserver::checkCOF() mCOFLastVersion = cof_version; + // dirtiness state should be updated before sending signal LLAppearanceMgr::getInstance()->updateIsDirty(); mCOFChanged(); @@ -120,6 +121,16 @@ void LLOutfitObserver::checkBaseOutfit() } LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); + // dirtiness state should be updated before sending signal app_mgr.updateIsDirty(); mBOFChanged(); + + if (mLastOutfitDirtiness != app_mgr.isOutfitDirty()) + { + if(!app_mgr.isOutfitDirty()) + { + mCOFSaved(); + } + mLastOutfitDirtiness = app_mgr.isOutfitDirty(); + } } diff --git a/indra/newview/lloutfitobserver.h b/indra/newview/lloutfitobserver.h index 4cb40ead15..a4b5fbe04a 100644 --- a/indra/newview/lloutfitobserver.h +++ b/indra/newview/lloutfitobserver.h @@ -48,6 +48,8 @@ public: virtual void changed(U32 mask); + void notifyOutfitLockChanged() { mOutfitLockChanged(); } + typedef boost::signals2::signal signal_t; void addBOFReplacedCallback(const signal_t::slot_type& cb) { mBOFReplaced.connect(cb); } @@ -56,6 +58,10 @@ public: void addCOFChangedCallback(const signal_t::slot_type& cb) { mCOFChanged.connect(cb); } + void addCOFSavedCallback(const signal_t::slot_type& cb) { mCOFSaved.connect(cb); } + + void addOutfitLockChangedCallback(const signal_t::slot_type& cb) { mOutfitLockChanged.connect(cb); } + protected: LLOutfitObserver(); @@ -73,10 +79,18 @@ protected: S32 mBaseOutfitLastVersion; + bool mLastOutfitDirtiness; + private: signal_t mBOFReplaced; signal_t mBOFChanged; signal_t mCOFChanged; + signal_t mCOFSaved; + + /** + * Signal for changing state of outfit lock. + */ + signal_t mOutfitLockChanged; }; #endif /* LL_OUTFITOBSERVER_H */ diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index ce382541c6..f3f67f2b03 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -198,6 +198,7 @@ LLPanelOutfitEdit::LLPanelOutfitEdit() LLOutfitObserver& observer = LLOutfitObserver::instance(); observer.addBOFReplacedCallback(boost::bind(&LLPanelOutfitEdit::updateCurrentOutfitName, this)); observer.addBOFChangedCallback(boost::bind(&LLPanelOutfitEdit::updateVerbs, this)); + observer.addOutfitLockChangedCallback(boost::bind(&LLPanelOutfitEdit::updateVerbs, this)); observer.addCOFChangedCallback(boost::bind(&LLPanelOutfitEdit::update, this)); mLookItemTypes.reserve(NUM_LOOK_ITEM_TYPES); @@ -666,12 +667,13 @@ void LLPanelOutfitEdit::updateCurrentOutfitName() void LLPanelOutfitEdit::updateVerbs() { bool outfit_is_dirty = LLAppearanceMgr::getInstance()->isOutfitDirty(); + bool outfit_locked = LLAppearanceMgr::getInstance()->isOutfitLocked(); bool has_baseoutfit = LLAppearanceMgr::getInstance()->getBaseOutfitUUID().notNull(); - mSaveComboBtn->setSaveBtnEnabled(outfit_is_dirty); + mSaveComboBtn->setSaveBtnEnabled(!outfit_locked && outfit_is_dirty); childSetEnabled(REVERT_BTN, outfit_is_dirty && has_baseoutfit); - mSaveComboBtn->setMenuItemEnabled("save_outfit", outfit_is_dirty); + mSaveComboBtn->setMenuItemEnabled("save_outfit", !outfit_locked && outfit_is_dirty); mStatus->setText(outfit_is_dirty ? getString("unsaved_changes") : getString("now_editing")); diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index 8836672f91..8b451c156c 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -209,6 +209,7 @@ LLPanelOutfitsInventory::LLPanelOutfitsInventory() : LLOutfitObserver& observer = LLOutfitObserver::instance(); observer.addBOFChangedCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this)); observer.addCOFChangedCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this)); + observer.addOutfitLockChangedCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this)); } LLPanelOutfitsInventory::~LLPanelOutfitsInventory() @@ -522,7 +523,7 @@ void LLPanelOutfitsInventory::updateListCommands() { bool trash_enabled = isActionEnabled("delete"); bool wear_enabled = isActionEnabled("wear"); - bool make_outfit_enabled = isActionEnabled("make_outfit"); + bool make_outfit_enabled = isActionEnabled("save_outfit"); mListCommands->childSetEnabled("trash_btn", trash_enabled); mListCommands->childSetEnabled("wear_btn", wear_enabled); @@ -668,9 +669,12 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata) return FALSE; } } - if (command_name == "make_outfit") + if (command_name == "save_outfit") { - return LLAppearanceMgr::getInstance()->isOutfitDirty(); + bool outfit_locked = LLAppearanceMgr::getInstance()->isOutfitLocked(); + bool outfit_dirty =LLAppearanceMgr::getInstance()->isOutfitDirty(); + // allow save only if outfit isn't locked and is dirty + return !outfit_locked && outfit_dirty; } if (command_name == "edit" || -- cgit v1.2.3