summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexei Arabadji <aarabadji@productengine.com>2010-06-08 15:36:48 +0300
committerAlexei Arabadji <aarabadji@productengine.com>2010-06-08 15:36:48 +0300
commit50eb27a04d193ef145f8879e12d8a82089a66891 (patch)
tree792b4d5bba8a03234bd1055b25fd67674c4c8ba7
parenta62287c2b0c94a8142818a5c3348c5f55b722614 (diff)
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
-rw-r--r--indra/newview/app_settings/settings.xml11
-rw-r--r--indra/newview/llappearancemgr.cpp67
-rw-r--r--indra/newview/llappearancemgr.h14
-rw-r--r--indra/newview/lloutfitobserver.cpp15
-rw-r--r--indra/newview/lloutfitobserver.h14
-rw-r--r--indra/newview/llpaneloutfitedit.cpp6
-rw-r--r--indra/newview/llpaneloutfitsinventory.cpp10
7 files changed, 130 insertions, 7 deletions
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 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>OutfitOperationsTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Timeout for outfit related operations.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>180</integer>
+ </map>
</map>
</llsd>
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<LLAppearanceMgr>
{
friend class LLSingleton<LLAppearanceMgr>;
+ friend class LLOutfitUnLockTimer;
public:
typedef std::vector<LLInventoryModel::item_array_t> 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<LLUUID> 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<LLOutfitUnLockTimer> 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<void (void)> 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" ||