diff options
Diffstat (limited to 'indra/newview')
262 files changed, 10869 insertions, 8130 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 1c1e2ef9ef..40b1776708 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -99,6 +99,7 @@ include_directories(SYSTEM set(viewer_SOURCE_FILES groupchatlistener.cpp llaccountingcostmanager.cpp + llaisapi.cpp llagent.cpp llagentaccess.cpp llagentcamera.cpp @@ -109,7 +110,6 @@ set(viewer_SOURCE_FILES llagentpilot.cpp llagentui.cpp llagentwearables.cpp - llagentwearablesfetch.cpp llanimstatelabels.cpp llappcorehttp.cpp llappearancemgr.cpp @@ -232,6 +232,7 @@ set(viewer_SOURCE_FILES llfloatergesture.cpp llfloatergodtools.cpp llfloatergotoline.cpp + llfloatergroupbulkban.cpp llfloatergroupinvite.cpp llfloatergroups.cpp llfloaterhandler.cpp @@ -313,6 +314,7 @@ set(viewer_SOURCE_FILES llhasheduniqueid.cpp llhints.cpp llhomelocationresponder.cpp + llhttpretrypolicy.cpp llhudeffect.cpp llhudeffectbeam.cpp llhudeffectlookat.cpp @@ -403,6 +405,8 @@ set(viewer_SOURCE_FILES llpanelface.cpp llpanelgenerictip.cpp llpanelgroup.cpp + llpanelgroupbulk.cpp + llpanelgroupbulkban.cpp llpanelgroupgeneral.cpp llpanelgroupinvite.cpp llpanelgrouplandmoney.cpp @@ -662,7 +666,6 @@ set(viewer_SOURCE_FILES llwearablelist.cpp llweb.cpp llwebprofile.cpp - llwebsharing.cpp llwind.cpp llwindowlistener.cpp llwlanimator.cpp @@ -690,6 +693,7 @@ set(viewer_HEADER_FILES groupchatlistener.h llaccountingcost.h llaccountingcostmanager.h + llaisapi.h llagent.h llagentaccess.h llagentcamera.h @@ -700,7 +704,6 @@ set(viewer_HEADER_FILES llagentpilot.h llagentui.h llagentwearables.h - llagentwearablesfetch.h llanimstatelabels.h llappcorehttp.h llappearance.h @@ -824,6 +827,7 @@ set(viewer_HEADER_FILES llfloatergesture.h llfloatergodtools.h llfloatergotoline.h + llfloatergroupbulkban.h llfloatergroupinvite.h llfloatergroups.h llfloaterhandler.h @@ -906,6 +910,7 @@ set(viewer_HEADER_FILES llgroupmgr.h llhasheduniqueid.h llhints.h + llhttpretrypolicy.h llhomelocationresponder.h llhudeffect.h llhudeffectbeam.h @@ -988,6 +993,9 @@ set(viewer_HEADER_FILES llpanelface.h llpanelgenerictip.h llpanelgroup.h + llpanelgroupbulk.h + llpanelgroupbulkimpl.h + llpanelgroupbulkban.h llpanelgroupgeneral.h llpanelgroupinvite.h llpanelgrouplandmoney.h @@ -1244,7 +1252,6 @@ set(viewer_HEADER_FILES llwearablelist.h llweb.h llwebprofile.h - llwebsharing.h llwind.h llwindowlistener.h llwlanimator.h @@ -2168,10 +2175,21 @@ if (LL_TESTS) #llviewertexturelist.cpp ) + set(test_libs + ${JSONCPP_LIBRARIES} + ${CURL_LIBRARIES} + ) + set_source_files_properties( lltranslate.cpp PROPERTIES - LL_TEST_ADDITIONAL_LIBRARIES "${JSONCPP_LIBRARIES}" + LL_TEST_ADDITIONAL_LIBRARIES "${test_libs}" + ) + + set_source_files_properties( + llmediadataclient.cpp + PROPERTIES + LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}" ) set_source_files_properties( @@ -2252,6 +2270,7 @@ if (LL_TESTS) set(test_libs ${LLMESSAGE_LIBRARIES} + ${LLCOREHTTP_LIBRARIES} ${WINDOWS_LIBRARIES} ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} @@ -2292,6 +2311,8 @@ if (LL_TESTS) "${test_libs}" ) + LL_ADD_INTEGRATION_TEST(llhttpretrypolicy "llhttpretrypolicy.cpp" "${test_libs}") + #ADD_VIEWER_BUILD_TEST(llmemoryview viewer) #ADD_VIEWER_BUILD_TEST(llagentaccess viewer) #ADD_VIEWER_BUILD_TEST(lltextureinfo viewer) diff --git a/indra/newview/SecondLife.nib b/indra/newview/SecondLife.nib Binary files differindex 8b99b5a770..c4ddca50dc 100644 --- a/indra/newview/SecondLife.nib +++ b/indra/newview/SecondLife.nib diff --git a/indra/newview/SecondLife.xib b/indra/newview/SecondLife.xib index 370df6bf5f..ef25c648a7 100644 --- a/indra/newview/SecondLife.xib +++ b/indra/newview/SecondLife.xib @@ -120,7 +120,7 @@ </object> <object class="NSMenuItem" id="755159360"> <reference key="NSMenu" ref="110575045"/> - <string key="NSTitle">Hide NewApplication</string> + <string key="NSTitle">Hide Second Life</string> <string key="NSKeyEquiv">h</string> <int key="NSKeyEquivModMask">1048576</int> <int key="NSMnemonicLoc">2147483647</int> diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index d2577d9756..f06fb9e915 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -3.7.7 +3.7.10 diff --git a/indra/newview/app_settings/keys.xml b/indra/newview/app_settings/keys.xml index 6e3673e7d9..a8037fec05 100755 --- a/indra/newview/app_settings/keys.xml +++ b/indra/newview/app_settings/keys.xml @@ -293,11 +293,24 @@ <!--these are for passing controls when sitting on vehicles--> <binding key="A" mask="SHIFT" command="slide_left"/> <binding key="D" mask="SHIFT" command="slide_right"/> + <binding key="W" mask="SHIFT" command="move_forward_sitting"/> + <binding key="S" mask="SHIFT" command="move_backward_sitting"/> + <binding key="E" mask="SHIFT" command="spin_over_sitting"/> + <binding key="C" mask="SHIFT" command="spin_under_sitting"/> + <binding key="LEFT" mask="SHIFT" command="slide_left"/> <binding key="RIGHT" mask="SHIFT" command="slide_right"/> + <binding key="UP" mask="SHIFT" command="move_forward_sitting"/> + <binding key="DOWN" mask="SHIFT" command="move_backward_sitting"/> + <binding key="PGUP" mask="SHIFT" command="spin_over_sitting"/> + <binding key="PGDN" mask="SHIFT" command="spin_under_sitting"/> <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/> <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/> + <binding key="PAD_UP" mask="SHIFT" command="move_forward_sitting"/> + <binding key="PAD_DOWN" mask="SHIFT" command="move_backward_sitting"/> + <binding key="PAD_PGUP" mask="SHIFT" command="spin_over_sitting"/> + <binding key="PAD_PGDN" mask="SHIFT" command="spin_under_sitting"/> <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/> <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/> diff --git a/indra/newview/app_settings/keywords.ini b/indra/newview/app_settings/keywords.ini index ad843bca14..17c70ef1c5 100755 --- a/indra/newview/app_settings/keywords.ini +++ b/indra/newview/app_settings/keywords.ini @@ -526,6 +526,7 @@ REGION_FLAG_SANDBOX Used with llGetRegionFlags to find if a region is a sand REGION_FLAG_DISABLE_COLLISIONS Used with llGetRegionFlags to find if a region has disabled collisions REGION_FLAG_DISABLE_PHYSICS Used with llGetRegionFlags to find if a region has disabled physics REGION_FLAG_BLOCK_FLY Used with llGetRegionFlags to find if a region blocks flying +REGION_FLAG_BLOCK_FLYOVER Used with llGetRegionFlags to find if a region enforces higher altitude parcel access rules REGION_FLAG_ALLOW_DIRECT_TELEPORT Used with llGetRegionFlags to find if a region allows direct teleports REGION_FLAG_RESTRICT_PUSHOBJECT Used with llGetRegionFlags to find if a region restricts llPushObject() calls diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml index 7da047aed5..15cb5bc0eb 100755 --- a/indra/newview/app_settings/logcontrol.xml +++ b/indra/newview/app_settings/logcontrol.xml @@ -43,6 +43,7 @@ <key>tags</key> <array> <!-- sample entry for debugging specific items + <string>Inventory</string> <string>SceneLoadTiming</string> <string>Avatar</string> <string>Voice</string> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 37352d5e98..c5d7689b95 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -11517,28 +11517,6 @@ <key>Value</key> <integer>75</integer> </map> - <key>SnapshotSharingEnabled</key> - <map> - <key>Comment</key> - <string>Enable uploading of snapshots to a web service.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>SnapshotConfigURL</key> - <map> - <key>Comment</key> - <string>URL to fetch Snapshot Sharing configuration data from.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>http://photos.apps.staging.avatarsunited.com/viewer_config</string> - </map> <key>SpeedTest</key> <map> <key>Comment</key> @@ -11770,6 +11748,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>TextureFetchFakeFailureRate</key> + <map> + <key>Comment</key> + <string>Simulate HTTP fetch failures for some server bake textures.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <integer>0.0</integer> + </map> <key>TextureFetchSource</key> <map> <key>Comment</key> @@ -15131,18 +15120,6 @@ <key>Value</key> <integer>7000</integer> </map> - <key>DisablePrecacheDelayAfterTeleporting</key> - <map> - <key>Comment</key> - <string>Disables the artificial delay in the viewer that precaches some incoming assets</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>VersionChannelName</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl index a74290bfcd..2487110624 100755 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl @@ -40,7 +40,7 @@ mat4 getObjectSkinnedTransform(); void main() { vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - + mat4 mat = getObjectSkinnedTransform(); mat = modelview_matrix * mat; diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index 5268498d56..9ec6428ee6 100755 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -3825,7 +3825,7 @@ <volume_morph name="BELLY" scale="0.075 0.04 0.03" - pos="0.07 0 -0.02"/> + pos="0.07 0 -0.07"/> <volume_morph name="PELVIS" scale="0.075 0.04 0.03" @@ -4269,7 +4269,7 @@ label_min="Big Pectorals" label_max="Sunken Chest" value_default="0" - value_min="-1.0" + value_min="-0.5" value_max="1.1" camera_elevation=".3" camera_distance="1.2"> @@ -4480,7 +4480,7 @@ group="1" sex="female" name="Breast_Physics_UpDown_Driven" - wearable="shape" + wearable="physics" edit_group="driven" value_default="0" value_min="-3" @@ -4502,7 +4502,7 @@ group="1" sex="female" name="Breast_Physics_InOut_Driven" - wearable="shape" + wearable="physics" edit_group="driven" value_default="0" value_min="-1.25" @@ -4524,7 +4524,6 @@ group="1" name="Belly_Physics_Torso_UpDown_Driven" wearable="physics" - cross_wearable="true" edit_group="driven" value_default="0" value_min="-1" @@ -4542,7 +4541,6 @@ group="1" name="Breast_Physics_LeftRight_Driven" wearable="physics" - cross_wearable="true" edit_group="driven" value_default="0" value_min="-2" @@ -7716,7 +7714,7 @@ render_pass="bump"> <param id="868" - group="0" + group="3" wearable="shirt" edit_group="shirt" edit_group_order="8" @@ -8839,7 +8837,7 @@ render_pass="bump"> <param id="869" - group="0" + group="3" wearable="pants" edit_group="pants" edit_group_order="6" @@ -9760,7 +9758,7 @@ render_pass="bump"> <param id="163" - group="0" + group="3" wearable="skin" edit_group="skin_facedetail" edit_group_order="3" @@ -11819,7 +11817,7 @@ render_pass="bump"> <param id="877" - group="0" + group="3" name="Jacket Wrinkles" label="Jacket Wrinkles" wearable="jacket" diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt index 8efc4ee87d..badbe486b9 100755 --- a/indra/newview/gpu_table.txt +++ b/indra/newview/gpu_table.txt @@ -327,7 +327,8 @@ Intel HD Graphics 4600 .*Intel.*HD Graphics 46.* 3 1 0 4.2 Intel HD Graphics 4000 .*Intel.*HD Graphics 4.* 3 1 1 4.2 Intel Intel Iris Pro Graphics 5200 .*Intel.*Iris Pro Graphics 52.* 4 1 0 4 Intel Intel Iris Graphics 5100 .*Intel.*Iris Graphics 51.* 4 1 0 4 -Intel Intel Iris OpenGL Engine .*Intel.*Iris (Pro )*OpenGL.* 4 1 0 4 +Intel Intel Iris OpenGL Engine .*Intel.*Iris OpenGL.* 4 1 0 4 +Intel Intel Iris Pro OpenGL Engine .*Intel.*Iris Pro OpenGL.* 5 1 0 4 Intel HD Graphics 5000 .*Intel.*HD Graphics 5.* 4 1 0 4 Intel HD Graphics .*Intel.*HD Graphics.* 2 1 1 4 Intel Mobile 4 Series .*Intel.*Mobile.* 4 Series.* 0 1 1 2.1 diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index c4f503ef4e..ad5ab22640 100755 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -106,6 +106,7 @@ Var COMMANDLINE ; command line passed to this installer, set in .onInit Var SHORTCUT_LANG_PARAM ; "--set InstallLanguage de", passes language to viewer
Var SKIP_DIALOGS ; set from command line in .onInit. autoinstall
; GUI and the defaults.
+Var SKIP_AUTORUN ; skip automatic launch of viewer after install
Var DO_UNINSTALL_V2 ; If non-null, path to a previous Viewer 2 installation that will be uninstalled.
;;; Function definitions should go before file includes, because calls to
@@ -122,24 +123,9 @@ Var DO_UNINSTALL_V2 ; If non-null, path to a previous Viewer 2 installation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function .onInstSuccess
Push $R0 # Option value, unused
-
- StrCmp $SKIP_DIALOGS "true" label_launch
-
- ${GetOptions} $COMMANDLINE "/AUTOSTART" $R0
- # If parameter was there (no error) just launch
- # Otherwise ask
- IfErrors label_ask_launch label_launch
-
-label_ask_launch:
- # Don't launch by default when silent
- IfSilent label_no_launch
- MessageBox MB_YESNO $(InstSuccesssQuestion) \
- IDYES label_launch IDNO label_no_launch
-
-label_launch:
+ StrCmp $SKIP_AUTORUN "true" +2;
# Assumes SetOutPath $INSTDIR
Exec '"$INSTDIR\$INSTEXE" $SHORTCUT_LANG_PARAM'
-label_no_launch:
Pop $R0
FunctionEnd
@@ -872,7 +858,12 @@ Function .onInit IfErrors +2 0 ; If error jump past setting SKIP_DIALOGS
StrCpy $SKIP_DIALOGS "true"
+ ${GetOptions} $COMMANDLINE "/SKIP_AUTORUN" $0
+ IfErrors +2 0 ; If error jump past setting SKIP_AUTORUN
+ StrCpy $SKIP_AUTORUN "true"
+
${GetOptions} $COMMANDLINE "/LANGID=" $0 ; /LANGID=1033 implies US English
+
; If no language (error), then proceed
IfErrors lbl_configure_default_lang
; No error means we got a language, so use it
diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index 150b97baa5..a42286a9e4 100755 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -36,6 +36,7 @@ LLAccountingCostManager::LLAccountingCostManager() //=============================================================================== class LLAccountingCostResponder : public LLCurl::Responder { + LOG_CLASS(LLAccountingCostResponder); public: LLAccountingCostResponder( const LLSD& objectIDs, const LLHandle<LLAccountingCostObserver>& observer_handle ) : mObjectIDs( objectIDs ), @@ -56,24 +57,27 @@ public: } } - void errorWithContent( U32 statusNum, const std::string& reason, const LLSD& content ) +protected: + void httpFailure() { - LL_WARNS() << "Transport error [status:" << statusNum << "]: " << content <<LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; clearPendingRequests(); LLAccountingCostObserver* observer = mObserverHandle.get(); if (observer && observer->getTransactionID() == mTransactionID) { - observer->setErrorStatus(statusNum, reason); + observer->setErrorStatus(getStatus(), getReason()); } } - void result( const LLSD& content ) + void httpSuccess() { + const LLSD& content = getContent(); //Check for error if ( !content.isMap() || content.has("error") ) { - LL_WARNS() << "Error on fetched data"<< LL_ENDL; + failureResult(HTTP_INTERNAL_ERROR, "Error on fetched data", content); + return; } else if (content.has("selected")) { diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h index 0bca1f54ef..3ade34c81d 100755 --- a/indra/newview/llaccountingcostmanager.h +++ b/indra/newview/llaccountingcostmanager.h @@ -38,7 +38,7 @@ public: LLAccountingCostObserver() { mObserverHandle.bind(this); } virtual ~LLAccountingCostObserver() {} virtual void onWeightsUpdate(const SelectionCost& selection_cost) = 0; - virtual void setErrorStatus(U32 status, const std::string& reason) = 0; + virtual void setErrorStatus(S32 status, const std::string& reason) = 0; const LLHandle<LLAccountingCostObserver>& getObserverHandle() const { return mObserverHandle; } const LLUUID& getTransactionID() { return mTransactionID; } diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index eb9ca542a3..aa8e0bad76 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -406,7 +406,7 @@ LLAgent::LLAgent() : mNextFidgetTime(0.f), mCurrentFidget(0), mFirstLogin(FALSE), - mGenderChosen(FALSE), + mOutfitChosen(FALSE), mVoiceConnected(false), @@ -809,30 +809,6 @@ void LLAgent::standUp() setControlFlags(AGENT_CONTROL_STAND_UP); } - -void LLAgent::handleServerBakeRegionTransition(const LLUUID& region_id) -{ - LL_INFOS() << "called" << LL_ENDL; - - - // Old-style appearance entering a server-bake region. - if (isAgentAvatarValid() && - !gAgentAvatarp->isUsingServerBakes() && - (mRegionp->getCentralBakeVersion()>0)) - { - LL_INFOS() << "update requested due to region transition" << LL_ENDL; - LLAppearanceMgr::instance().requestServerAppearanceUpdate(); - } - // new-style appearance entering a non-bake region, - // need to check for existence of the baking service. - else if (isAgentAvatarValid() && - gAgentAvatarp->isUsingServerBakes() && - mRegionp->getCentralBakeVersion()==0) - { - gAgentAvatarp->checkForUnsupportedServerBakeAppearance(); - } -} - void LLAgent::changeParcels() { LL_DEBUGS("AgentLocation") << "Calling ParcelChanged callbacks" << LL_ENDL; @@ -934,19 +910,6 @@ void LLAgent::setRegion(LLViewerRegion *regionp) LLFloaterMove::sUpdateFlyingStatus(); - // If the newly entered region is using server bakes, and our - // current appearance is non-baked, request appearance update from - // server. - if (mRegionp->capabilitiesReceived()) - { - handleServerBakeRegionTransition(mRegionp->getRegionID()); - } - else - { - // Need to handle via callback after caps arrive. - mRegionp->setCapabilitiesReceivedCallback(boost::bind(&LLAgent::handleServerBakeRegionTransition,this,_1)); - } - if (notifyRegionChange) { LL_DEBUGS("AgentLocation") << "Calling RegionChanged callbacks" << LL_ENDL; @@ -1917,7 +1880,7 @@ BOOL LLAgent::needsRenderAvatar() return FALSE; } - return mShowAvatar && mGenderChosen; + return mShowAvatar && mOutfitChosen; } // TRUE if we need to render your own avatar's head. @@ -2565,17 +2528,19 @@ int LLAgent::convertTextToMaturity(char text) class LLMaturityPreferencesResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLMaturityPreferencesResponder); public: LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity); virtual ~LLMaturityPreferencesResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); +protected: + virtual void httpSuccess(); + virtual void httpFailure(); protected: private: - U8 parseMaturityFromServerResponse(const LLSD &pContent); + U8 parseMaturityFromServerResponse(const LLSD &pContent) const; LLAgent *mAgent; U8 mPreferredMaturity; @@ -2594,39 +2559,43 @@ LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder() { } -void LLMaturityPreferencesResponder::result(const LLSD &pContent) +void LLMaturityPreferencesResponder::httpSuccess() { - U8 actualMaturity = parseMaturityFromServerResponse(pContent); + U8 actualMaturity = parseMaturityFromServerResponse(getContent()); if (actualMaturity != mPreferredMaturity) { - LL_WARNS() << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity) - << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', the server responded with '" - << LLViewerRegion::accessToString(actualMaturity) << "' [value:" << static_cast<U32>(actualMaturity) << ", llsd:" - << pContent << "]" << LL_ENDL; + LL_WARNS() << "while attempting to change maturity preference from '" + << LLViewerRegion::accessToString(mPreviousMaturity) + << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) + << "', the server responded with '" + << LLViewerRegion::accessToString(actualMaturity) + << "' [value:" << static_cast<U32>(actualMaturity) + << "], " << dumpResponse() << LL_ENDL; } mAgent->handlePreferredMaturityResult(actualMaturity); } -void LLMaturityPreferencesResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void LLMaturityPreferencesResponder::httpFailure() { - LL_WARNS() << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity) - << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', we got an error with [status:" - << pStatus << "]: " << (pContent.isDefined() ? pContent : LLSD(pReason)) << LL_ENDL; + LL_WARNS() << "while attempting to change maturity preference from '" + << LLViewerRegion::accessToString(mPreviousMaturity) + << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) + << "', " << dumpResponse() << LL_ENDL; mAgent->handlePreferredMaturityError(); } -U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) +U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) const { U8 maturity = SIM_ACCESS_MIN; - llassert(!pContent.isUndefined()); + llassert(pContent.isDefined()); llassert(pContent.isMap()); llassert(pContent.has("access_prefs")); llassert(pContent.get("access_prefs").isMap()); llassert(pContent.get("access_prefs").has("max")); llassert(pContent.get("access_prefs").get("max").isString()); - if (!pContent.isUndefined() && pContent.isMap() && pContent.has("access_prefs") + if (pContent.isDefined() && pContent.isMap() && pContent.has("access_prefs") && pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max") && pContent.get("access_prefs").get("max").isString()) { @@ -2772,7 +2741,7 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity) // If we don't have a region, report it as an error if (getRegion() == NULL) { - responderPtr->errorWithContent(0U, "region is not defined", LLSD()); + responderPtr->failureResult(0U, "region is not defined", LLSD()); } else { @@ -2782,7 +2751,7 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity) // If the capability is not defined, report it as an error if (url.empty()) { - responderPtr->errorWithContent(0U, + responderPtr->failureResult(0U, "capability 'UpdateAgentInformation' is not defined for region", LLSD()); } else @@ -3330,8 +3299,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode !input.has("body") ) { //what to do with badly formed message? - response->statusUnknownError(400); - response->result(LLSD("Invalid message parameters")); + response->extendedResult(HTTP_BAD_REQUEST, LLSD("Invalid message parameters")); } LLSD body = input["body"]; @@ -3400,8 +3368,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode else { //what to do with badly formed message? - response->statusUnknownError(400); - response->result(LLSD("Invalid message parameters")); + response->extendedResult(HTTP_BAD_REQUEST, LLSD("Invalid message parameters")); } } }; @@ -3683,82 +3650,6 @@ void LLAgent::processControlRelease(LLMessageSystem *msg, void **) } */ -//static -void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data) -{ - gAgentQueryManager.mNumPendingQueries--; - if (gAgentQueryManager.mNumPendingQueries == 0) - { - selfStopPhase("fetch_texture_cache_entries"); - } - - if (!isAgentAvatarValid() || gAgentAvatarp->isDead()) - { - LL_WARNS() << "No avatar for user in cached texture update!" << LL_ENDL; - return; - } - - if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance()) - { - // ignore baked textures when in customize mode - return; - } - - S32 query_id; - mesgsys->getS32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, query_id); - - S32 num_texture_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_WearableData); - - - S32 num_results = 0; - for (S32 texture_block = 0; texture_block < num_texture_blocks; texture_block++) - { - LLUUID texture_id; - U8 texture_index; - - mesgsys->getUUIDFast(_PREHASH_WearableData, _PREHASH_TextureID, texture_id, texture_block); - mesgsys->getU8Fast(_PREHASH_WearableData, _PREHASH_TextureIndex, texture_index, texture_block); - - - if ((S32)texture_index < TEX_NUM_INDICES ) - { - const LLAvatarAppearanceDictionary::TextureEntry *texture_entry = LLAvatarAppearanceDictionary::instance().getTexture((ETextureIndex)texture_index); - if (texture_entry) - { - EBakedTextureIndex baked_index = texture_entry->mBakedTextureIndex; - - if (gAgentQueryManager.mActiveCacheQueries[baked_index] == query_id) - { - if (texture_id.notNull()) - { - //LL_INFOS() << "Received cached texture " << (U32)texture_index << ": " << texture_id << LL_ENDL; - gAgentAvatarp->setCachedBakedTexture((ETextureIndex)texture_index, texture_id); - //gAgentAvatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id ); - gAgentQueryManager.mActiveCacheQueries[baked_index] = 0; - num_results++; - } - else - { - // no cache of this bake. request upload. - gAgentAvatarp->invalidateComposite(gAgentAvatarp->getLayerSet(baked_index),TRUE); - } - } - } - } - } - LL_INFOS() << "Received cached texture response for " << num_results << " textures." << LL_ENDL; - gAgentAvatarp->outputRezTiming("Fetched agent wearables textures from cache. Will now load them"); - - gAgentAvatarp->updateMeshTextures(); - - if (gAgentQueryManager.mNumPendingQueries == 0) - { - // RN: not sure why composites are disabled at this point - gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); - gAgent.sendAgentSetAppearance(); - } -} - BOOL LLAgent::anyControlGrabbed() const { for (U32 i = 0; i < TOTAL_CONTROLS; i++) @@ -4351,192 +4242,6 @@ void LLAgent::requestLeaveGodMode() sendReliableMessage(); } -// For debugging, trace agent state at times appearance message are sent out. -void LLAgent::dumpSentAppearance(const std::string& dump_prefix) -{ - std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml"); - - LLAPRFile outfile; - std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); - outfile.open(fullpath, LL_APR_WB ); - apr_file_t* file = outfile.getFileHandle(); - if (!file) - { - return; - } - else - { - LL_DEBUGS("Avatar") << "dumping sent appearance message to " << fullpath << LL_ENDL; - } - - LLVisualParam* appearance_version_param = gAgentAvatarp->getVisualParam(11000); - if (appearance_version_param) - { - F32 value = appearance_version_param->getWeight(); - dump_visual_param(file, appearance_version_param, value); - } - for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); - ++iter) - { - const ETextureIndex index = iter->first; - const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; - if (texture_dict->mIsBakedTexture) - { - LLTextureEntry* entry = gAgentAvatarp->getTE((U8) index); - const LLUUID& uuid = entry->getID(); - apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", index, uuid.asString().c_str()); - } - } -} - -//----------------------------------------------------------------------------- -// sendAgentSetAppearance() -//----------------------------------------------------------------------------- -void LLAgent::sendAgentSetAppearance() -{ - if (gAgentQueryManager.mNumPendingQueries > 0) - { - return; - } - - if (!isAgentAvatarValid() || (getRegion() && getRegion()->getCentralBakeVersion())) return; - - // At this point we have a complete appearance to send and are in a non-baking region. - // DRANO FIXME - //gAgentAvatarp->setIsUsingServerBakes(FALSE); - S32 sb_count, host_count, both_count, neither_count; - gAgentAvatarp->bakedTextureOriginCounts(sb_count, host_count, both_count, neither_count); - if (both_count != 0 || neither_count != 0) - { - LL_WARNS() << "bad bake texture state " << sb_count << "," << host_count << "," << both_count << "," << neither_count << LL_ENDL; - } - if (sb_count != 0 && host_count == 0) - { - gAgentAvatarp->setIsUsingServerBakes(true); - } - else if (sb_count == 0 && host_count != 0) - { - gAgentAvatarp->setIsUsingServerBakes(false); - } - else if (sb_count + host_count > 0) - { - LL_WARNS() << "unclear baked texture state, not sending appearance" << LL_ENDL; - return; - } - - - LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << LL_ENDL; - //dumpAvatarTEs( "sendAgentSetAppearance()" ); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_AgentSetAppearance); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, getID()); - msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); - - // correct for the collision tolerance (to make it look like the - // agent is actually walking on the ground/object) - // NOTE -- when we start correcting all of the other Havok geometry - // to compensate for the COLLISION_TOLERANCE ugliness we will have - // to tweak this number again - const LLVector3 body_size = gAgentAvatarp->mBodySize + gAgentAvatarp->mAvatarOffset; - msg->addVector3Fast(_PREHASH_Size, body_size); - - // To guard against out of order packets - // Note: always start by sending 1. This resets the server's count. 0 on the server means "uninitialized" - mAppearanceSerialNum++; - msg->addU32Fast(_PREHASH_SerialNum, mAppearanceSerialNum ); - - // is texture data current relative to wearables? - // KLW - TAT this will probably need to check the local queue. - BOOL textures_current = gAgentAvatarp->areTexturesCurrent(); - - for(U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ ) - { - const ETextureIndex texture_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index); - - // if we're not wearing a skirt, we don't need the texture to be baked - if (texture_index == TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT)) - { - continue; - } - - // IMG_DEFAULT_AVATAR means not baked. 0 index should be ignored for baked textures - if (!gAgentAvatarp->isTextureDefined(texture_index, 0)) - { - LL_DEBUGS("Avatar") << "texture not current for baked " << (S32)baked_index << " local " << (S32)texture_index << LL_ENDL; - textures_current = FALSE; - break; - } - } - - // only update cache entries if we have all our baked textures - - // FIXME DRANO need additional check for not in appearance editing - // mode, if still using local composites need to set using local - // composites to false, and update mesh textures. - if (textures_current) - { - bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); - std::string dump_prefix = gAgentAvatarp->getFullname() + "_sent_appearance"; - if (enable_verbose_dumps) - { - dumpSentAppearance(dump_prefix); - } - LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "TAT: Sending cached texture data" << LL_ENDL; - for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) - { - BOOL generate_valid_hash = TRUE; - if (isAgentAvatarValid() && !gAgentAvatarp->isBakedTextureFinal((LLAvatarAppearanceDefines::EBakedTextureIndex)baked_index)) - { - generate_valid_hash = FALSE; - LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Not caching baked texture upload for " << (U32)baked_index << " due to being uploaded at low resolution." << LL_ENDL; - } - - const LLUUID hash = gAgentWearables.computeBakedTextureHash((EBakedTextureIndex) baked_index, generate_valid_hash); - if (hash.notNull()) - { - ETextureIndex texture_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex) baked_index); - msg->nextBlockFast(_PREHASH_WearableData); - msg->addUUIDFast(_PREHASH_CacheID, hash); - msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index); - } - } - msg->nextBlockFast(_PREHASH_ObjectData); - gAgentAvatarp->sendAppearanceMessage( gMessageSystem ); - } - else - { - // If the textures aren't baked, send NULL for texture IDs - // This means the baked texture IDs on the server will be untouched. - // Once all textures are baked, another AvatarAppearance message will be sent to update the TEs - msg->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, NULL, 0); - } - - - S32 transmitted_params = 0; - for (LLViewerVisualParam* param = (LLViewerVisualParam*)gAgentAvatarp->getFirstVisualParam(); - param; - param = (LLViewerVisualParam*)gAgentAvatarp->getNextVisualParam()) - { - if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT - { - msg->nextBlockFast(_PREHASH_VisualParam ); - - // We don't send the param ids. Instead, we assume that the receiver has the same params in the same sequence. - const F32 param_value = param->getWeight(); - const U8 new_weight = F32_to_U8(param_value, param->getMinWeight(), param->getMaxWeight()); - msg->addU8Fast(_PREHASH_ParamValue, new_weight ); - transmitted_params++; - } - } - - //LL_INFOS() << "Avatar XML num VisualParams transmitted = " << transmitted_params << LL_ENDL; - sendReliableMessage(); -} - void LLAgent::sendAgentDataUpdateRequest() { gMessageSystem->newMessageFast(_PREHASH_AgentDataUpdateRequest); @@ -4679,23 +4384,6 @@ void LLAgent::renderAutoPilotTarget() /********************************************************************************/ -LLAgentQueryManager gAgentQueryManager; - -LLAgentQueryManager::LLAgentQueryManager() : - mWearablesCacheQueryID(0), - mNumPendingQueries(0), - mUpdateSerialNum(0) -{ - for (U32 i = 0; i < BAKED_NUM_INDICES; i++) - { - mActiveCacheQueries[i] = 0; - } -} - -LLAgentQueryManager::~LLAgentQueryManager() -{ -} - //----------------------------------------------------------------------------- // LLTeleportRequest //----------------------------------------------------------------------------- diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 1a573d32ce..a2e9cedd88 100755 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -161,12 +161,13 @@ public: // Gender //-------------------------------------------------------------------- public: - // On the very first login, gender isn't chosen until the user clicks - // in a dialog. We don't render the avatar until they choose. - BOOL isGenderChosen() const { return mGenderChosen; } - void setGenderChosen(BOOL b) { mGenderChosen = b; } + // On the very first login, outfit needs to be chosen by some + // mechanism, usually by loading the requested initial outfit. We + // don't render the avatar until the choice is made. + BOOL isOutfitChosen() const { return mOutfitChosen; } + void setOutfitChosen(BOOL b) { mOutfitChosen = b; } private: - BOOL mGenderChosen; + BOOL mOutfitChosen; /** Identity ** ** @@ -652,7 +653,6 @@ private: void handleTeleportFinished(); void handleTeleportFailed(); - void handleServerBakeRegionTransition(const LLUUID& region_id); //-------------------------------------------------------------------- // Teleport State @@ -888,8 +888,6 @@ private: public: void sendMessage(); // Send message to this agent's region void sendReliableMessage(); - void dumpSentAppearance(const std::string& dump_prefix); - void sendAgentSetAppearance(); void sendAgentDataUpdateRequest(); void sendAgentUserInfoRequest(); // IM to Email and Online visibility @@ -903,7 +901,6 @@ public: static void processAgentGroupDataUpdate(LLMessageSystem *msg, void **); static void processAgentDropGroup(LLMessageSystem *msg, void **); static void processScriptControlChange(LLMessageSystem *msg, void **); - static void processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data); /** Messaging ** ** @@ -932,24 +929,4 @@ inline bool operator==(const LLGroupData &a, const LLGroupData &b) return (a.mID == b.mID); } -class LLAgentQueryManager -{ - friend class LLAgent; - friend class LLAgentWearables; - -public: - LLAgentQueryManager(); - virtual ~LLAgentQueryManager(); - - BOOL hasNoPendingQueries() const { return getNumPendingQueries() == 0; } - S32 getNumPendingQueries() const { return mNumPendingQueries; } -private: - S32 mNumPendingQueries; - S32 mWearablesCacheQueryID; - U32 mUpdateSerialNum; - S32 mActiveCacheQueries[LLAvatarAppearanceDefines::BAKED_NUM_INDICES]; -}; - -extern LLAgentQueryManager gAgentQueryManager; - #endif diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 58981d0e06..26626ad894 100755 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -30,7 +30,6 @@ #include "llaccordionctrltab.h" #include "llagent.h" #include "llagentcamera.h" -#include "llagentwearablesfetch.h" #include "llappearancemgr.h" #include "llcallbacklist.h" #include "llfloatersidepanelcontainer.h" @@ -70,7 +69,7 @@ void wear_and_edit_cb(const LLUUID& inv_item) gAgentWearables.requestEditingWearable(inv_item); // Wear it. - LLAppearanceMgr::instance().wearItemOnAvatar(inv_item); + LLAppearanceMgr::instance().wearItemOnAvatar(inv_item,true); } /////////////////////////////////////////////////////////////////////////////// @@ -127,13 +126,6 @@ void LLAgentWearables::dump() } } - LL_INFOS() << "Total items awaiting wearable update " << mItemsAwaitingWearableUpdate.size() << LL_ENDL; - for (std::set<LLUUID>::iterator it = mItemsAwaitingWearableUpdate.begin(); - it != mItemsAwaitingWearableUpdate.end(); - ++it) - { - LL_INFOS() << (*it).asString() << LL_ENDL; - } } struct LLAgentDumper @@ -183,23 +175,9 @@ void LLAgentWearables::initClass() void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar) { llassert(avatar); - avatar->outputRezTiming("Sending wearables request"); - sendAgentWearablesRequest(); setAvatarAppearance(avatar); } -// wearables -LLAgentWearables::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback() -{ - LL_INFOS() << "destructor - all done?" << LL_ENDL; - gAgentWearables.createStandardWearablesAllDone(); -} - -LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback() -{ - gAgentWearables.sendAgentWearablesUpdate(); -} - /** * @brief Construct a callback for dealing with the wearables. * @@ -210,7 +188,7 @@ LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCal * @param wearable The wearable data. * @param todo Bitmask of actions to take on completion. */ -LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback( +LLAgentWearables::AddWearableToAgentInventoryCallback::AddWearableToAgentInventoryCallback( LLPointer<LLRefCount> cb, LLWearableType::EType type, U32 index, LLViewerWearable* wearable, U32 todo, const std::string description) : mType(type), mIndex(index), @@ -222,42 +200,24 @@ LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInvento LL_INFOS() << "constructor" << LL_ENDL; } -void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item) +void LLAgentWearables::AddWearableToAgentInventoryCallback::fire(const LLUUID& inv_item) { - if (mTodo & CALL_CREATESTANDARDDONE) - { - LL_INFOS() << "callback fired, inv_item " << inv_item.asString() << LL_ENDL; - } - if (inv_item.isNull()) return; gAgentWearables.addWearabletoAgentInventoryDone(mType, mIndex, inv_item, mWearable); - if (mTodo & CALL_UPDATE) - { - gAgentWearables.sendAgentWearablesUpdate(); - } - if (mTodo & CALL_RECOVERDONE) - { - LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); - gAgentWearables.recoverMissingWearableDone(); - } /* * Do this for every one in the loop */ - if (mTodo & CALL_CREATESTANDARDDONE) - { - LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); - gAgentWearables.createStandardWearablesDone(mType, mIndex); - } if (mTodo & CALL_MAKENEWOUTFITDONE) { gAgentWearables.makeNewOutfitDone(mType, mIndex); } if (mTodo & CALL_WEARITEM) { - LLAppearanceMgr::instance().addCOFItemLink(inv_item, true, NULL, mDescription); + LLAppearanceMgr::instance().addCOFItemLink(inv_item, + new LLUpdateAppearanceAndEditWearableOnDestroy(inv_item), mDescription); } } @@ -304,81 +264,7 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy gInventory.notifyObservers(); } -void LLAgentWearables::sendAgentWearablesUpdate() -{ - // First make sure that we have inventory items for each wearable - for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) - { - for (U32 index=0; index < getWearableCount((LLWearableType::EType)type); ++index) - { - LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type,index); - if (wearable) - { - if (wearable->getItemID().isNull()) - { - LLPointer<LLInventoryCallback> cb = - new addWearableToAgentInventoryCallback( - LLPointer<LLRefCount>(NULL), - (LLWearableType::EType)type, - index, - wearable, - addWearableToAgentInventoryCallback::CALL_NONE); - addWearableToAgentInventory(cb, wearable); - } - else - { - gInventory.addChangedMask(LLInventoryObserver::LABEL, - wearable->getItemID()); - } - } - } - } - - // Then make sure the inventory is in sync with the avatar. - gInventory.notifyObservers(); - - // Send the AgentIsNowWearing - gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); - - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - - LL_DEBUGS() << "sendAgentWearablesUpdate()" << LL_ENDL; - // MULTI-WEARABLE: DEPRECATED: HACK: index to 0- server database tables don't support concept of multiwearables. - for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) - { - gMessageSystem->nextBlockFast(_PREHASH_WearableData); - - U8 type_u8 = (U8)type; - gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8); - - LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type, 0); - if (wearable) - { - //LL_INFOS() << "Sending wearable " << wearable->getName() << LL_ENDL; - LLUUID item_id = wearable->getItemID(); - const LLViewerInventoryItem *item = gInventory.getItem(item_id); - if (item && item->getIsLinkType()) - { - // Get the itemID that this item points to. i.e. make sure - // we are storing baseitems, not their links, in the database. - item_id = item->getLinkedUUID(); - } - gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id); - } - else - { - //LL_INFOS() << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)i) << LL_ENDL; - gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null); - } - - LL_DEBUGS() << " " << LLWearableType::getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << LL_ENDL; - } - gAgent.sendReliableMessage(); -} - -void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update, +void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, const std::string new_name) { LLViewerWearable* old_wearable = getViewerWearable(type, index); @@ -419,23 +305,14 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 item->getFlags(), item->getCreationDate()); template_item->setTransactionID(new_wearable->getTransactionID()); - template_item->updateServer(FALSE); - gInventory.updateItem(template_item); - if (name_changed) - { - gInventory.notifyObservers(); - } + update_inventory_item(template_item, gAgentAvatarp->mEndCustomizeCallback); } else { // Add a new inventory item (shouldn't ever happen here) - U32 todo = addWearableToAgentInventoryCallback::CALL_NONE; - if (send_update) - { - todo |= addWearableToAgentInventoryCallback::CALL_UPDATE; - } + U32 todo = AddWearableToAgentInventoryCallback::CALL_NONE; LLPointer<LLInventoryCallback> cb = - new addWearableToAgentInventoryCallback( + new AddWearableToAgentInventoryCallback( LLPointer<LLRefCount>(NULL), type, index, @@ -445,12 +322,7 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 return; } - gAgentAvatarp->wearableUpdated( type, TRUE ); - - if (send_update) - { - sendAgentWearablesUpdate(); - } + gAgentAvatarp->wearableUpdated(type); } } @@ -484,12 +356,12 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, old_wearable, trunc_name); LLPointer<LLInventoryCallback> cb = - new addWearableToAgentInventoryCallback( + new AddWearableToAgentInventoryCallback( LLPointer<LLRefCount>(NULL), type, index, new_wearable, - addWearableToAgentInventoryCallback::CALL_WEARITEM, + AddWearableToAgentInventoryCallback::CALL_WEARITEM, description ); LLUUID category_id; @@ -526,8 +398,6 @@ void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U3 { wearable->revertValues(); } - - gAgent.sendAgentSetAppearance(); } void LLAgentWearables::saveAllWearables() @@ -540,9 +410,8 @@ void LLAgentWearables::saveAllWearables() for (S32 i=0; i < LLWearableType::WT_COUNT; i++) { for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) - saveWearable((LLWearableType::EType)i, j, FALSE); + saveWearable((LLWearableType::EType)i, j); } - sendAgentWearablesUpdate(); } // Called when the user changes the name of a wearable inventory item that is currently being worn. @@ -571,7 +440,6 @@ void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string& old_wearable->setName(old_name); setWearable((LLWearableType::EType)i,j,new_wearable); - sendAgentWearablesUpdate(); break; } } @@ -692,15 +560,6 @@ LLViewerWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_i return NULL; } -void LLAgentWearables::sendAgentWearablesRequest() -{ - gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); -} - LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/) { return dynamic_cast<LLViewerWearable*> (getWearable(type, index)); @@ -722,8 +581,7 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed) { if (isAgentAvatarValid()) { - const BOOL upload_result = removed; - gAgentAvatarp->wearableUpdated(wearable->getType(), upload_result); + gAgentAvatarp->wearableUpdated(wearable->getType()); } LLWearableData::wearableUpdated(wearable, removed); @@ -743,23 +601,13 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed) wearable->setDefinitionVersion(22); U32 index = getWearableIndex(wearable); LL_INFOS() << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << LL_ENDL; - saveWearable(wearable->getType(),index,TRUE); + saveWearable(wearable->getType(),index); } checkWearableAgainstInventory(viewer_wearable); } } -BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const -{ - return mItemsAwaitingWearableUpdate.find(item_id) != mItemsAwaitingWearableUpdate.end(); -} - -U32 LLAgentWearables::itemUpdatePendingCount() const -{ - return mItemsAwaitingWearableUpdate.size(); -} - const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 index) const { const LLViewerWearable *wearable = getViewerWearable(type,index); @@ -783,157 +631,6 @@ BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const return getWearableFromItemID(item_id) != NULL; } -// MULTI-WEARABLE: DEPRECATED (see backwards compatibility) -// static -// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume -// that viewers have a Current Outfit Folder and won't need this message, and thus -// we can remove/ignore this whole function. EXCEPT gAgentWearables.notifyLoadingStarted -void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data) -{ - // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates - // that may result from AgentWearablesRequest having been sent more than once. - if (mInitialWearablesUpdateReceived) - return; - - if (isAgentAvatarValid()) - { - gAgentAvatarp->startPhase("process_initial_wearables_update"); - gAgentAvatarp->outputRezTiming("Received initial wearables update"); - } - - // notify subscribers that wearables started loading. See EXT-7777 - // *TODO: find more proper place to not be called from deprecated method. - // Seems such place is found: LLInitialWearablesFetch::processContents() - gAgentWearables.notifyLoadingStarted(); - - mInitialWearablesUpdateReceived = true; - - LLUUID agent_id; - gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - - if (isAgentAvatarValid() && (agent_id == gAgentAvatarp->getID())) - { - gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgentQueryManager.mUpdateSerialNum); - - const S32 NUM_BODY_PARTS = 4; - S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData); - if (num_wearables < NUM_BODY_PARTS) - { - // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin). - // The fact that they don't have any here (only a dummy is sent) implies that either: - // 1. This account existed before we had wearables - // 2. The database has gotten messed up - // 3. This is the account's first login (i.e. the wearables haven't been generated yet). - return; - } - - // Get the UUID of the current outfit folder (will be created if it doesn't exist) - const LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch(current_outfit_id); - - //LL_DEBUGS() << "processAgentInitialWearablesUpdate()" << LL_ENDL; - // Add wearables - // MULTI-WEARABLE: DEPRECATED: Message only supports one wearable per type, will be ignored in future. - gAgentWearables.mItemsAwaitingWearableUpdate.clear(); - for (S32 i=0; i < num_wearables; i++) - { - // Parse initial wearables data from message system - U8 type_u8 = 0; - gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i); - if (type_u8 >= LLWearableType::WT_COUNT) - { - continue; - } - const LLWearableType::EType type = (LLWearableType::EType) type_u8; - - LLUUID item_id; - gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i); - - LLUUID asset_id; - gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i); - if (asset_id.isNull()) - { - LLViewerWearable::removeFromAvatar(type, FALSE); - } - else - { - LLAssetType::EType asset_type = LLWearableType::getAssetType(type); - if (asset_type == LLAssetType::AT_NONE) - { - continue; - } - - // MULTI-WEARABLE: DEPRECATED: this message only supports one wearable per type. Should be ignored in future versions - - // Store initial wearables data until we know whether we have the current outfit folder or need to use the data. - LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id); - outfit->add(wearable_data); - } - - LL_DEBUGS() << " " << LLWearableType::getTypeLabel(type) << LL_ENDL; - } - - // Get the complete information on the items in the inventory and set up an observer - // that will trigger when the complete information is fetched. - outfit->startFetch(); - if(outfit->isFinished()) - { - // everything is already here - call done. - outfit->done(); - } - else - { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(outfit); - } - - } -} - -// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the -// database. If for some reason, we can't load one of those assets, we can try to reconstruct it so that -// the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.) -void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type, U32 index) -{ - // Try to recover by replacing missing wearable with a new one. - LLNotificationsUtil::add("ReplacedMissingWearable"); - LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type) << " could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; - LLViewerWearable* new_wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); - - setWearable(type,index,new_wearable); - //new_wearable->writeToAvatar(TRUE); - - // Add a new one in the lost and found folder. - // (We used to overwrite the "not found" one, but that could potentially - // destory content.) JC - const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - LLPointer<LLInventoryCallback> cb = - new addWearableToAgentInventoryCallback( - LLPointer<LLRefCount>(NULL), - type, - index, - new_wearable, - addWearableToAgentInventoryCallback::CALL_RECOVERDONE); - addWearableToAgentInventory(cb, new_wearable, lost_and_found_id, TRUE); -} - -void LLAgentWearables::recoverMissingWearableDone() -{ - // Have all the wearables that the avatar was wearing at log-in arrived or been fabricated? - updateWearablesLoaded(); - if (areWearablesLoaded()) - { - // Make sure that the server's idea of the avatar's wearables actually match the wearables. - gAgent.sendAgentSetAppearance(); - } - else - { - gInventory.addChangedMask(LLInventoryObserver::LABEL, LLUUID::null); - gInventory.notifyObservers(); - } -} - void LLAgentWearables::addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index) { LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)wearable_type, wearable_index); @@ -957,7 +654,7 @@ public: /* virtual */ void fire(const LLUUID& inv_item) { LL_INFOS() << "One item created " << inv_item.asString() << LL_ENDL; - LLViewerInventoryItem *item = gInventory.getItem(inv_item); + LLConstPointer<LLInventoryObject> item = gInventory.getItem(inv_item); mItemsToLink.push_back(item); updatePendingWearable(inv_item); } @@ -965,9 +662,9 @@ public: { LL_INFOS() << "All items created" << LL_ENDL; LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; - LLAppearanceMgr::instance().linkAll(LLAppearanceMgr::instance().getCOF(), - mItemsToLink, - link_waiter); + link_inventory_array(LLAppearanceMgr::instance().getCOF(), + mItemsToLink, + link_waiter); } void addPendingWearable(LLViewerWearable *wearable) { @@ -1016,7 +713,7 @@ public: } private: - LLInventoryModel::item_array_t mItemsToLink; + LLInventoryObject::const_object_list_t mItemsToLink; std::vector<LLViewerWearable*> mWearablesAwaitingItems; }; @@ -1068,28 +765,38 @@ void LLAgentWearables::createStandardWearables() } } -void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index) +// We no longer need this message in the current viewer, but send +// it for now to maintain compatibility with release viewers. Can +// remove this function once the SH-3455 changesets are universally deployed. +void LLAgentWearables::sendDummyAgentWearablesUpdate() { - LL_INFOS() << "type " << type << " index " << index << LL_ENDL; + LL_DEBUGS("Avatar") << "sendAgentWearablesUpdate()" << LL_ENDL; - if (!isAgentAvatarValid()) return; - gAgentAvatarp->updateVisualParams(); -} + // Send the AgentIsNowWearing + gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); + + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -void LLAgentWearables::createStandardWearablesAllDone() -{ - // ... because sendAgentWearablesUpdate will notify inventory - // observers. - LL_INFOS() << "all done?" << LL_ENDL; + // Send 4 standardized nonsense item ids (same as returned by the modified sim, not that it especially matters). + gMessageSystem->nextBlockFast(_PREHASH_WearableData); + gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(1)); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("db5a4e5f-9da3-44c8-992d-1181c5795498")); - mWearablesLoaded = TRUE; - checkWearablesLoaded(); - notifyLoadingFinished(); - - updateServer(); + gMessageSystem->nextBlockFast(_PREHASH_WearableData); + gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(2)); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("6969c7cc-f72f-4a76-a19b-c293cce8ce4f")); + + gMessageSystem->nextBlockFast(_PREHASH_WearableData); + gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(3)); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("7999702b-b291-48f9-8903-c91dfb828408")); - // Treat this as the first texture entry message, if none received yet - gAgentAvatarp->onFirstTEMessageReceived(); + gMessageSystem->nextBlockFast(_PREHASH_WearableData); + gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(4)); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("566cb59e-ef60-41d7-bfa6-e0f293fbea40")); + + gAgent.sendReliableMessage(); } void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) @@ -1205,11 +912,10 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo for (S32 i=max_entry; i>=0; i--) { LLViewerWearable* old_wearable = getViewerWearable(type,i); - //queryWearableCache(); // moved below if (old_wearable) { popWearable(old_wearable); - old_wearable->removeFromAvatar(TRUE); + old_wearable->removeFromAvatar(); } } clearWearableType(type); @@ -1217,48 +923,99 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo else { LLViewerWearable* old_wearable = getViewerWearable(type, index); - //queryWearableCache(); // moved below if (old_wearable) { popWearable(old_wearable); - old_wearable->removeFromAvatar(TRUE); + old_wearable->removeFromAvatar(); } } - queryWearableCache(); - - // Update the server - updateServer(); gInventory.notifyObservers(); } // Assumes existing wearables are not dirty. void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& items, - const std::vector< LLViewerWearable* >& wearables, - BOOL remove) + const std::vector< LLViewerWearable* >& wearables) { LL_INFOS() << "setWearableOutfit() start" << LL_ENDL; + S32 count = wearables.size(); + llassert(items.size() == count); + + // Check for whether outfit already matches the one requested + S32 matched = 0, mismatched = 0; + const S32 arr_size = LLWearableType::WT_COUNT; + S32 type_counts[arr_size]; + std::fill(type_counts,type_counts+arr_size,0); + for (S32 i = 0; i < count; i++) + { + LLViewerWearable* new_wearable = wearables[i]; + LLPointer<LLInventoryItem> new_item = items[i]; + + const LLWearableType::EType type = new_wearable->getType(); + if (type < 0 || type>=LLWearableType::WT_COUNT) + { + LL_WARNS() << "invalid type " << type << LL_ENDL; + mismatched++; + continue; + } + S32 index = type_counts[type]; + type_counts[type]++; + + LLViewerWearable *curr_wearable = dynamic_cast<LLViewerWearable*>(getWearable(type,index)); + if (!new_wearable || !curr_wearable || + new_wearable->getAssetID() != curr_wearable->getAssetID()) + { + LL_DEBUGS("Avatar") << "mismatch, type " << type << " index " << index + << " names " << (curr_wearable ? curr_wearable->getName() : "NONE") << "," + << " names " << (new_wearable ? new_wearable->getName() : "NONE") << LL_ENDL; + mismatched++; + continue; + } + + if (curr_wearable->getName() != new_item->getName() || + curr_wearable->getItemID() != new_item->getUUID()) + { + LL_DEBUGS("Avatar") << "mismatch on name or inventory id, names " + << curr_wearable->getName() << " vs " << new_item->getName() + << " item ids " << curr_wearable->getItemID() << " vs " << new_item->getUUID() + << LL_ENDL; + mismatched++; + continue; + } + // If we got here, everything matches. + matched++; + } + LL_DEBUGS("Avatar") << "matched " << matched << " mismatched " << mismatched << LL_ENDL; + for (S32 j=0; j<LLWearableType::WT_COUNT; j++) + { + LLWearableType::EType type = (LLWearableType::EType) j; + if (getWearableCount(type) != type_counts[j]) + { + LL_DEBUGS("Avatar") << "count mismatch for type " << j << " current " << getWearableCount(j) << " requested " << type_counts[j] << LL_ENDL; + mismatched++; + } + } + if (mismatched == 0) + { + LL_DEBUGS("Avatar") << "no changes, bailing out" << LL_ENDL; + return; + } + + // TODO: Removed check for ensuring that teens don't remove undershirt and underwear. Handle later - if (remove) + // note: shirt is the first non-body part wearable item. Update if wearable order changes. + // This loop should remove all clothing, but not any body parts + for (S32 j = 0; j < (S32)LLWearableType::WT_COUNT; j++) { - // note: shirt is the first non-body part wearable item. Update if wearable order changes. - // This loop should remove all clothing, but not any body parts - for (S32 type = 0; type < (S32)LLWearableType::WT_COUNT; type++) + if (LLWearableType::getAssetType((LLWearableType::EType)j) == LLAssetType::AT_CLOTHING) { - if (LLWearableType::getAssetType((LLWearableType::EType)type) == LLAssetType::AT_CLOTHING) - { - removeWearable((LLWearableType::EType)type, true, 0); - } + removeWearable((LLWearableType::EType)j, true, 0); } } - S32 count = wearables.size(); - llassert(items.size() == count); - - S32 i; - for (i = 0; i < count; i++) + for (S32 i = 0; i < count; i++) { LLViewerWearable* new_wearable = wearables[i]; LLPointer<LLInventoryItem> new_item = items[i]; @@ -1305,14 +1062,12 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // Start rendering & update the server mWearablesLoaded = TRUE; - checkWearablesLoaded(); + notifyLoadingFinished(); - queryWearableCache(); - updateServer(); gAgentAvatarp->dumpAvatarTEs("setWearableOutfit"); - LL_DEBUGS() << "setWearableOutfit() end" << LL_ENDL; + LL_DEBUGS("Avatar") << "setWearableOutfit() end" << LL_ENDL; } @@ -1429,79 +1184,6 @@ void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWeara LL_INFOS() << "Replaced current element 0 for type " << type << " size is now " << getWearableCount(type) << LL_ENDL; } - - //LL_INFOS() << "LLVOAvatar::setWearableItem()" << LL_ENDL; - queryWearableCache(); - //new_wearable->writeToAvatar(TRUE); - - updateServer(); -} - -void LLAgentWearables::queryWearableCache() -{ - if (!areWearablesLoaded() || (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion())) - { - return; - } - - // Look up affected baked textures. - // If they exist: - // disallow updates for affected layersets (until dataserver responds with cache request.) - // If cache miss, turn updates back on and invalidate composite. - // If cache hit, modify baked texture entries. - // - // Cache requests contain list of hashes for each baked texture entry. - // Response is list of valid baked texture assets. (same message) - - gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->addS32Fast(_PREHASH_SerialNum, gAgentQueryManager.mWearablesCacheQueryID); - - S32 num_queries = 0; - for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) - { - LLUUID hash_id = computeBakedTextureHash((EBakedTextureIndex) baked_index); - if (hash_id.notNull()) - { - num_queries++; - // *NOTE: make sure at least one request gets packed - - ETextureIndex te_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index); - - //LL_INFOS() << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << LL_ENDL; - gMessageSystem->nextBlockFast(_PREHASH_WearableData); - gMessageSystem->addUUIDFast(_PREHASH_ID, hash_id); - gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)te_index); - } - - gAgentQueryManager.mActiveCacheQueries[baked_index] = gAgentQueryManager.mWearablesCacheQueryID; - } - //VWR-22113: gAgent.getRegion() can return null if invalid, seen here on logout - if(gAgent.getRegion()) - { - if (isAgentAvatarValid()) - { - selfStartPhase("fetch_texture_cache_entries"); - gAgentAvatarp->outputRezTiming("Fetching textures from cache"); - } - - LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Requesting texture cache entry for " << num_queries << " baked textures" << LL_ENDL; - gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); - gAgentQueryManager.mNumPendingQueries++; - gAgentQueryManager.mWearablesCacheQueryID++; - } -} - -// virtual -void LLAgentWearables::invalidateBakedTextureHash(LLMD5& hash) const -{ - // Add some garbage into the hash so that it becomes invalid. - if (isAgentAvatarValid()) - { - hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES); - } } // User has picked "remove from avatar" from a menu. @@ -1687,17 +1369,6 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra } } -void LLAgentWearables::checkWearablesLoaded() const -{ -#ifdef SHOW_ASSERT - U32 item_pend_count = itemUpdatePendingCount(); - if (mWearablesLoaded) - { - llassert(item_pend_count==0); - } -#endif -} - // Returns false if the given wearable is already topmost/bottommost // (depending on closer_to_body parameter). bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_body) const @@ -1714,20 +1385,9 @@ bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_bod BOOL LLAgentWearables::areWearablesLoaded() const { - checkWearablesLoaded(); return mWearablesLoaded; } -// MULTI-WEARABLE: DEPRECATED: item pending count relies on old messages that don't support multi-wearables. do not trust to be accurate -void LLAgentWearables::updateWearablesLoaded() -{ - mWearablesLoaded = (itemUpdatePendingCount()==0); - if (mWearablesLoaded) - { - notifyLoadingFinished(); - } -} - bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) const { if (!wearable) return false; @@ -1737,7 +1397,7 @@ bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) co return !(((type == LLWearableType::WT_SHAPE) || (type == LLWearableType::WT_SKIN) || (type == LLWearableType::WT_HAIR) || (type == LLWearableType::WT_EYES)) && (getWearableCount(type) <= 1) ); } -void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake) +void LLAgentWearables::animateAllWearableParams(F32 delta) { for( S32 type = 0; type < LLWearableType::WT_COUNT; ++type ) { @@ -1747,7 +1407,7 @@ void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake) llassert(wearable); if (wearable) { - wearable->animateParams(delta, upload_bake); + wearable->animateParams(delta); } } } @@ -1870,30 +1530,6 @@ void LLAgentWearables::editWearableIfRequested(const LLUUID& item_id) } } -void LLAgentWearables::updateServer() -{ - sendAgentWearablesUpdate(); - gAgent.sendAgentSetAppearance(); -} - -void LLAgentWearables::populateMyOutfitsFolder(void) -{ - LL_INFOS() << "starting outfit population" << LL_ENDL; - - const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - LLLibraryOutfitsFetch* outfits = new LLLibraryOutfitsFetch(my_outfits_id); - outfits->mMyOutfitsID = my_outfits_id; - - // Get the complete information on the items in the inventory and - // setup an observer that will wait for that to happen. - gInventory.addObserver(outfits); - outfits->startFetch(); - if (outfits->isFinished()) - { - outfits->done(); - } -} - boost::signals2::connection LLAgentWearables::addLoadingStartedCallback(loading_started_callback_t cb) { return mLoadingStartedSignal.connect(cb); @@ -1912,6 +1548,7 @@ bool LLAgentWearables::changeInProgress() const void LLAgentWearables::notifyLoadingStarted() { mCOFChangeInProgress = true; + mCOFChangeTimer.reset(); mLoadingStartedSignal(); } diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 02d24892b5..cdb1bdbe05 100755 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -42,7 +42,6 @@ class LLInventoryItem; class LLVOAvatarSelf; class LLViewerWearable; -class LLInitialWearablesFetch; class LLViewerObject; class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearableData @@ -51,7 +50,6 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // Constructors / destructors / Initializers //-------------------------------------------------------------------- public: - friend class LLInitialWearablesFetch; LLAgentWearables(); virtual ~LLAgentWearables(); @@ -62,9 +60,6 @@ public: // LLInitClass interface static void initClass(); -protected: - void createStandardWearablesDone(S32 type, U32 index/* = 0*/); - void createStandardWearablesAllDone(); //-------------------------------------------------------------------- // Queries @@ -77,6 +72,7 @@ public: BOOL isWearableCopyable(LLWearableType::EType type, U32 index /*= 0*/) const; BOOL areWearablesLoaded() const; bool isCOFChangeInProgress() const { return mCOFChangeInProgress; } + F32 getCOFChangeTime() const { return mCOFChangeTimer.getElapsedTimeF32(); } void updateWearablesLoaded(); void checkWearablesLoaded() const; bool canMoveWearable(const LLUUID& item_id, bool closer_to_body) const; @@ -84,7 +80,7 @@ public: // Note: False for shape, skin, eyes, and hair, unless you have MORE than 1. bool canWearableBeRemoved(const LLViewerWearable* wearable) const; - void animateAllWearableParams(F32 delta, BOOL upload_bake); + void animateAllWearableParams(F32 delta); //-------------------------------------------------------------------- // Accessors @@ -107,7 +103,7 @@ private: /*virtual*/void wearableUpdated(LLWearable *wearable, BOOL removed); public: void setWearableItem(LLInventoryItem* new_item, LLViewerWearable* wearable, bool do_append = false); - void setWearableOutfit(const LLInventoryItem::item_array_t& items, const std::vector< LLViewerWearable* >& wearables, BOOL remove); + void setWearableOutfit(const LLInventoryItem::item_array_t& items, const std::vector< LLViewerWearable* >& wearables); void setWearableName(const LLUUID& item_id, const std::string& new_name); // *TODO: Move this into llappearance/LLWearableData ? void addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index); @@ -151,31 +147,10 @@ private: void removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); protected: static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response); - - //-------------------------------------------------------------------- - // Server Communication - //-------------------------------------------------------------------- -public: - // Processes the initial wearables update message (if necessary, since the outfit folder makes it redundant) - static void processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data); - -protected: - /*virtual*/ void invalidateBakedTextureHash(LLMD5& hash) const; - void sendAgentWearablesUpdate(); - void sendAgentWearablesRequest(); - void queryWearableCache(); - void updateServer(); - static void onInitialWearableAssetArrived(LLViewerWearable* wearable, void* userdata); //-------------------------------------------------------------------- // Outfits //-------------------------------------------------------------------- -public: - - // Should only be called if we *know* we've never done so before, since users may - // not want the Library outfits to stay in their quick outfit selector and can delete them. - void populateMyOutfitsFolder(); - private: void makeNewOutfitDone(S32 type, U32 index); @@ -184,11 +159,16 @@ private: //-------------------------------------------------------------------- public: void saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, const std::string& description, BOOL save_in_lost_and_found); - void saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE, + void saveWearable(const LLWearableType::EType type, const U32 index, const std::string new_name = ""); void saveAllWearables(); void revertWearable(const LLWearableType::EType type, const U32 index); + // We no longer need this message in the current viewer, but send + // it for now to maintain compatibility with release viewers. Can + // remove this function once the SH-3455 changesets are universally deployed. + void sendDummyAgentWearablesUpdate(); + //-------------------------------------------------------------------- // Static UI hooks //-------------------------------------------------------------------- @@ -202,9 +182,6 @@ public: static void userRemoveMultipleAttachments(llvo_vec_t& llvo_array); static void userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array); - BOOL itemUpdatePending(const LLUUID& item_id) const; - U32 itemUpdatePendingCount() const; - //-------------------------------------------------------------------- // Signals //-------------------------------------------------------------------- @@ -231,29 +208,18 @@ private: private: static BOOL mInitialWearablesUpdateReceived; BOOL mWearablesLoaded; - std::set<LLUUID> mItemsAwaitingWearableUpdate; /** * True if agent's outfit is being changed now. */ BOOL mCOFChangeInProgress; + LLTimer mCOFChangeTimer; //-------------------------------------------------------------------------------- // Support classes //-------------------------------------------------------------------------------- private: - class createStandardWearablesAllDoneCallback : public LLRefCount - { - protected: - ~createStandardWearablesAllDoneCallback(); - }; - class sendAgentWearablesUpdateCallback : public LLRefCount - { - protected: - ~sendAgentWearablesUpdateCallback(); - }; - - class addWearableToAgentInventoryCallback : public LLInventoryCallback + class AddWearableToAgentInventoryCallback : public LLInventoryCallback { public: enum ETodo @@ -266,7 +232,7 @@ private: CALL_WEARITEM = 16 }; - addWearableToAgentInventoryCallback(LLPointer<LLRefCount> cb, + AddWearableToAgentInventoryCallback(LLPointer<LLRefCount> cb, LLWearableType::EType type, U32 index, LLViewerWearable* wearable, diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp deleted file mode 100755 index af0f02861d..0000000000 --- a/indra/newview/llagentwearablesfetch.cpp +++ /dev/null @@ -1,600 +0,0 @@ -/** - * @file llagentwearablesfetch.cpp - * @brief LLAgentWearblesFetch class implementation - * - * $LicenseInfo:firstyear=2001&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 "llagentwearablesfetch.h" - -#include "llagent.h" -#include "llagentwearables.h" -#include "llappearancemgr.h" -#include "llinventoryfunctions.h" -#include "llstartup.h" -#include "llvoavatarself.h" - - -void order_my_outfits_cb() - { - if (!LLApp::isRunning()) - { - LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; - return; - } - - const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - if (my_outfits_id.isNull()) return; - - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(my_outfits_id, cats, items); - if (!cats) return; - - //My Outfits should at least contain saved initial outfit and one another outfit - if (cats->size() < 2) - { - LL_WARNS() << "My Outfits category was not populated properly" << LL_ENDL; - return; - } - - LL_INFOS() << "Starting updating My Outfits with wearables ordering information" << LL_ENDL; - - for (LLInventoryModel::cat_array_t::iterator outfit_iter = cats->begin(); - outfit_iter != cats->end(); ++outfit_iter) - { - const LLUUID& cat_id = (*outfit_iter)->getUUID(); - if (cat_id.isNull()) continue; - - // saved initial outfit already contains wearables ordering information - if (cat_id == LLAppearanceMgr::getInstance()->getBaseOutfitUUID()) continue; - - LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(cat_id); - } - - LL_INFOS() << "Finished updating My Outfits with wearables ordering information" << LL_ENDL; - } - -LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) : - LLInventoryFetchDescendentsObserver(cof_id) -{ - if (isAgentAvatarValid()) - { - gAgentAvatarp->startPhase("initial_wearables_fetch"); - gAgentAvatarp->outputRezTiming("Initial wearables fetch started"); - } -} - -LLInitialWearablesFetch::~LLInitialWearablesFetch() -{ -} - -// virtual -void LLInitialWearablesFetch::done() -{ - // Delay processing the actual results of this so it's not handled within - // gInventory.notifyObservers. The results will be handled in the next - // idle tick instead. - gInventory.removeObserver(this); - doOnIdleOneTime(boost::bind(&LLInitialWearablesFetch::processContents,this)); - if (isAgentAvatarValid()) - { - gAgentAvatarp->stopPhase("initial_wearables_fetch"); - gAgentAvatarp->outputRezTiming("Initial wearables fetch done"); - } -} - -void LLInitialWearablesFetch::add(InitialWearableData &data) - -{ - mAgentInitialWearables.push_back(data); -} - -void LLInitialWearablesFetch::processContents() -{ - if(!gAgentAvatarp) //no need to process wearables if the agent avatar is deleted. - { - delete this; - return ; - } - - // Fetch the wearable items from the Current Outfit Folder - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t wearable_array; - LLFindWearables is_wearable; - llassert_always(mComplete.size() != 0); - gInventory.collectDescendentsIf(mComplete.front(), cat_array, wearable_array, - LLInventoryModel::EXCLUDE_TRASH, is_wearable); - - LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); - if (wearable_array.size() > 0) - { - gAgentWearables.notifyLoadingStarted(); - LLAppearanceMgr::instance().updateAppearanceFromCOF(); - } - else - { - // if we're constructing the COF from the wearables message, we don't have a proper outfit link - LLAppearanceMgr::instance().setOutfitDirty(true); - processWearablesMessage(); - } - delete this; -} - -class LLFetchAndLinkObserver: public LLInventoryFetchItemsObserver -{ -public: - LLFetchAndLinkObserver(uuid_vec_t& ids): - LLInventoryFetchItemsObserver(ids) - { - } - ~LLFetchAndLinkObserver() - { - } - virtual void done() - { - gInventory.removeObserver(this); - - // Link to all fetched items in COF. - LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; - for (uuid_vec_t::iterator it = mIDs.begin(); - it != mIDs.end(); - ++it) - { - LLUUID id = *it; - LLViewerInventoryItem *item = gInventory.getItem(*it); - if (!item) - { - LL_WARNS() << "fetch failed!" << LL_ENDL; - continue; - } - - link_inventory_item(gAgent.getID(), - item->getLinkedUUID(), - LLAppearanceMgr::instance().getCOF(), - item->getName(), - item->getDescription(), - LLAssetType::AT_LINK, - link_waiter); - } - } -}; - -void LLInitialWearablesFetch::processWearablesMessage() -{ - if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead. - { - const LLUUID current_outfit_id = LLAppearanceMgr::instance().getCOF(); - uuid_vec_t ids; - for (U8 i = 0; i < mAgentInitialWearables.size(); ++i) - { - // Populate the current outfit folder with links to the wearables passed in the message - InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback. - - if (wearable_data->mAssetID.notNull()) - { - ids.push_back(wearable_data->mItemID); - } - else - { - LL_INFOS() << "Invalid wearable, type " << wearable_data->mType << " itemID " - << wearable_data->mItemID << " assetID " << wearable_data->mAssetID << LL_ENDL; - delete wearable_data; - } - } - - // Add all current attachments to the requested items as well. - if (isAgentAvatarValid()) - { - for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - if (!attachment) continue; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - LLViewerObject* attached_object = (*attachment_iter); - if (!attached_object) continue; - const LLUUID& item_id = attached_object->getAttachmentItemID(); - if (item_id.isNull()) continue; - ids.push_back(item_id); - } - } - } - - // Need to fetch the inventory items for ids, then create links to them after they arrive. - LLFetchAndLinkObserver *fetcher = new LLFetchAndLinkObserver(ids); - fetcher->startFetch(); - // If no items to be fetched, done will never be triggered. - // TODO: Change LLInventoryFetchItemsObserver::fetchItems to trigger done() on this condition. - if (fetcher->isFinished()) - { - fetcher->done(); - } - else - { - gInventory.addObserver(fetcher); - } - } - else - { - LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL; - } -} - -LLLibraryOutfitsFetch::LLLibraryOutfitsFetch(const LLUUID& my_outfits_id) : - LLInventoryFetchDescendentsObserver(my_outfits_id), - mCurrFetchStep(LOFS_FOLDER), - mOutfitsPopulated(false) -{ - LL_INFOS() << "created" << LL_ENDL; - - mMyOutfitsID = LLUUID::null; - mClothingID = LLUUID::null; - mLibraryClothingID = LLUUID::null; - mImportedClothingID = LLUUID::null; - mImportedClothingName = "Imported Library Clothing"; -} - -LLLibraryOutfitsFetch::~LLLibraryOutfitsFetch() -{ - LL_INFOS() << "destroyed" << LL_ENDL; -} - -void LLLibraryOutfitsFetch::done() -{ - LL_INFOS() << "start" << LL_ENDL; - - // Delay this until idle() routine, since it's a heavy operation and - // we also can't have it run within notifyObservers. - doOnIdleOneTime(boost::bind(&LLLibraryOutfitsFetch::doneIdle,this)); - gInventory.removeObserver(this); // Prevent doOnIdleOneTime from being added twice. -} - -void LLLibraryOutfitsFetch::doneIdle() -{ - LL_INFOS() << "start" << LL_ENDL; - - gInventory.addObserver(this); // Add this back in since it was taken out during ::done() - - switch (mCurrFetchStep) - { - case LOFS_FOLDER: - folderDone(); - mCurrFetchStep = LOFS_OUTFITS; - break; - case LOFS_OUTFITS: - outfitsDone(); - mCurrFetchStep = LOFS_LIBRARY; - break; - case LOFS_LIBRARY: - libraryDone(); - mCurrFetchStep = LOFS_IMPORTED; - break; - case LOFS_IMPORTED: - importedFolderDone(); - mCurrFetchStep = LOFS_CONTENTS; - break; - case LOFS_CONTENTS: - contentsDone(); - break; - default: - LL_WARNS() << "Got invalid state for outfit fetch: " << mCurrFetchStep << LL_ENDL; - mOutfitsPopulated = TRUE; - break; - } - - // We're completely done. Cleanup. - if (mOutfitsPopulated) - { - gInventory.removeObserver(this); - delete this; - return; - } -} - -void LLLibraryOutfitsFetch::folderDone() -{ - LL_INFOS() << "start" << LL_ENDL; - - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t wearable_array; - gInventory.collectDescendents(mMyOutfitsID, cat_array, wearable_array, - LLInventoryModel::EXCLUDE_TRASH); - - // Early out if we already have items in My Outfits - // except the case when My Outfits contains just initial outfit - if (cat_array.size() > 1) - { - mOutfitsPopulated = true; - return; - } - - mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); - mLibraryClothingID = gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_CLOTHING, false); - - // If Library->Clothing->Initial Outfits exists, use that. - LLNameCategoryCollector matchFolderFunctor("Initial Outfits"); - cat_array.clear(); - gInventory.collectDescendentsIf(mLibraryClothingID, - cat_array, wearable_array, - LLInventoryModel::EXCLUDE_TRASH, - matchFolderFunctor); - if (cat_array.size() > 0) - { - const LLViewerInventoryCategory *cat = cat_array.at(0); - mLibraryClothingID = cat->getUUID(); - } - - mComplete.clear(); - - // Get the complete information on the items in the inventory. - uuid_vec_t folders; - folders.push_back(mClothingID); - folders.push_back(mLibraryClothingID); - setFetchIDs(folders); - startFetch(); - if (isFinished()) - { - done(); - } -} - -void LLLibraryOutfitsFetch::outfitsDone() -{ - LL_INFOS() << "start" << LL_ENDL; - - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t wearable_array; - uuid_vec_t folders; - - // Collect the contents of the Library's Clothing folder - gInventory.collectDescendents(mLibraryClothingID, cat_array, wearable_array, - LLInventoryModel::EXCLUDE_TRASH); - - llassert(cat_array.size() > 0); - for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); - iter != cat_array.end(); - ++iter) - { - const LLViewerInventoryCategory *cat = iter->get(); - - // Get the names and id's of every outfit in the library, skip "Ruth" - // because it's a low quality legacy outfit - if (cat->getName() != "Ruth") - { - // Get the name of every outfit in the library - folders.push_back(cat->getUUID()); - mLibraryClothingFolders.push_back(cat->getUUID()); - } - } - cat_array.clear(); - wearable_array.clear(); - - // Check if you already have an "Imported Library Clothing" folder - LLNameCategoryCollector matchFolderFunctor(mImportedClothingName); - gInventory.collectDescendentsIf(mClothingID, - cat_array, wearable_array, - LLInventoryModel::EXCLUDE_TRASH, - matchFolderFunctor); - if (cat_array.size() > 0) - { - const LLViewerInventoryCategory *cat = cat_array.at(0); - mImportedClothingID = cat->getUUID(); - } - - mComplete.clear(); - setFetchIDs(folders); - startFetch(); - if (isFinished()) - { - done(); - } -} - -class LLLibraryOutfitsCopyDone: public LLInventoryCallback -{ -public: - LLLibraryOutfitsCopyDone(LLLibraryOutfitsFetch * fetcher): - mFireCount(0), mLibraryOutfitsFetcher(fetcher) - { - } - - virtual ~LLLibraryOutfitsCopyDone() - { - if (!LLApp::isExiting() && mLibraryOutfitsFetcher) - { - gInventory.addObserver(mLibraryOutfitsFetcher); - mLibraryOutfitsFetcher->done(); - } - } - - /* virtual */ void fire(const LLUUID& inv_item) - { - mFireCount++; - } -private: - U32 mFireCount; - LLLibraryOutfitsFetch * mLibraryOutfitsFetcher; -}; - -// Copy the clothing folders from the library into the imported clothing folder -void LLLibraryOutfitsFetch::libraryDone() -{ - LL_INFOS() << "start" << LL_ENDL; - - if (mImportedClothingID != LLUUID::null) - { - // Skip straight to fetching the contents of the imported folder - importedFolderFetch(); - return; - } - - // Remove observer; next autopopulation step will be triggered externally by LLLibraryOutfitsCopyDone. - gInventory.removeObserver(this); - - LLPointer<LLInventoryCallback> copy_waiter = new LLLibraryOutfitsCopyDone(this); - mImportedClothingID = gInventory.createNewCategory(mClothingID, - LLFolderType::FT_NONE, - mImportedClothingName); - // Copy each folder from library into clothing unless it already exists. - for (uuid_vec_t::const_iterator iter = mLibraryClothingFolders.begin(); - iter != mLibraryClothingFolders.end(); - ++iter) - { - const LLUUID& src_folder_id = (*iter); // Library clothing folder ID - const LLViewerInventoryCategory *cat = gInventory.getCategory(src_folder_id); - if (!cat) - { - LL_WARNS() << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << LL_ENDL; - continue; - } - - if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id)) - { - LL_INFOS() << "Skipping non-outfit folder name:" << cat->getName() << LL_ENDL; - continue; - } - - // Don't copy the category if it already exists. - LLNameCategoryCollector matchFolderFunctor(cat->getName()); - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t wearable_array; - gInventory.collectDescendentsIf(mImportedClothingID, - cat_array, wearable_array, - LLInventoryModel::EXCLUDE_TRASH, - matchFolderFunctor); - if (cat_array.size() > 0) - { - continue; - } - - LLUUID dst_folder_id = gInventory.createNewCategory(mImportedClothingID, - LLFolderType::FT_NONE, - cat->getName()); - LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_folder_id, dst_folder_id, copy_waiter); - } -} - -void LLLibraryOutfitsFetch::importedFolderFetch() -{ - LL_INFOS() << "start" << LL_ENDL; - - // Fetch the contents of the Imported Clothing Folder - uuid_vec_t folders; - folders.push_back(mImportedClothingID); - - mComplete.clear(); - setFetchIDs(folders); - startFetch(); - if (isFinished()) - { - done(); - } -} - -void LLLibraryOutfitsFetch::importedFolderDone() -{ - LL_INFOS() << "start" << LL_ENDL; - - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t wearable_array; - uuid_vec_t folders; - - // Collect the contents of the Imported Clothing folder - gInventory.collectDescendents(mImportedClothingID, cat_array, wearable_array, - LLInventoryModel::EXCLUDE_TRASH); - - for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); - iter != cat_array.end(); - ++iter) - { - const LLViewerInventoryCategory *cat = iter->get(); - - // Get the name of every imported outfit - folders.push_back(cat->getUUID()); - mImportedClothingFolders.push_back(cat->getUUID()); - } - - mComplete.clear(); - setFetchIDs(folders); - startFetch(); - if (isFinished()) - { - done(); - } -} - -void LLLibraryOutfitsFetch::contentsDone() -{ - LL_INFOS() << "start" << LL_ENDL; - - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t wearable_array; - - LLPointer<LLInventoryCallback> order_myoutfits_on_destroy = new LLBoostFuncInventoryCallback(no_op_inventory_func, order_my_outfits_cb); - - for (uuid_vec_t::const_iterator folder_iter = mImportedClothingFolders.begin(); - folder_iter != mImportedClothingFolders.end(); - ++folder_iter) - { - const LLUUID &folder_id = (*folder_iter); - const LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id); - if (!cat) - { - LL_WARNS() << "Library folder import for uuid:" << folder_id << " failed to find folder." << LL_ENDL; - continue; - } - - //initial outfit should be already in My Outfits - if (cat->getName() == LLStartUp::getInitialOutfitName()) continue; - - // First, make a folder in the My Outfits directory. - LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, cat->getName()); - - cat_array.clear(); - wearable_array.clear(); - // Collect the contents of each imported clothing folder, so we can create new outfit links for it - gInventory.collectDescendents(folder_id, cat_array, wearable_array, - LLInventoryModel::EXCLUDE_TRASH); - - for (LLInventoryModel::item_array_t::const_iterator wearable_iter = wearable_array.begin(); - wearable_iter != wearable_array.end(); - ++wearable_iter) - { - const LLViewerInventoryItem *item = wearable_iter->get(); - link_inventory_item(gAgent.getID(), - item->getLinkedUUID(), - new_outfit_folder_id, - item->getName(), - item->getDescription(), - LLAssetType::AT_LINK, - order_myoutfits_on_destroy); - } - } - - mOutfitsPopulated = true; -} - diff --git a/indra/newview/llagentwearablesfetch.h b/indra/newview/llagentwearablesfetch.h deleted file mode 100755 index bedc445c0e..0000000000 --- a/indra/newview/llagentwearablesfetch.h +++ /dev/null @@ -1,114 +0,0 @@ -/** - * @file llagentwearablesinitialfetch.h - * @brief LLAgentWearablesInitialFetch class header file - * - * $LicenseInfo:firstyear=2000&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_LLAGENTWEARABLESINITIALFETCH_H -#define LL_LLAGENTWEARABLESINITIALFETCH_H - -#include "llinventoryobserver.h" -#include "llwearabletype.h" -#include "lluuid.h" - -//-------------------------------------------------------------------- -// InitialWearablesFetch -// -// This grabs contents from the COF and processes them. -// The processing is handled in idle(), i.e. outside of done(), -// to avoid gInventory.notifyObservers recursion. -//-------------------------------------------------------------------- -class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver -{ - LOG_CLASS(LLInitialWearablesFetch); - -public: - LLInitialWearablesFetch(const LLUUID& cof_id); - ~LLInitialWearablesFetch(); - virtual void done(); - - struct InitialWearableData - { - LLWearableType::EType mType; - LLUUID mItemID; - LLUUID mAssetID; - InitialWearableData(LLWearableType::EType type, LLUUID& itemID, LLUUID& assetID) : - mType(type), - mItemID(itemID), - mAssetID(assetID) - {} - }; - - void add(InitialWearableData &data); - -protected: - void processWearablesMessage(); - void processContents(); - -private: - typedef std::vector<InitialWearableData> initial_wearable_data_vec_t; - initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg -}; - -//-------------------------------------------------------------------- -// InitialWearablesFetch -// -// This grabs outfits from the Library and copies those over to the user's -// outfits folder, typically during first-ever login. -//-------------------------------------------------------------------- -class LLLibraryOutfitsFetch : public LLInventoryFetchDescendentsObserver -{ -public: - enum ELibraryOutfitFetchStep - { - LOFS_FOLDER = 0, - LOFS_OUTFITS, - LOFS_LIBRARY, - LOFS_IMPORTED, - LOFS_CONTENTS - }; - - LLLibraryOutfitsFetch(const LLUUID& my_outfits_id); - ~LLLibraryOutfitsFetch(); - - virtual void done(); - void doneIdle(); - LLUUID mMyOutfitsID; - void importedFolderFetch(); -protected: - void folderDone(); - void outfitsDone(); - void libraryDone(); - void importedFolderDone(); - void contentsDone(); - enum ELibraryOutfitFetchStep mCurrFetchStep; - uuid_vec_t mLibraryClothingFolders; - uuid_vec_t mImportedClothingFolders; - bool mOutfitsPopulated; - LLUUID mClothingID; - LLUUID mLibraryClothingID; - LLUUID mImportedClothingID; - std::string mImportedClothingName; -}; - -#endif // LL_AGENTWEARABLESINITIALFETCH_H diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp new file mode 100755 index 0000000000..da66ea357a --- /dev/null +++ b/indra/newview/llaisapi.cpp @@ -0,0 +1,867 @@ +/** + * @file llaisapi.cpp + * @brief classes and functions for interfacing with the v3+ ais inventory service. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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 "llagent.h" +#include "llcallbacklist.h" +#include "llinventorymodel.h" +#include "llsdutil.h" +#include "llviewerregion.h" +#include "llinventoryobserver.h" + +///---------------------------------------------------------------------------- +/// Classes for AISv3 support. +///---------------------------------------------------------------------------- + +// AISCommand - base class for retry-able HTTP requests using the AISv3 cap. +AISCommand::AISCommand(LLPointer<LLInventoryCallback> callback): + mCommandFunc(NULL), + mCallback(callback) +{ + mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10); +} + +bool AISCommand::run_command() +{ + if (NULL == mCommandFunc) + { + // This may happen if a command failed to initiate itself. + LL_WARNS("Inventory") << "AIS command attempted with null command function" << LL_ENDL; + return false; + } + else + { + mCommandFunc(); + return true; + } +} + +void AISCommand::setCommandFunc(command_func_type command_func) +{ + mCommandFunc = command_func; +} + +// virtual +bool AISCommand::getResponseUUID(const LLSD& content, LLUUID& id) +{ + return false; +} + +/* virtual */ +void AISCommand::httpSuccess() +{ + // Command func holds a reference to self, need to release it + // after a success or final failure. + setCommandFunc(no_op); + + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + mRetryPolicy->onSuccess(); + + gInventory.onAISUpdateReceived("AISCommand", content); + + if (mCallback) + { + LLUUID id; // will default to null if parse fails. + getResponseUUID(content,id); + mCallback->fire(id); + } +} + +/*virtual*/ +void AISCommand::httpFailure() +{ + LL_WARNS("Inventory") << dumpResponse() << LL_ENDL; + S32 status = getStatus(); + const LLSD& headers = getResponseHeaders(); + mRetryPolicy->onFailure(status, headers); + F32 seconds_to_wait; + if (mRetryPolicy->shouldRetry(seconds_to_wait)) + { + doAfterInterval(boost::bind(&AISCommand::run_command,this),seconds_to_wait); + } + else + { + // Command func holds a reference to self, need to release it + // after a success or final failure. + // *TODO: Notify user? This seems bad. + setCommandFunc(no_op); + } +} + +//static +bool AISCommand::isAPIAvailable() +{ + if (gAgent.getRegion()) + { + return gAgent.getRegion()->isCapabilityAvailable("InventoryAPIv3"); + } + return false; +} + +//static +bool AISCommand::getInvCap(std::string& cap) +{ + if (gAgent.getRegion()) + { + cap = gAgent.getRegion()->getCapability("InventoryAPIv3"); + } + if (!cap.empty()) + { + return true; + } + return false; +} + +//static +bool AISCommand::getLibCap(std::string& cap) +{ + if (gAgent.getRegion()) + { + cap = gAgent.getRegion()->getCapability("LibraryAPIv3"); + } + if (!cap.empty()) + { + return true; + } + return false; +} + +//static +void AISCommand::getCapabilityNames(LLSD& capabilityNames) +{ + capabilityNames.append("InventoryAPIv3"); + capabilityNames.append("LibraryAPIv3"); +} + +RemoveItemCommand::RemoveItemCommand(const LLUUID& item_id, + LLPointer<LLInventoryCallback> callback): + AISCommand(callback) +{ + std::string cap; + if (!getInvCap(cap)) + { + LL_WARNS() << "No cap found" << LL_ENDL; + return; + } + std::string url = cap + std::string("/item/") + item_id.asString(); + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + LLHTTPClient::ResponderPtr responder = this; + LLSD headers; + F32 timeout = HTTP_REQUEST_EXPIRY_SECS; + command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout); + setCommandFunc(cmd); +} + +RemoveCategoryCommand::RemoveCategoryCommand(const LLUUID& item_id, + LLPointer<LLInventoryCallback> callback): + AISCommand(callback) +{ + std::string cap; + if (!getInvCap(cap)) + { + LL_WARNS() << "No cap found" << LL_ENDL; + return; + } + std::string url = cap + std::string("/category/") + item_id.asString(); + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + LLHTTPClient::ResponderPtr responder = this; + LLSD headers; + F32 timeout = HTTP_REQUEST_EXPIRY_SECS; + command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout); + setCommandFunc(cmd); +} + +PurgeDescendentsCommand::PurgeDescendentsCommand(const LLUUID& item_id, + LLPointer<LLInventoryCallback> callback): + AISCommand(callback) +{ + std::string cap; + if (!getInvCap(cap)) + { + LL_WARNS() << "No cap found" << LL_ENDL; + return; + } + std::string url = cap + std::string("/category/") + item_id.asString() + "/children"; + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + LLCurl::ResponderPtr responder = this; + LLSD headers; + F32 timeout = HTTP_REQUEST_EXPIRY_SECS; + command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout); + setCommandFunc(cmd); +} + +UpdateItemCommand::UpdateItemCommand(const LLUUID& item_id, + const LLSD& updates, + LLPointer<LLInventoryCallback> callback): + mUpdates(updates), + AISCommand(callback) +{ + std::string cap; + if (!getInvCap(cap)) + { + LL_WARNS() << "No cap found" << LL_ENDL; + return; + } + std::string url = cap + std::string("/item/") + item_id.asString(); + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + LL_DEBUGS("Inventory") << "request: " << ll_pretty_print_sd(mUpdates) << LL_ENDL; + LLCurl::ResponderPtr responder = this; + LLSD headers; + headers["Content-Type"] = "application/llsd+xml"; + F32 timeout = HTTP_REQUEST_EXPIRY_SECS; + command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout); + setCommandFunc(cmd); +} + +UpdateCategoryCommand::UpdateCategoryCommand(const LLUUID& cat_id, + const LLSD& updates, + LLPointer<LLInventoryCallback> callback): + mUpdates(updates), + AISCommand(callback) +{ + std::string cap; + if (!getInvCap(cap)) + { + LL_WARNS() << "No cap found" << LL_ENDL; + return; + } + std::string url = cap + std::string("/category/") + cat_id.asString(); + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + LLCurl::ResponderPtr responder = this; + LLSD headers; + headers["Content-Type"] = "application/llsd+xml"; + F32 timeout = HTTP_REQUEST_EXPIRY_SECS; + command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout); + setCommandFunc(cmd); +} + +CreateInventoryCommand::CreateInventoryCommand(const LLUUID& parent_id, + const LLSD& new_inventory, + LLPointer<LLInventoryCallback> callback): + mNewInventory(new_inventory), + AISCommand(callback) +{ + std::string cap; + if (!getInvCap(cap)) + { + LL_WARNS() << "No cap found" << LL_ENDL; + return; + } + LLUUID tid; + tid.generate(); + std::string url = cap + std::string("/category/") + parent_id.asString() + "?tid=" + tid.asString(); + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + LLCurl::ResponderPtr responder = this; + LLSD headers; + headers["Content-Type"] = "application/llsd+xml"; + F32 timeout = HTTP_REQUEST_EXPIRY_SECS; + command_func_type cmd = boost::bind(&LLHTTPClient::post, url, mNewInventory, responder, headers, timeout); + setCommandFunc(cmd); +} + +SlamFolderCommand::SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback): + mContents(contents), + AISCommand(callback) +{ + std::string cap; + if (!getInvCap(cap)) + { + LL_WARNS() << "No cap found" << LL_ENDL; + return; + } + LLUUID tid; + tid.generate(); + std::string url = cap + std::string("/category/") + folder_id.asString() + "/links?tid=" + tid.asString(); + LL_INFOS() << url << LL_ENDL; + LLCurl::ResponderPtr responder = this; + LLSD headers; + headers["Content-Type"] = "application/llsd+xml"; + F32 timeout = HTTP_REQUEST_EXPIRY_SECS; + command_func_type cmd = boost::bind(&LLHTTPClient::put, url, mContents, responder, headers, timeout); + setCommandFunc(cmd); +} + +CopyLibraryCategoryCommand::CopyLibraryCategoryCommand(const LLUUID& source_id, + const LLUUID& dest_id, + LLPointer<LLInventoryCallback> callback): + AISCommand(callback) +{ + std::string cap; + if (!getLibCap(cap)) + { + LL_WARNS() << "No cap found" << LL_ENDL; + return; + } + LL_DEBUGS("Inventory") << "Copying library category: " << source_id << " => " << dest_id << LL_ENDL; + LLUUID tid; + tid.generate(); + std::string url = cap + std::string("/category/") + source_id.asString() + "?tid=" + tid.asString(); + LL_INFOS() << url << LL_ENDL; + LLCurl::ResponderPtr responder = this; + LLSD headers; + F32 timeout = HTTP_REQUEST_EXPIRY_SECS; + command_func_type cmd = boost::bind(&LLHTTPClient::copy, url, dest_id.asString(), responder, headers, timeout); + setCommandFunc(cmd); +} + +bool CopyLibraryCategoryCommand::getResponseUUID(const LLSD& content, LLUUID& id) +{ + if (content.has("category_id")) + { + id = content["category_id"]; + return true; + } + return false; +} + +AISUpdate::AISUpdate(const LLSD& update) +{ + parseUpdate(update); +} + +void AISUpdate::clearParseResults() +{ + mCatDescendentDeltas.clear(); + mCatDescendentsKnown.clear(); + mCatVersionsUpdated.clear(); + mItemsCreated.clear(); + mItemsUpdated.clear(); + mCategoriesCreated.clear(); + mCategoriesUpdated.clear(); + mObjectsDeletedIds.clear(); + mItemIds.clear(); + mCategoryIds.clear(); +} + +void AISUpdate::parseUpdate(const LLSD& update) +{ + clearParseResults(); + parseMeta(update); + parseContent(update); +} + +void AISUpdate::parseMeta(const LLSD& update) +{ + // parse _categories_removed -> mObjectsDeletedIds + uuid_list_t cat_ids; + parseUUIDArray(update,"_categories_removed",cat_ids); + for (uuid_list_t::const_iterator it = cat_ids.begin(); + it != cat_ids.end(); ++it) + { + LLViewerInventoryCategory *cat = gInventory.getCategory(*it); + mCatDescendentDeltas[cat->getParentUUID()]--; + mObjectsDeletedIds.insert(*it); + } + + // parse _categories_items_removed -> mObjectsDeletedIds + uuid_list_t item_ids; + parseUUIDArray(update,"_category_items_removed",item_ids); + parseUUIDArray(update,"_removed_items",item_ids); + for (uuid_list_t::const_iterator it = item_ids.begin(); + it != item_ids.end(); ++it) + { + LLViewerInventoryItem *item = gInventory.getItem(*it); + mCatDescendentDeltas[item->getParentUUID()]--; + mObjectsDeletedIds.insert(*it); + } + + // parse _broken_links_removed -> mObjectsDeletedIds + uuid_list_t broken_link_ids; + parseUUIDArray(update,"_broken_links_removed",broken_link_ids); + for (uuid_list_t::const_iterator it = broken_link_ids.begin(); + it != broken_link_ids.end(); ++it) + { + LLViewerInventoryItem *item = gInventory.getItem(*it); + mCatDescendentDeltas[item->getParentUUID()]--; + mObjectsDeletedIds.insert(*it); + } + + // parse _created_items + parseUUIDArray(update,"_created_items",mItemIds); + + // parse _created_categories + parseUUIDArray(update,"_created_categories",mCategoryIds); + + // Parse updated category versions. + const std::string& ucv = "_updated_category_versions"; + if (update.has(ucv)) + { + for(LLSD::map_const_iterator it = update[ucv].beginMap(), + end = update[ucv].endMap(); + it != end; ++it) + { + const LLUUID id((*it).first); + S32 version = (*it).second.asInteger(); + mCatVersionsUpdated[id] = version; + } + } +} + +void AISUpdate::parseContent(const LLSD& update) +{ + if (update.has("linked_id")) + { + parseLink(update); + } + else if (update.has("item_id")) + { + parseItem(update); + } + + if (update.has("category_id")) + { + parseCategory(update); + } + else + { + if (update.has("_embedded")) + { + parseEmbedded(update["_embedded"]); + } + } +} + +void AISUpdate::parseItem(const LLSD& item_map) +{ + LLUUID item_id = item_map["item_id"].asUUID(); + LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem); + LLViewerInventoryItem *curr_item = gInventory.getItem(item_id); + if (curr_item) + { + // Default to current values where not provided. + new_item->copyViewerItem(curr_item); + } + BOOL rv = new_item->unpackMessage(item_map); + if (rv) + { + if (curr_item) + { + mItemsUpdated[item_id] = new_item; + // This statement is here to cause a new entry with 0 + // delta to be created if it does not already exist; + // otherwise has no effect. + mCatDescendentDeltas[new_item->getParentUUID()]; + } + else + { + mItemsCreated[item_id] = new_item; + mCatDescendentDeltas[new_item->getParentUUID()]++; + } + } + else + { + // *TODO: Wow, harsh. Should we just complain and get out? + LL_ERRS() << "unpack failed" << LL_ENDL; + } +} + +void AISUpdate::parseLink(const LLSD& link_map) +{ + LLUUID item_id = link_map["item_id"].asUUID(); + LLPointer<LLViewerInventoryItem> new_link(new LLViewerInventoryItem); + LLViewerInventoryItem *curr_link = gInventory.getItem(item_id); + if (curr_link) + { + // Default to current values where not provided. + new_link->copyViewerItem(curr_link); + } + BOOL rv = new_link->unpackMessage(link_map); + if (rv) + { + const LLUUID& parent_id = new_link->getParentUUID(); + if (curr_link) + { + mItemsUpdated[item_id] = new_link; + // This statement is here to cause a new entry with 0 + // delta to be created if it does not already exist; + // otherwise has no effect. + mCatDescendentDeltas[parent_id]; + } + else + { + LLPermissions default_perms; + default_perms.init(gAgent.getID(),gAgent.getID(),LLUUID::null,LLUUID::null); + default_perms.initMasks(PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE); + new_link->setPermissions(default_perms); + LLSaleInfo default_sale_info; + new_link->setSaleInfo(default_sale_info); + //LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL; + mItemsCreated[item_id] = new_link; + mCatDescendentDeltas[parent_id]++; + } + } + else + { + // *TODO: Wow, harsh. Should we just complain and get out? + LL_ERRS() << "unpack failed" << LL_ENDL; + } +} + + +void AISUpdate::parseCategory(const LLSD& category_map) +{ + LLUUID category_id = category_map["category_id"].asUUID(); + + // Check descendent count first, as it may be needed + // to populate newly created categories + if (category_map.has("_embedded")) + { + parseDescendentCount(category_id, category_map["_embedded"]); + } + + LLPointer<LLViewerInventoryCategory> new_cat(new LLViewerInventoryCategory(category_id)); + LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id); + if (curr_cat) + { + // Default to current values where not provided. + new_cat->copyViewerCategory(curr_cat); + } + BOOL rv = new_cat->unpackMessage(category_map); + // *NOTE: unpackMessage does not unpack version or descendent count. + //if (category_map.has("version")) + //{ + // mCatVersionsUpdated[category_id] = category_map["version"].asInteger(); + //} + if (rv) + { + if (curr_cat) + { + mCategoriesUpdated[category_id] = new_cat; + // This statement is here to cause a new entry with 0 + // delta to be created if it does not already exist; + // otherwise has no effect. + mCatDescendentDeltas[new_cat->getParentUUID()]; + // Capture update for the category itself as well. + mCatDescendentDeltas[category_id]; + } + else + { + // Set version/descendents for newly created categories. + if (category_map.has("version")) + { + S32 version = category_map["version"].asInteger(); + LL_DEBUGS("Inventory") << "Setting version to " << version + << " for new category " << category_id << LL_ENDL; + new_cat->setVersion(version); + } + uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id); + if (mCatDescendentsKnown.end() != lookup_it) + { + S32 descendent_count = lookup_it->second; + LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count + << " for new category " << category_id << LL_ENDL; + new_cat->setDescendentCount(descendent_count); + } + mCategoriesCreated[category_id] = new_cat; + mCatDescendentDeltas[new_cat->getParentUUID()]++; + } + } + else + { + // *TODO: Wow, harsh. Should we just complain and get out? + LL_ERRS() << "unpack failed" << LL_ENDL; + } + + // Check for more embedded content. + if (category_map.has("_embedded")) + { + parseEmbedded(category_map["_embedded"]); + } +} + +void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embedded) +{ + // We can only determine true descendent count if this contains all descendent types. + if (embedded.has("categories") && + embedded.has("links") && + embedded.has("items")) + { + mCatDescendentsKnown[category_id] = embedded["categories"].size(); + mCatDescendentsKnown[category_id] += embedded["links"].size(); + mCatDescendentsKnown[category_id] += embedded["items"].size(); + } +} + +void AISUpdate::parseEmbedded(const LLSD& embedded) +{ + if (embedded.has("links")) // _embedded in a category + { + parseEmbeddedLinks(embedded["links"]); + } + if (embedded.has("items")) // _embedded in a category + { + parseEmbeddedItems(embedded["items"]); + } + if (embedded.has("item")) // _embedded in a link + { + parseEmbeddedItem(embedded["item"]); + } + if (embedded.has("categories")) // _embedded in a category + { + parseEmbeddedCategories(embedded["categories"]); + } + if (embedded.has("category")) // _embedded in a link + { + parseEmbeddedCategory(embedded["category"]); + } +} + +void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids) +{ + if (content.has(name)) + { + for(LLSD::array_const_iterator it = content[name].beginArray(), + end = content[name].endArray(); + it != end; ++it) + { + ids.insert((*it).asUUID()); + } + } +} + +void AISUpdate::parseEmbeddedLinks(const LLSD& links) +{ + for(LLSD::map_const_iterator linkit = links.beginMap(), + linkend = links.endMap(); + linkit != linkend; ++linkit) + { + const LLUUID link_id((*linkit).first); + const LLSD& link_map = (*linkit).second; + if (mItemIds.end() == mItemIds.find(link_id)) + { + LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL; + } + else + { + parseLink(link_map); + } + } +} + +void AISUpdate::parseEmbeddedItem(const LLSD& item) +{ + // a single item (_embedded in a link) + if (item.has("item_id")) + { + if (mItemIds.end() != mItemIds.find(item["item_id"].asUUID())) + { + parseItem(item); + } + } +} + +void AISUpdate::parseEmbeddedItems(const LLSD& items) +{ + // a map of items (_embedded in a category) + for(LLSD::map_const_iterator itemit = items.beginMap(), + itemend = items.endMap(); + itemit != itemend; ++itemit) + { + const LLUUID item_id((*itemit).first); + const LLSD& item_map = (*itemit).second; + if (mItemIds.end() == mItemIds.find(item_id)) + { + LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL; + } + else + { + parseItem(item_map); + } + } +} + +void AISUpdate::parseEmbeddedCategory(const LLSD& category) +{ + // a single category (_embedded in a link) + if (category.has("category_id")) + { + if (mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID())) + { + parseCategory(category); + } + } +} + +void AISUpdate::parseEmbeddedCategories(const LLSD& categories) +{ + // a map of categories (_embedded in a category) + for(LLSD::map_const_iterator categoryit = categories.beginMap(), + categoryend = categories.endMap(); + categoryit != categoryend; ++categoryit) + { + const LLUUID category_id((*categoryit).first); + const LLSD& category_map = (*categoryit).second; + if (mCategoryIds.end() == mCategoryIds.find(category_id)) + { + LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL; + } + else + { + parseCategory(category_map); + } + } +} + +void AISUpdate::doUpdate() +{ + // Do version/descendent accounting. + for (std::map<LLUUID,S32>::const_iterator catit = mCatDescendentDeltas.begin(); + catit != mCatDescendentDeltas.end(); ++catit) + { + LL_DEBUGS("Inventory") << "descendent accounting for " << catit->first << LL_ENDL; + + const LLUUID cat_id(catit->first); + // Don't account for update if we just created this category. + if (mCategoriesCreated.find(cat_id) != mCategoriesCreated.end()) + { + LL_DEBUGS("Inventory") << "Skipping version increment for new category " << cat_id << LL_ENDL; + continue; + } + + // Don't account for update unless AIS told us it updated that category. + if (mCatVersionsUpdated.find(cat_id) == mCatVersionsUpdated.end()) + { + LL_DEBUGS("Inventory") << "Skipping version increment for non-updated category " << cat_id << LL_ENDL; + continue; + } + + // If we have a known descendent count, set that now. + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + if (cat) + { + S32 descendent_delta = catit->second; + S32 old_count = cat->getDescendentCount(); + LL_DEBUGS("Inventory") << "Updating descendent count for " + << cat->getName() << " " << cat_id + << " with delta " << descendent_delta << " from " + << old_count << " to " << (old_count+descendent_delta) << LL_ENDL; + LLInventoryModel::LLCategoryUpdate up(cat_id, descendent_delta); + gInventory.accountForUpdate(up); + } + else + { + LL_DEBUGS("Inventory") << "Skipping version accounting for unknown category " << cat_id << LL_ENDL; + } + } + + // CREATE CATEGORIES + for (deferred_category_map_t::const_iterator create_it = mCategoriesCreated.begin(); + create_it != mCategoriesCreated.end(); ++create_it) + { + LLUUID category_id(create_it->first); + LLPointer<LLViewerInventoryCategory> new_category = create_it->second; + + gInventory.updateCategory(new_category, LLInventoryObserver::CREATE); + LL_DEBUGS("Inventory") << "created category " << category_id << LL_ENDL; + } + + // UPDATE CATEGORIES + for (deferred_category_map_t::const_iterator update_it = mCategoriesUpdated.begin(); + update_it != mCategoriesUpdated.end(); ++update_it) + { + LLUUID category_id(update_it->first); + LLPointer<LLViewerInventoryCategory> new_category = update_it->second; + // Since this is a copy of the category *before* the accounting update, above, + // we need to transfer back the updated version/descendent count. + LLViewerInventoryCategory* curr_cat = gInventory.getCategory(new_category->getUUID()); + if (NULL == curr_cat) + { + LL_WARNS("Inventory") << "Failed to update unknown category " << new_category->getUUID() << LL_ENDL; + } + else + { + new_category->setVersion(curr_cat->getVersion()); + new_category->setDescendentCount(curr_cat->getDescendentCount()); + gInventory.updateCategory(new_category); + LL_DEBUGS("Inventory") << "updated category " << new_category->getName() << " " << category_id << LL_ENDL; + } + } + + // CREATE ITEMS + for (deferred_item_map_t::const_iterator create_it = mItemsCreated.begin(); + create_it != mItemsCreated.end(); ++create_it) + { + LLUUID item_id(create_it->first); + LLPointer<LLViewerInventoryItem> new_item = create_it->second; + + // FIXME risky function since it calls updateServer() in some + // cases. Maybe break out the update/create cases, in which + // case this is create. + LL_DEBUGS("Inventory") << "created item " << item_id << LL_ENDL; + gInventory.updateItem(new_item, LLInventoryObserver::CREATE); + } + + // UPDATE ITEMS + for (deferred_item_map_t::const_iterator update_it = mItemsUpdated.begin(); + update_it != mItemsUpdated.end(); ++update_it) + { + LLUUID item_id(update_it->first); + LLPointer<LLViewerInventoryItem> new_item = update_it->second; + // FIXME risky function since it calls updateServer() in some + // cases. Maybe break out the update/create cases, in which + // case this is update. + LL_DEBUGS("Inventory") << "updated item " << item_id << LL_ENDL; + //LL_DEBUGS("Inventory") << ll_pretty_print_sd(new_item->asLLSD()) << LL_ENDL; + gInventory.updateItem(new_item); + } + + // DELETE OBJECTS + for (uuid_list_t::const_iterator del_it = mObjectsDeletedIds.begin(); + del_it != mObjectsDeletedIds.end(); ++del_it) + { + LL_DEBUGS("Inventory") << "deleted item " << *del_it << LL_ENDL; + gInventory.onObjectDeletedFromServer(*del_it, false, false, false); + } + + // TODO - how can we use this version info? Need to be sure all + // changes are going through AIS first, or at least through + // something with a reliable responder. + for (uuid_int_map_t::iterator ucv_it = mCatVersionsUpdated.begin(); + ucv_it != mCatVersionsUpdated.end(); ++ucv_it) + { + const LLUUID id = ucv_it->first; + S32 version = ucv_it->second; + LLViewerInventoryCategory *cat = gInventory.getCategory(id); + 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() + << " server version " << version << LL_ENDL; + } + } + + gInventory.notifyObservers(); +} + diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h new file mode 100755 index 0000000000..5a2ec94af9 --- /dev/null +++ b/indra/newview/llaisapi.h @@ -0,0 +1,183 @@ +/** + * @file llaisapi.h + * @brief classes and functions for interfacing with the v3+ ais inventory service. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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_LLAISAPI_H +#define LL_LLAISAPI_H + +#include "lluuid.h" +#include <map> +#include <set> +#include <string> +#include "llcurl.h" +#include "llhttpclient.h" +#include "llhttpretrypolicy.h" +#include "llviewerinventory.h" + +class AISCommand: public LLHTTPClient::Responder +{ +public: + typedef boost::function<void()> command_func_type; + + AISCommand(LLPointer<LLInventoryCallback> callback); + + virtual ~AISCommand() {} + + bool run_command(); + + void setCommandFunc(command_func_type command_func); + + // Need to do command-specific parsing to get an id here, for + // LLInventoryCallback::fire(). May or may not need to bother, + // since most LLInventoryCallbacks do their work in the + // destructor. + + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); + + static bool isAPIAvailable(); + static bool getInvCap(std::string& cap); + static bool getLibCap(std::string& cap); + static void getCapabilityNames(LLSD& capabilityNames); + +protected: + virtual bool getResponseUUID(const LLSD& content, LLUUID& id); + +private: + command_func_type mCommandFunc; + LLPointer<LLHTTPRetryPolicy> mRetryPolicy; + LLPointer<LLInventoryCallback> mCallback; +}; + +class RemoveItemCommand: public AISCommand +{ +public: + RemoveItemCommand(const LLUUID& item_id, + LLPointer<LLInventoryCallback> callback); +}; + +class RemoveCategoryCommand: public AISCommand +{ +public: + RemoveCategoryCommand(const LLUUID& item_id, + LLPointer<LLInventoryCallback> callback); +}; + +class PurgeDescendentsCommand: public AISCommand +{ +public: + PurgeDescendentsCommand(const LLUUID& item_id, + LLPointer<LLInventoryCallback> callback); +}; + +class UpdateItemCommand: public AISCommand +{ +public: + UpdateItemCommand(const LLUUID& item_id, + const LLSD& updates, + LLPointer<LLInventoryCallback> callback); +private: + LLSD mUpdates; +}; + +class UpdateCategoryCommand: public AISCommand +{ +public: + UpdateCategoryCommand(const LLUUID& cat_id, + const LLSD& updates, + LLPointer<LLInventoryCallback> callback); +private: + LLSD mUpdates; +}; + +class SlamFolderCommand: public AISCommand +{ +public: + SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback); + +private: + LLSD mContents; +}; + +class CopyLibraryCategoryCommand: public AISCommand +{ +public: + CopyLibraryCategoryCommand(const LLUUID& source_id, const LLUUID& dest_id, LLPointer<LLInventoryCallback> callback); + +protected: + /* virtual */ bool getResponseUUID(const LLSD& content, LLUUID& id); +}; + +class CreateInventoryCommand: public AISCommand +{ +public: + CreateInventoryCommand(const LLUUID& parent_id, const LLSD& new_inventory, LLPointer<LLInventoryCallback> callback); + +private: + LLSD mNewInventory; +}; + +class AISUpdate +{ +public: + AISUpdate(const LLSD& update); + void parseUpdate(const LLSD& update); + void parseMeta(const LLSD& update); + void parseContent(const LLSD& update); + void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); + void parseLink(const LLSD& link_map); + void parseItem(const LLSD& link_map); + void parseCategory(const LLSD& link_map); + void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded); + void parseEmbedded(const LLSD& embedded); + void parseEmbeddedLinks(const LLSD& links); + void parseEmbeddedItems(const LLSD& items); + void parseEmbeddedCategories(const LLSD& categories); + void parseEmbeddedItem(const LLSD& item); + void parseEmbeddedCategory(const LLSD& category); + void doUpdate(); +private: + void clearParseResults(); + + typedef std::map<LLUUID,S32> uuid_int_map_t; + uuid_int_map_t mCatDescendentDeltas; + uuid_int_map_t mCatDescendentsKnown; + uuid_int_map_t mCatVersionsUpdated; + + typedef std::map<LLUUID,LLPointer<LLViewerInventoryItem> > deferred_item_map_t; + deferred_item_map_t mItemsCreated; + deferred_item_map_t mItemsUpdated; + typedef std::map<LLUUID,LLPointer<LLViewerInventoryCategory> > deferred_category_map_t; + deferred_category_map_t mCategoriesCreated; + deferred_category_map_t mCategoriesUpdated; + + // These keep track of uuid's mentioned in meta values. + // Useful for filtering out which content we are interested in. + uuid_list_t mObjectsDeletedIds; + uuid_list_t mItemIds; + uuid_list_t mCategoryIds; +}; + +#endif diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 81f713502f..a4c430bada 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -52,6 +52,8 @@ #include "llwearablelist.h" #include "llsdutil.h" #include "llsdserialize.h" +#include "llhttpretrypolicy.h" +#include "llaisapi.h" #if LL_MSVC // disable boost::lexical_cast warning @@ -196,7 +198,7 @@ public: LLEventTimer(5.0) { if (!mTrackingPhase.empty()) - { + { selfStartPhase(mTrackingPhase); } } @@ -212,23 +214,22 @@ public: addItem(item->getUUID()); } } - + // Request or re-request operation for specified item. void addItem(const LLUUID& item_id) { LL_DEBUGS("Avatar") << "item_id " << item_id << LL_ENDL; - if (!requestOperation(item_id)) { LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << LL_ENDL; return; - } + } mPendingRequests++; // On a re-request, this will reset the timer. mWaitTimes[item_id] = LLTimer(); if (mRetryCounts.find(item_id) == mRetryCounts.end()) - { + { mRetryCounts[item_id] = 0; } else @@ -242,7 +243,7 @@ public: void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp) { if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate")) - { + { LL_WARNS() << "Simulating late operation by punting handling to later" << LL_ENDL; doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp), mRetryAfter); @@ -265,12 +266,12 @@ public: onCompletionOrFailure(); } } - + void onCompletionOrFailure() { assert (!mCompletionOrFailureCalled); mCompletionOrFailureCalled = true; - + // Will never call onCompletion() if any item has been flagged as // a failure - otherwise could wind up with corrupted // outfit, involuntary nudity, etc. @@ -288,7 +289,7 @@ public: onFailure(); } } - + void onFailure() { LL_INFOS() << "failed" << LL_ENDL; @@ -300,7 +301,7 @@ public: LL_INFOS() << "done" << LL_ENDL; mOnCompletionFunc(); } - + // virtual // Will be deleted after returning true - only safe to do this if all callbacks have fired. BOOL tick() @@ -313,7 +314,7 @@ public: // been serviced, since it will result in this object being // deleted. bool all_done = (mPendingRequests==0); - + if (!mWaitTimes.empty()) { LL_WARNS() << "still waiting on " << mWaitTimes.size() << " items" << LL_ENDL; @@ -323,20 +324,20 @@ public: // Use a copy of iterator because it may be erased/invalidated. std::map<LLUUID,LLTimer>::iterator curr_it = it; ++it; - + F32 time_waited = curr_it->second.getElapsedTimeF32(); S32 retries = mRetryCounts[curr_it->first]; if (time_waited > mRetryAfter) { if (retries < mMaxRetries) - { + { LL_DEBUGS("Avatar") << "Waited " << time_waited << " for " << curr_it->first << ", retrying" << LL_ENDL; mRetryCount++; addItem(curr_it->first); - } - else - { + } + else + { LL_WARNS() << "Giving up on " << curr_it->first << " after too many retries" << LL_ENDL; mWaitTimes.erase(curr_it); mFailCount++; @@ -347,8 +348,8 @@ public: onCompletionOrFailure(); } + } } - } return all_done; } @@ -360,7 +361,7 @@ public: LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << LL_ENDL; LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << LL_ENDL; } - + virtual ~LLCallAfterInventoryBatchMgr() { LL_DEBUGS("Avatar") << "deleting" << LL_ENDL; @@ -396,10 +397,16 @@ public: LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries) { addItems(src_items); + sInstanceCount++; } + ~LLCallAfterInventoryCopyMgr() + { + sInstanceCount--; + } + virtual bool requestOperation(const LLUUID& item_id) - { + { LLViewerInventoryItem *item = gInventory.getItem(item_id); llassert(item); LL_DEBUGS("Avatar") << "copying item " << item_id << LL_ENDL; @@ -418,95 +425,86 @@ public: ); return true; } + + static S32 getInstanceCount() { return sInstanceCount; } + +private: + static S32 sInstanceCount; }; -class LLCallAfterInventoryLinkMgr: public LLCallAfterInventoryBatchMgr +S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0; + +class LLWearCategoryAfterCopy: public LLInventoryCallback { public: - LLCallAfterInventoryLinkMgr(LLInventoryModel::item_array_t& src_items, - const LLUUID& dst_cat_id, - const std::string& phase_name, - nullary_func_t on_completion_func, - nullary_func_t on_failure_func = no_op, - F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, - S32 max_retries = DEFAULT_MAX_RETRIES - ): - LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries) + LLWearCategoryAfterCopy(bool append): + mAppend(append) + {} + + // virtual + void fire(const LLUUID& id) { - addItems(src_items); + // Wear the inventory category. + LLInventoryCategory* cat = gInventory.getCategory(id); + LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend); } - - virtual bool requestOperation(const LLUUID& item_id) - { - bool request_sent = false; - LLViewerInventoryItem *item = gInventory.getItem(item_id); - if (item) - { - if (item->getParentUUID() == mDstCatID) - { - LL_DEBUGS("Avatar") << "item " << item_id << " name " << item->getName() << " is already a child of " << mDstCatID << LL_ENDL; - return false; - } - LL_DEBUGS("Avatar") << "linking item " << item_id << " name " << item->getName() << " to " << mDstCatID << LL_ENDL; - // create an inventory item link. - if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) - { - LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << LL_ENDL; - return true; - } - link_inventory_item(gAgent.getID(), - item->getLinkedUUID(), - mDstCatID, - item->getName(), - item->getActualDescription(), - LLAssetType::AT_LINK, - new LLBoostFuncInventoryCallback( - boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer()))); - return true; - } - else - { - // create a base outfit link if appropriate. - LLViewerInventoryCategory *catp = gInventory.getCategory(item_id); - if (!catp) - { - LL_WARNS() << "link request failed, id not found as inventory item or category " << item_id << LL_ENDL; - return false; - } - const LLUUID cof = LLAppearanceMgr::instance().getCOF(); - std::string new_outfit_name = ""; - LLAppearanceMgr::instance().purgeBaseOutfitLink(cof); +private: + bool mAppend; +}; - if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) +class LLTrackPhaseWrapper : public LLInventoryCallback +{ +public: + LLTrackPhaseWrapper(const std::string& phase_name, LLPointer<LLInventoryCallback> cb = NULL): + mTrackingPhase(phase_name), + mCB(cb) { - if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) + selfStartPhase(mTrackingPhase); + } + + // virtual + void fire(const LLUUID& id) + { + if (mCB) { - LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << LL_ENDL; - return true; - } - LL_DEBUGS("Avatar") << "linking folder " << item_id << " name " << catp->getName() << " to cof " << cof << LL_ENDL; - link_inventory_item(gAgent.getID(), item_id, cof, catp->getName(), "", - LLAssetType::AT_LINK_FOLDER, - new LLBoostFuncInventoryCallback( - boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer()))); - new_outfit_name = catp->getName(); - request_sent = true; - } - - LLAppearanceMgr::instance().updatePanelOutfitName(new_outfit_name); + mCB->fire(id); } - return request_sent; } + + // virtual + ~LLTrackPhaseWrapper() + { + selfStopPhase(mTrackingPhase); + } + +protected: + std::string mTrackingPhase; + LLPointer<LLInventoryCallback> mCB; }; -LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering): +LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions, + bool enforce_ordering, + nullary_func_t post_update_func + ): mFireCount(0), - mUpdateBaseOrder(update_base_outfit_ordering) + mEnforceItemRestrictions(enforce_item_restrictions), + mEnforceOrdering(enforce_ordering), + mPostUpdateFunc(post_update_func) { selfStartPhase("update_appearance_on_destroy"); } +void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) +{ + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); + const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; +#endif + mFireCount++; +} + LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() { if (!LLApp::isExiting()) @@ -516,20 +514,46 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() selfStopPhase("update_appearance_on_destroy"); - LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder); + LLAppearanceMgr::instance().updateAppearanceFromCOF(mEnforceItemRestrictions, + mEnforceOrdering, + mPostUpdateFunc); } } -void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) +LLUpdateAppearanceAndEditWearableOnDestroy::LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id): + mItemID(item_id) { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); - const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; -#ifndef LL_RELEASE_FOR_DOWNLOAD - LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; -#endif - mFireCount++; } +void edit_wearable_and_customize_avatar(LLUUID item_id) +{ + // Start editing the item if previously requested. + gAgentWearables.editWearableIfRequested(item_id); + + // TODO: camera mode may not be changed if a debug setting is tweaked + if( gAgentCamera.cameraCustomizeAvatar() ) + { + // If we're in appearance editing mode, the current tab may need to be refreshed + LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>( + LLFloaterSidePanelContainer::getPanel("appearance")); + if (panel) + { + panel->showDefaultSubpart(); + } + } +} + +LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOnDestroy() +{ + if (!LLApp::isExiting()) + { + LLAppearanceMgr::instance().updateAppearanceFromCOF( + true,true, + boost::bind(edit_wearable_and_customize_avatar, mItemID)); + } +} + + struct LLFoundData { LLFoundData() : @@ -593,6 +617,8 @@ public: bool isMostRecent(); void handleLateArrivals(); void resetTime(F32 timeout); + static S32 countActive() { return sActiveHoldingPatterns.size(); } + S32 index() { return mIndex; } private: found_list_t mFoundList; @@ -606,12 +632,15 @@ private: bool mFired; typedef std::set<LLWearableHoldingPattern*> type_set_hp; static type_set_hp sActiveHoldingPatterns; + static S32 sNextIndex; + S32 mIndex; bool mIsMostRecent; std::set<LLViewerWearable*> mLateArrivals; bool mIsAllComplete; }; LLWearableHoldingPattern::type_set_hp LLWearableHoldingPattern::sActiveHoldingPatterns; +S32 LLWearableHoldingPattern::sNextIndex = 0; LLWearableHoldingPattern::LLWearableHoldingPattern(): mResolved(0), @@ -619,13 +648,13 @@ LLWearableHoldingPattern::LLWearableHoldingPattern(): mIsMostRecent(true), mIsAllComplete(false) { - if (sActiveHoldingPatterns.size()>0) + if (countActive()>0) { LL_INFOS() << "Creating LLWearableHoldingPattern when " - << sActiveHoldingPatterns.size() - << " other attempts are active." - << " Flagging others as invalid." - << LL_ENDL; + << countActive() + << " other attempts are active." + << " Flagging others as invalid." + << LL_ENDL; for (type_set_hp::iterator it = sActiveHoldingPatterns.begin(); it != sActiveHoldingPatterns.end(); ++it) @@ -634,7 +663,9 @@ LLWearableHoldingPattern::LLWearableHoldingPattern(): } } + mIndex = sNextIndex++; sActiveHoldingPatterns.insert(this); + LL_DEBUGS("Avatar") << "HP " << index() << " created" << LL_ENDL; selfStartPhase("holding_pattern"); } @@ -645,6 +676,7 @@ LLWearableHoldingPattern::~LLWearableHoldingPattern() { selfStopPhase("holding_pattern"); } + LL_DEBUGS("Avatar") << "HP " << index() << " deleted" << LL_ENDL; } bool LLWearableHoldingPattern::isMostRecent() @@ -733,7 +765,10 @@ void LLWearableHoldingPattern::checkMissingWearables() resetTime(60.0F); - selfStartPhase("get_missing_wearables"); + if (isMostRecent()) + { + selfStartPhase("get_missing_wearables_2"); + } if (!pollMissingWearables()) { doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); @@ -773,8 +808,8 @@ void LLWearableHoldingPattern::onAllComplete() } // Update wearables. - LL_INFOS("Avatar") << self_av_string() << "Updating agent wearables with " << mResolved << " wearable items " << LL_ENDL; - LLAppearanceMgr::instance().updateAgentWearables(this, false); + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with " << mResolved << " wearable items " << LL_ENDL; + LLAppearanceMgr::instance().updateAgentWearables(this); // Update attachments to match those requested. if (isAgentAvatarValid()) @@ -797,7 +832,10 @@ void LLWearableHoldingPattern::onAllComplete() void LLWearableHoldingPattern::onFetchCompletion() { - selfStopPhase("get_wearables"); + if (isMostRecent()) + { + selfStopPhase("get_wearables_2"); + } if (!isMostRecent()) { @@ -823,7 +861,7 @@ bool LLWearableHoldingPattern::pollFetchCompletion() if (done) { - LL_INFOS("Avatar") << self_av_string() << "polling, done status: " << completed << " timed out " << timed_out + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling, done status: " << completed << " timed out " << timed_out << " elapsed " << mWaitTime.getElapsedTimeF32() << LL_ENDL; mFired = true; @@ -841,69 +879,64 @@ bool LLWearableHoldingPattern::pollFetchCompletion() void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder) { if (!holder->isMostRecent()) - { - LL_WARNS() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - // runway skip here? - } + { + LL_WARNS() << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + // runway skip here? + } - LL_INFOS() << "Recovered item link for type " << type << LL_ENDL; + LL_INFOS() << "HP " << holder->index() << " recovered item link for type " << type << LL_ENDL; holder->eraseTypeToLink(type); - // Add wearable to FoundData for actual wearing - LLViewerInventoryItem *item = gInventory.getItem(item_id); - LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; + // Add wearable to FoundData for actual wearing + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - if (linked_item) - { - gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); + if (linked_item) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); - if (item) - { - LLFoundData found(linked_item->getUUID(), - linked_item->getAssetUUID(), - linked_item->getName(), - linked_item->getType(), - linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID, - true // is replacement - ); + if (item) + { + LLFoundData found(linked_item->getUUID(), + linked_item->getAssetUUID(), + linked_item->getName(), + linked_item->getType(), + linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID, + true // is replacement + ); found.mWearable = wearable; holder->getFoundList().push_front(found); - } - else - { - LL_WARNS() << self_av_string() << "inventory item not found for recovered wearable" << LL_ENDL; - } } else { LL_WARNS() << self_av_string() << "inventory link not found for recovered wearable" << LL_ENDL; } } + else + { + LL_WARNS() << self_av_string() << "HP " << holder->index() << " inventory link not found for recovered wearable" << LL_ENDL; + } +} void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder) { if (!holder->isMostRecent()) - { - // runway skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } + { + // runway skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL; - LLViewerInventoryItem *itemp = gInventory.getItem(item_id); + LLConstPointer<LLInventoryObject> itemp = gInventory.getItem(item_id); wearable->setItemID(item_id); - LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder)); holder->eraseTypeToRecover(type); - llassert(itemp); - if (itemp) - { - link_inventory_item( gAgent.getID(), - item_id, - LLAppearanceMgr::instance().getCOF(), - itemp->getName(), - itemp->getDescription(), - LLAssetType::AT_LINK, - cb); - } + llassert(itemp); + if (itemp) + { + LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder)); + + link_inventory_object(LLAppearanceMgr::instance().getCOF(), itemp, cb); } +} void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type) { @@ -916,7 +949,7 @@ void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type // Try to recover by replacing missing wearable with a new one. LLNotificationsUtil::add("ReplacedMissingWearable"); LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type) - << " could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; + << " could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); // Add a new one in the lost and found folder. @@ -949,7 +982,7 @@ void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) { // Wearable link that was never resolved; remove links to it from COF - LL_INFOS("Avatar") << self_av_string() << "removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); } } @@ -969,7 +1002,7 @@ bool LLWearableHoldingPattern::pollMissingWearables() if (!done) { - LL_INFOS("Avatar") << self_av_string() << "polling missing wearables, waiting for items " << mTypesToRecover.size() + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling missing wearables, waiting for items " << mTypesToRecover.size() << " links " << mTypesToLink.size() << " wearables, timed out " << timed_out << " elapsed " << mWaitTime.getElapsedTimeF32() @@ -978,7 +1011,10 @@ bool LLWearableHoldingPattern::pollMissingWearables() if (done) { - selfStopPhase("get_missing_wearables"); + if (isMostRecent()) + { + selfStopPhase("get_missing_wearables_2"); + } gAgentAvatarp->debugWearablesLoaded(); @@ -1016,7 +1052,7 @@ void LLWearableHoldingPattern::handleLateArrivals() LL_WARNS() << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << LL_ENDL; } - LL_INFOS("Avatar") << self_av_string() << "Need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL; + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL; // Update mFoundList using late-arriving wearables. std::set<LLWearableType::EType> replaced_types; @@ -1079,7 +1115,7 @@ void LLWearableHoldingPattern::handleLateArrivals() mLateArrivals.clear(); // Update appearance based on mFoundList - LLAppearanceMgr::instance().updateAgentWearables(this, false); + LLAppearanceMgr::instance().updateAgentWearables(this); } void LLWearableHoldingPattern::resetTime(F32 timeout) @@ -1096,7 +1132,7 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable) } mResolved += 1; // just counting callbacks, not successes. - LL_DEBUGS("Avatar") << self_av_string() << "resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; + LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; if (!wearable) { LL_WARNS() << self_av_string() << "no wearable found" << LL_ENDL; @@ -1203,8 +1239,7 @@ const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink() cat_array, item_array, false, - is_category, - false); + is_category); for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); iter != item_array.end(); iter++) @@ -1270,8 +1305,12 @@ void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace = false) } } -bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_update, bool replace, LLPointer<LLInventoryCallback> cb) +bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, + bool do_update, + bool replace, + LLPointer<LLInventoryCallback> cb) { + if (item_id_to_wear.isNull()) return false; // *TODO: issue with multi-wearable should be fixed: @@ -1290,7 +1329,7 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID())) { LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace)); - copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(),cb); + copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb); return false; } else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID())) @@ -1310,15 +1349,22 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up switch (item_to_wear->getType()) { case LLAssetType::AT_CLOTHING: - if (gAgentWearables.areWearablesLoaded()) + if (gAgentWearables.areWearablesLoaded()) { + if (!cb && do_update) + { + cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear); + } S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType()); if ((replace && wearable_count != 0) || (wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) ) { - removeCOFItemLinks(gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1)); + LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), + wearable_count-1); + removeCOFItemLinks(item_id, cb); } - addCOFItemLink(item_to_wear, do_update, cb); + + addCOFItemLink(item_to_wear, cb); } break; case LLAssetType::AT_BODYPART: @@ -1327,8 +1373,11 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up // Remove the existing wearables of the same type. // Remove existing body parts anyway because we must not be able to wear e.g. two skins. removeCOFLinksOfType(item_to_wear->getWearableType()); - - addCOFItemLink(item_to_wear, do_update, cb); + if (!cb && do_update) + { + cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear); + } + addCOFItemLink(item_to_wear, cb); break; case LLAssetType::AT_OBJECT: rez_attachment(item_to_wear, NULL, replace); @@ -1457,6 +1506,58 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds gInventory.notifyObservers(); } +void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id, + bool include_folder_links, LLPointer<LLInventoryCallback> cb) +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + LLSD contents = LLSD::emptyArray(); + gInventory.getDirectDescendentsOf(src_id, cats, items); + LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; + for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); + iter != items->end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + switch (item->getActualType()) + { + case LLAssetType::AT_LINK: + { + LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; + //getActualDescription() is used for a new description + //to propagate ordering information saved in descriptions of links + LLSD item_contents; + item_contents["name"] = item->getName(); + item_contents["desc"] = item->getActualDescription(); + item_contents["linked_id"] = item->getLinkedUUID(); + item_contents["type"] = LLAssetType::AT_LINK; + contents.append(item_contents); + break; + } + case LLAssetType::AT_LINK_FOLDER: + { + LLViewerInventoryCategory *catp = item->getLinkedCategory(); + if (catp && include_folder_links) + { + LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; + LLSD base_contents; + base_contents["name"] = catp->getName(); + base_contents["desc"] = ""; // categories don't have descriptions. + base_contents["linked_id"] = catp->getLinkedUUID(); + base_contents["type"] = LLAssetType::AT_LINK_FOLDER; + contents.append(base_contents); + } + break; + } + default: + { + // Linux refuses to compile unless all possible enums are handled. Really, Linux? + break; + } + } + } + slam_inventory_folder(dst_id, contents, cb); +} // Copy contents of src_id to dst_id. void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id, LLPointer<LLInventoryCallback> cb) @@ -1465,6 +1566,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL LLInventoryModel::item_array_t* items; gInventory.getDirectDescendentsOf(src_id, cats, items); LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; + LLInventoryObject::const_object_list_t link_array; for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); iter != items->end(); ++iter) @@ -1474,14 +1576,8 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL { case LLAssetType::AT_LINK: { - //getActualDescription() is used for a new description - //to propagate ordering information saved in descriptions of links - link_inventory_item(gAgent.getID(), - item->getLinkedUUID(), - dst_id, - item->getName(), - item->getActualDescription(), - LLAssetType::AT_LINK, cb); + LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; + link_array.push_back(LLConstPointer<LLInventoryObject>(item)); break; } case LLAssetType::AT_LINK_FOLDER: @@ -1490,12 +1586,8 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL // Skip copying outfit links. if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT) { - link_inventory_item(gAgent.getID(), - item->getLinkedUUID(), - dst_id, - item->getName(), - item->getDescription(), - LLAssetType::AT_LINK_FOLDER, cb); + LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; + link_array.push_back(LLConstPointer<LLInventoryObject>(item)); } break; } @@ -1504,7 +1596,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL case LLAssetType::AT_BODYPART: case LLAssetType::AT_GESTURE: { - LL_INFOS() << "copying inventory item " << item->getName() << LL_ENDL; + LL_DEBUGS("Avatar") << "copying inventory item " << item->getName() << LL_ENDL; copy_inventory_item(gAgent.getID(), item->getPermissions().getOwner(), item->getUUID(), @@ -1518,6 +1610,10 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL break; } } + if (!link_array.empty()) + { + link_inventory_array(dst_id, link_array, cb); + } } BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id) @@ -1582,15 +1678,13 @@ bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id) // static bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; + if (gAgentWearables.isCOFChangeInProgress()) + { + return false; + } + LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_worn); - return items.size() > 0; + return gInventory.hasMatchingDirectDescendent(outfit_cat_id, is_worn); } // static @@ -1601,15 +1695,8 @@ bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id) return false; } - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - not_worn); - return items.size() > 0; + return gInventory.hasMatchingDirectDescendent(outfit_cat_id, not_worn); } bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) @@ -1627,18 +1714,11 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) } // Check whether the outfit contains any wearables we aren't wearing already (STORM-702). - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_worn); - return items.size() > 0; + LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ true); + return gInventory.hasMatchingDirectDescendent(outfit_cat_id, not_worn); } -void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category) +void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb) { LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; @@ -1649,46 +1729,14 @@ void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category) LLViewerInventoryItem *item = items.at(i); if (item->getActualType() != LLAssetType::AT_LINK_FOLDER) continue; - if (item->getIsLinkType()) + LLViewerInventoryCategory* catp = item->getLinkedCategory(); + if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) { - LLViewerInventoryCategory* catp = item->getLinkedCategory(); - if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) - { - gInventory.purgeObject(item->getUUID()); - } + remove_inventory_item(item->getUUID(), cb); } } } -void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t* keep_items) -{ - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(category, cats, items, - LLInventoryModel::EXCLUDE_TRASH); - for (S32 i = 0; i < items.size(); ++i) - { - LLViewerInventoryItem *item = items.at(i); - if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER)) - continue; - if (item->getIsLinkType()) - { -#if 0 - if (keep_items && keep_items->find(item) != LLInventoryModel::item_array_t::FAIL) - { - LL_INFOS() << "preserved item" << LL_ENDL; - } - else - { - gInventory.purgeObject(item->getUUID()); - } -#else - gInventory.purgeObject(item->getUUID()); - } -#endif - } -} - // Keep the last N wearables of each type. For viewer 2.0, N is 1 for // both body parts and clothing items. void LLAppearanceMgr::filterWearableItems( @@ -1713,33 +1761,14 @@ void LLAppearanceMgr::filterWearableItems( } } -// Create links to all listed items. -void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid, - LLInventoryModel::item_array_t& items, - LLPointer<LLInventoryCallback> cb) -{ - for (S32 i=0; i<items.size(); i++) - { - const LLInventoryItem* item = items.at(i).get(); - link_inventory_item(gAgent.getID(), - item->getLinkedUUID(), - cat_uuid, - item->getName(), - item->getActualDescription(), - LLAssetType::AT_LINK, - cb); - - const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid); - const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; -#ifndef LL_RELEASE_FOR_DOWNLOAD - LL_DEBUGS("Avatar") << self_av_string() << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << LL_ENDL; -#endif - } -} - void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) { LLViewerInventoryCategory *pcat = gInventory.getCategory(category); + if (!pcat) + { + LL_WARNS() << "no category found for id " << category << LL_ENDL; + return; + } LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL; const LLUUID cof = getCOF(); @@ -1748,7 +1777,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) if (!append) { LLInventoryModel::item_array_t gest_items; - getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); for(S32 i = 0; i < gest_items.size(); ++i) { LLViewerInventoryItem *gest_item = gest_items.at(i); @@ -1765,8 +1794,8 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // required parts are missing. // Preserve body parts from COF if appending. LLInventoryModel::item_array_t body_items; - getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false); - getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false); + getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART); + getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART); if (append) reverse(body_items.begin(), body_items.end()); // Reduce body items to max of one per type. @@ -1776,8 +1805,8 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // - Wearables: include COF contents only if appending. LLInventoryModel::item_array_t wear_items; if (append) - getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false); - getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false); + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); + getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING); // Reduce wearables to max of one per type. removeDuplicateItems(wear_items); filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE); @@ -1785,15 +1814,15 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // - Attachments: include COF contents only if appending. LLInventoryModel::item_array_t obj_items; if (append) - getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false); - getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false); + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); + getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT); removeDuplicateItems(obj_items); // - Gestures: include COF contents only if appending. LLInventoryModel::item_array_t gest_items; if (append) - getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); - getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false); + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); + getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE); removeDuplicateItems(gest_items); // Create links to new COF contents. @@ -1803,23 +1832,56 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) std::copy(obj_items.begin(), obj_items.end(), std::back_inserter(all_items)); std::copy(gest_items.begin(), gest_items.end(), std::back_inserter(all_items)); + // Find any wearables that need description set to enforce ordering. + desc_map_t desc_map; + getWearableOrderingDescUpdates(wear_items, desc_map); + // Will link all the above items. - LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; - linkAll(cof,all_items,link_waiter); + // link_waiter enforce flags are false because we've already fixed everything up in updateCOF(). + LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false); + LLSD contents = LLSD::emptyArray(); - // Add link to outfit if category is an outfit. - if (!append) + for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin(); + it != all_items.end(); ++it) { - createBaseOutfitLink(category, link_waiter); - } + LLSD item_contents; + LLInventoryItem *item = *it; - // Remove current COF contents. Have to do this after creating - // the link_waiter so links can be followed for any items that get - // carried over (e.g. keeping old shape if the new outfit does not - // contain one) - bool keep_outfit_links = append; - purgeCategory(cof, keep_outfit_links, &all_items); - gInventory.notifyObservers(); + std::string desc; + desc_map_t::const_iterator desc_iter = desc_map.find(item->getUUID()); + if (desc_iter != desc_map.end()) + { + desc = desc_iter->second; + LL_DEBUGS("Avatar") << item->getName() << " overriding desc to: " << desc + << " (was: " << item->getActualDescription() << ")" << LL_ENDL; + } + else + { + desc = item->getActualDescription(); + } + + item_contents["name"] = item->getName(); + item_contents["desc"] = desc; + item_contents["linked_id"] = item->getLinkedUUID(); + item_contents["type"] = LLAssetType::AT_LINK; + contents.append(item_contents); + } + const LLUUID& base_id = append ? getBaseOutfitUUID() : category; + LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); + if (base_cat) + { + LLSD base_contents; + base_contents["name"] = base_cat->getName(); + base_contents["desc"] = ""; + base_contents["linked_id"] = base_cat->getLinkedUUID(); + base_contents["type"] = LLAssetType::AT_LINK_FOLDER; + contents.append(base_contents); + } + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) + { + dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents); + } + slam_inventory_folder(getCOF(), contents, link_waiter); LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL; } @@ -1840,21 +1902,20 @@ void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLI LLViewerInventoryCategory* catp = gInventory.getCategory(category); std::string new_outfit_name = ""; - purgeBaseOutfitLink(cof); + purgeBaseOutfitLink(cof, link_waiter); if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) { - link_inventory_item(gAgent.getID(), category, cof, catp->getName(), "", - LLAssetType::AT_LINK_FOLDER, link_waiter); + link_inventory_object(cof, catp, link_waiter); new_outfit_name = catp->getName(); } updatePanelOutfitName(new_outfit_name); } -void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, bool append) +void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder) { - LL_DEBUGS() << "updateAgentWearables()" << LL_ENDL; + LL_DEBUGS("Avatar") << "updateAgentWearables()" << LL_ENDL; LLInventoryItem::item_array_t items; std::vector< LLViewerWearable* > wearables; wearables.reserve(32); @@ -1881,10 +1942,15 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo if(wearables.size() > 0) { - gAgentWearables.setWearableOutfit(items, wearables, !append); + gAgentWearables.setWearableOutfit(items, wearables); } } +S32 LLAppearanceMgr::countActiveHoldingPatterns() +{ + return LLWearableHoldingPattern::countActive(); +} + static void remove_non_link_items(LLInventoryModel::item_array_t &items) { LLInventoryModel::item_array_t pruned_items; @@ -1933,12 +1999,12 @@ void item_array_diff(LLInventoryModel::item_array_t& full_list, S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id, LLAssetType::EType type, S32 max_items, - LLInventoryModel::item_array_t& items_to_kill) + LLInventoryObject::object_list_t& items_to_kill) { S32 to_kill_count = 0; LLInventoryModel::item_array_t items; - getDescendentsOfAssetType(cat_id, items, type, false); + getDescendentsOfAssetType(cat_id, items, type); LLInventoryModel::item_array_t curr_items = items; removeDuplicateItems(items); if (max_items > 0) @@ -1951,40 +2017,39 @@ S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id, it != kill_items.end(); ++it) { - items_to_kill.push_back(*it); + items_to_kill.push_back(LLPointer<LLInventoryObject>(*it)); to_kill_count++; } return to_kill_count; } - -void LLAppearanceMgr::enforceItemRestrictions() -{ - S32 purge_count = 0; - LLInventoryModel::item_array_t items_to_kill; - purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_BODYPART, - 1, items_to_kill); - purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_CLOTHING, - LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill); - purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_OBJECT, - -1, items_to_kill); +void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id, + LLInventoryObject::object_list_t& items_to_kill) +{ + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART, + 1, items_to_kill); + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING, + LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill); + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT, + -1, items_to_kill); +} +void LLAppearanceMgr::enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb) +{ + LLInventoryObject::object_list_t items_to_kill; + findAllExcessOrDuplicateItems(getCOF(), items_to_kill); if (items_to_kill.size()>0) { - for (LLInventoryModel::item_array_t::iterator it = items_to_kill.begin(); - it != items_to_kill.end(); - ++it) - { - LLViewerInventoryItem *item = *it; - LL_DEBUGS("Avatar") << self_av_string() << "purging duplicate or excess item " << item->getName() << LL_ENDL; - gInventory.purgeObject(item->getUUID()); - } - gInventory.notifyObservers(); + // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but + // this should catch anything that gets through. + remove_inventory_items(items_to_kill, cb); } } -void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) +void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, + bool enforce_ordering, + nullary_func_t post_update_func) { if (mIsInUpdateAppearanceFromCOF) { @@ -1992,19 +2057,43 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) return; } - BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); - selfStartPhase("update_appearance_from_cof"); - LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL; - //checking integrity of the COF in terms of ordering of wearables, - //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) - updateClothingOrderingInfo(LLUUID::null, update_base_outfit_ordering); + if (enforce_item_restrictions) + { + // The point here is just to call + // updateAppearanceFromCOF() again after excess items + // have been removed. That time we will set + // enforce_item_restrictions to false so we don't get + // caught in a perpetual loop. + LLPointer<LLInventoryCallback> cb( + new LLUpdateAppearanceOnDestroy(false, enforce_ordering, post_update_func)); + enforceCOFItemRestrictions(cb); + return; + } + + if (enforce_ordering) + { + //checking integrity of the COF in terms of ordering of wearables, + //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) + + // As with enforce_item_restrictions handling above, we want + // to wait for the update callbacks, then (finally!) call + // updateAppearanceFromCOF() with no additional COF munging needed. + LLPointer<LLInventoryCallback> cb( + new LLUpdateAppearanceOnDestroy(false, false, post_update_func)); + updateClothingOrderingInfo(LLUUID::null, cb); + return; + } + + if (!validateClothingOrderingInfo()) + { + LL_WARNS() << "Clothing ordering error" << LL_ENDL; + } + + BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); + selfStartPhase("update_appearance_from_cof"); - // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but - // this should catch anything that gets through. - enforceItemRestrictions(); - // update dirty flag to see if the state of the COF matches // the saved outfit stored as a folder link updateIsDirty(); @@ -2014,13 +2103,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) { requestServerAppearanceUpdate(); } - // DRANO really should wait for the appearance message to set this. - // verify that deleting this line doesn't break anything. - //gAgentAvatarp->setIsUsingServerBakes(gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()); - - //dumpCat(getCOF(),"COF, start"); - bool follow_folder_links = false; LLUUID current_outfit_id = getCOF(); // Find all the wearables that are in the COF's subtree. @@ -2028,7 +2111,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) LLInventoryModel::item_array_t wear_items; LLInventoryModel::item_array_t obj_items; LLInventoryModel::item_array_t gest_items; - getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items, follow_folder_links); + getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items); // Get rid of non-links in case somehow the COF was corrupted. remove_non_link_items(wear_items); remove_non_link_items(obj_items); @@ -2037,6 +2120,13 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) dumpItemArray(wear_items,"asset_dump: wear_item"); dumpItemArray(obj_items,"asset_dump: obj_item"); + LLViewerInventoryCategory *cof = gInventory.getCategory(current_outfit_id); + if (!gInventory.isCategoryComplete(current_outfit_id)) + { + LL_WARNS() << "COF info is not complete. Version " << cof->getVersion() + << " descendent_count " << cof->getDescendentCount() + << " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL; + } if(!wear_items.size()) { LLNotificationsUtil::add("CouldNotPutOnOutfit"); @@ -2047,6 +2137,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) sortItemsByActualDescription(wear_items); + LL_DEBUGS("Avatar") << "HP block starts" << LL_ENDL; + LLTimer hp_block_timer; LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; holder->setObjItems(obj_items); @@ -2096,7 +2188,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) } } - selfStartPhase("get_wearables"); + selfStartPhase("get_wearables_2"); for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin(); it != holder->getFoundList().end(); ++it) @@ -2120,12 +2212,14 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) { doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder)); } + post_update_func(); + + LL_DEBUGS("Avatar") << "HP block ends, elapsed " << hp_block_timer.getElapsedTimeF32() << LL_ENDL; } void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category, LLInventoryModel::item_array_t& items, - LLAssetType::EType type, - bool follow_folder_links) + LLAssetType::EType type) { LLInventoryModel::cat_array_t cats; LLIsType is_of_type(type); @@ -2133,15 +2227,13 @@ void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category, cats, items, LLInventoryModel::EXCLUDE_TRASH, - is_of_type, - follow_folder_links); + is_of_type); } void LLAppearanceMgr::getUserDescendents(const LLUUID& category, LLInventoryModel::item_array_t& wear_items, LLInventoryModel::item_array_t& obj_items, - LLInventoryModel::item_array_t& gest_items, - bool follow_folder_links) + LLInventoryModel::item_array_t& gest_items) { LLInventoryModel::cat_array_t wear_cats; LLFindWearables is_wearable; @@ -2149,8 +2241,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category, wear_cats, wear_items, LLInventoryModel::EXCLUDE_TRASH, - is_wearable, - follow_folder_links); + is_wearable); LLInventoryModel::cat_array_t obj_cats; LLIsType is_object( LLAssetType::AT_OBJECT ); @@ -2158,8 +2249,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category, obj_cats, obj_items, LLInventoryModel::EXCLUDE_TRASH, - is_object, - follow_folder_links); + is_object); // Find all gestures in this folder LLInventoryModel::cat_array_t gest_cats; @@ -2168,8 +2258,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category, gest_cats, gest_items, LLInventoryModel::EXCLUDE_TRASH, - is_gesture, - follow_folder_links); + is_gesture); } void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append) @@ -2184,10 +2273,36 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName() << " )" << LL_ENDL; - selfStartPhase("wear_inventory_category_fetch"); - callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, - &LLAppearanceMgr::instance(), - category->getUUID(), copy, append)); + // If we are copying from library, attempt to use AIS to copy the category. + bool ais_ran=false; + if (copy && AISCommand::isAPIAvailable()) + { + LLUUID parent_id; + parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); + if (parent_id.isNull()) + { + parent_id = gInventory.getRootFolderID(); + } + + LLPointer<LLInventoryCallback> copy_cb = new LLWearCategoryAfterCopy(append); + LLPointer<LLInventoryCallback> track_cb = new LLTrackPhaseWrapper( + std::string("wear_inventory_category_callback"), copy_cb); + LLPointer<AISCommand> cmd_ptr = new CopyLibraryCategoryCommand(category->getUUID(), parent_id, track_cb); + ais_ran=cmd_ptr->run_command(); + } + + if (!ais_ran) + { + selfStartPhase("wear_inventory_category_fetch"); + callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, + &LLAppearanceMgr::instance(), + category->getUUID(), copy, append)); + } +} + +S32 LLAppearanceMgr::getActiveCopyOperations() const +{ + return LLCallAfterInventoryCopyMgr::getInstanceCount(); } void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append) @@ -2268,7 +2383,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego // Avoid unintentionally overwriting old wearables. We have to do // this up front to avoid having to deal with the case of multiple // wearables being dirty. - if(!category) return; + if (!category) return; if ( !LLInventoryCallbackManager::is_instantiated() ) { @@ -2288,6 +2403,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } +// FIXME do we really want to search entire inventory for matching name? void LLAppearanceMgr::wearOutfitByName(const std::string& name) { LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; @@ -2341,9 +2457,8 @@ bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventor class LLDeferredCOFLinkObserver: public LLInventoryObserver { public: - LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update, LLPointer<LLInventoryCallback> cb = NULL, std::string description = ""): + LLDeferredCOFLinkObserver(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb, const std::string& description): mItemID(item_id), - mDoUpdate(do_update), mCallback(cb), mDescription(description) { @@ -2359,14 +2474,13 @@ public: if (item) { gInventory.removeObserver(this); - LLAppearanceMgr::instance().addCOFItemLink(item,mDoUpdate,mCallback); + LLAppearanceMgr::instance().addCOFItemLink(item, mCallback, mDescription); delete this; } } private: const LLUUID mItemID; - bool mDoUpdate; std::string mDescription; LLPointer<LLInventoryCallback> mCallback; }; @@ -2374,42 +2488,26 @@ private: // BAP - note that this runs asynchronously if the item is not already loaded from inventory. // Dangerous if caller assumes link will exist after calling the function. -void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update, LLPointer<LLInventoryCallback> cb, const std::string description) +void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, + LLPointer<LLInventoryCallback> cb, + const std::string description) { const LLInventoryItem *item = gInventory.getItem(item_id); if (!item) { - LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update, cb, description); + LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, cb, description); gInventory.addObserver(observer); } else { - addCOFItemLink(item, do_update, cb, description); - } -} - -void modified_cof_cb(const LLUUID& inv_item) -{ - LLAppearanceMgr::instance().updateAppearanceFromCOF(); - - // Start editing the item if previously requested. - gAgentWearables.editWearableIfRequested(inv_item); - - // TODO: camera mode may not be changed if a debug setting is tweaked - if( gAgentCamera.cameraCustomizeAvatar() ) - { - // If we're in appearance editing mode, the current tab may need to be refreshed - LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLFloaterSidePanelContainer::getPanel("appearance")); - if (panel) - { - panel->showDefaultSubpart(); - } + addCOFItemLink(item, cb, description); } } -void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update, LLPointer<LLInventoryCallback> cb, const std::string description) -{ - std::string link_description = description; +void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, + LLPointer<LLInventoryCallback> cb, + const std::string description) +{ const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item); if (!vitem) { @@ -2449,43 +2547,23 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update ++count; if (is_body_part && inv_item->getIsLinkType() && (vitem->getWearableType() == wearable_type)) { - gInventory.purgeObject(inv_item->getUUID()); + remove_inventory_item(inv_item->getUUID(), cb); } else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) { // MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE - gInventory.purgeObject(inv_item->getUUID()); + remove_inventory_item(inv_item->getUUID(), cb); } } } - if (linked_already) - { - if (do_update) - { - LLAppearanceMgr::updateAppearanceFromCOF(); - } - return; - } - else + if (!linked_already) { - if(do_update && cb.isNull()) - { - cb = new LLBoostFuncInventoryCallback(modified_cof_cb); - } - if (vitem->getIsLinkType()) - { - link_description = vitem->getActualDescription(); - } - link_inventory_item( gAgent.getID(), - vitem->getLinkedUUID(), - getCOF(), - vitem->getName(), - link_description, - LLAssetType::AT_LINK, - cb); + LLViewerInventoryItem *copy_item = new LLViewerInventoryItem; + copy_item->copyViewerItem(vitem); + copy_item->setDescription(description); + link_inventory_object(getCOF(), copy_item, cb); } - return; } LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id) @@ -2515,6 +2593,12 @@ LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& i return result; } +bool LLAppearanceMgr::isLinkedInCOF(const LLUUID& item_id) +{ + LLInventoryModel::item_array_t links = LLAppearanceMgr::instance().findCOFItemLinks(item_id); + return links.size() > 0; +} + void LLAppearanceMgr::removeAllClothesFromAvatar() { // Fetch worn clothes (i.e. the ones in COF). @@ -2525,8 +2609,7 @@ void LLAppearanceMgr::removeAllClothesFromAvatar() dummy, clothing_items, LLInventoryModel::EXCLUDE_TRASH, - is_clothing, - false); + is_clothing); uuid_vec_t item_ids; for (LLInventoryModel::item_array_t::iterator it = clothing_items.begin(); it != clothing_items.end(); ++it) @@ -2570,7 +2653,7 @@ void LLAppearanceMgr::removeAllAttachmentsFromAvatar() removeItemsFromAvatar(ids_to_remove); } -void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id) +void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb) { gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); @@ -2585,12 +2668,12 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id) const LLInventoryItem* item = item_array.at(i).get(); if (item->getIsLinkType() && item->getLinkedUUID() == item_id) { - gInventory.purgeObject(item->getUUID()); + remove_inventory_item(item->getUUID(), cb); } } } -void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type) +void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb) { LLFindWearablesOfType filter_wearables_of_type(type); LLInventoryModel::cat_array_t cats; @@ -2603,7 +2686,7 @@ void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type) const LLViewerInventoryItem* item = *it; if (item->getIsLinkType()) // we must operate on links only { - gInventory.purgeObject(item->getUUID()); + remove_inventory_item(item->getUUID(), cb); } } } @@ -2642,7 +2725,7 @@ void LLAppearanceMgr::updateIsDirty() if (base_outfit.notNull()) { - LLIsOfAssetType collector = LLIsOfAssetType(LLAssetType::AT_LINK); + LLIsValidItemLink collector; LLInventoryModel::cat_array_t cof_cats; LLInventoryModel::item_array_t cof_items; @@ -2656,6 +2739,7 @@ void LLAppearanceMgr::updateIsDirty() if(outfit_items.size() != cof_items.size()) { + LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.size() << " cof " << cof_items.size() << LL_ENDL; // Current outfit folder should have one more item than the outfit folder. // this one item is the link back to the outfit folder itself. mOutfitIsDirty = true; @@ -2675,11 +2759,30 @@ void LLAppearanceMgr::updateIsDirty() item1->getName() != item2->getName() || item1->getActualDescription() != item2->getActualDescription()) { + if (item1->getLinkedUUID() != item2->getLinkedUUID()) + { + LL_DEBUGS("Avatar") << "link id different " << LL_ENDL; + } + else + { + if (item1->getName() != item2->getName()) + { + LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << LL_ENDL; + } + if (item1->getActualDescription() != item2->getActualDescription()) + { + LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription() + << " " << item2->getActualDescription() + << " names " << item1->getName() << " " << item2->getName() << LL_ENDL; + } + } mOutfitIsDirty = true; return; } } } + llassert(!mOutfitIsDirty); + LL_DEBUGS("Avatar") << "clean" << LL_ENDL; } // *HACK: Must match name in Library or agent inventory @@ -2761,23 +2864,6 @@ void LLAppearanceMgr::copyLibraryGestures() } } -void LLAppearanceMgr::autopopulateOutfits() -{ - // If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account) - // then auto-populate outfits from the library into the My Outfits folder. - - LL_INFOS("Avatar") << self_av_string() << "avatar fully visible" << LL_ENDL; - - static bool check_populate_my_outfits = true; - if (check_populate_my_outfits && - (LLInventoryModel::getIsFirstTimeInViewer2() - || gSavedSettings.getBOOL("MyOutfitsAutofill"))) - { - gAgentWearables.populateMyOutfitsFolder(); - } - check_populate_my_outfits = false; -} - // Handler for anything that's deferred until avatar de-clouds. void LLAppearanceMgr::onFirstFullyVisible() { @@ -2785,10 +2871,6 @@ void LLAppearanceMgr::onFirstFullyVisible() gAgentAvatarp->reportAvatarRezTime(); gAgentAvatarp->debugAvatarVisible(); - // The auto-populate is failing at the point of generating outfits - // folders, so don't do the library copy until that is resolved. - // autopopulateOutfits(); - // If this is the first time we've ever logged in, // then copy default gestures from the library. if (gAgent.isFirstLogin()) { @@ -2803,9 +2885,27 @@ void appearance_mgr_update_dirty_state() if (LLAppearanceMgr::instanceExists()) { LLAppearanceMgr::getInstance()->updateIsDirty(); + LLAppearanceMgr::getInstance()->setOutfitLocked(false); + gAgentWearables.notifyLoadingFinished(); } } +void update_base_outfit_after_ordering() +{ + LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); + + LLPointer<LLInventoryCallback> dirty_state_updater = + new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state); + + //COF contains only links so we copy to the Base Outfit only links + const LLUUID base_outfit_id = app_mgr.getBaseOutfitUUID(); + bool copy_folder_links = false; + app_mgr.slamCategoryLinks(app_mgr.getCOF(), base_outfit_id, copy_folder_links, dirty_state_updater); + +} + +// Save COF changes - update the contents of the current base outfit +// to match the current COF. Fails if no current base outfit is set. bool LLAppearanceMgr::updateBaseOutfit() { if (isOutfitLocked()) @@ -2814,23 +2914,20 @@ bool LLAppearanceMgr::updateBaseOutfit() llassert(!isOutfitLocked()); return false; } + setOutfitLocked(true); gAgentWearables.notifyLoadingStarted(); const LLUUID base_outfit_id = getBaseOutfitUUID(); if (base_outfit_id.isNull()) return false; + LL_DEBUGS("Avatar") << "saving cof to base outfit " << base_outfit_id << LL_ENDL; - updateClothingOrderingInfo(); - - // in a Base Outfit we do not remove items, only links - purgeCategory(base_outfit_id, false); - - LLPointer<LLInventoryCallback> dirty_state_updater = - new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state); - - //COF contains only links so we copy to the Base Outfit only links - shallowCopyCategoryContents(getCOF(), base_outfit_id, dirty_state_updater); + LLPointer<LLInventoryCallback> cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, update_base_outfit_after_ordering); + // Really shouldn't be needed unless there's a race condition - + // updateAppearanceFromCOF() already calls updateClothingOrderingInfo. + updateClothingOrderingInfo(LLUUID::null, cb); return true; } @@ -2878,12 +2975,6 @@ struct WearablesOrderComparator bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2) { - if (!item1 || !item2) - { - LL_WARNS() << "either item1 or item2 is NULL" << LL_ENDL; - return true; - } - const std::string& desc1 = item1->getActualDescription(); const std::string& desc2 = item2->getActualDescription(); @@ -2897,260 +2988,373 @@ struct WearablesOrderComparator //items with ordering information but not for the associated wearables type if (!item1_valid && item2_valid) return false; + else if (item1_valid && !item2_valid) + return true; - return true; + return item1->getName() < item2->getName(); } U32 mControlSize; }; -void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base_outfit_ordering) +void LLAppearanceMgr::getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items, + desc_map_t& desc_map) { - if (cat_id.isNull()) - { - cat_id = getCOF(); - if (update_base_outfit_ordering) - { - const LLUUID base_outfit_id = getBaseOutfitUUID(); - if (base_outfit_id.notNull()) - { - updateClothingOrderingInfo(base_outfit_id,false); - } - } - } - - // COF is processed if cat_id is not specified - LLInventoryModel::item_array_t wear_items; - getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING, false); - wearables_by_type_t items_by_type(LLWearableType::WT_COUNT); divvyWearablesByType(wear_items, items_by_type); - bool inventory_changed = false; for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++) { - U32 size = items_by_type[type].size(); if (!size) continue; - + //sinking down invalid items which need reordering std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type)); - + //requesting updates only for those links which don't have "valid" descriptions for (U32 i = 0; i < size; i++) { LLViewerInventoryItem* item = items_by_type[type][i]; if (!item) continue; - + std::string new_order_str = build_order_string((LLWearableType::EType)type, i); if (new_order_str == item->getActualDescription()) continue; - - item->setDescription(new_order_str); - item->setComplete(TRUE); - item->updateServer(FALSE); - gInventory.updateItem(item); - inventory_changed = true; + desc_map[item->getUUID()] = new_order_str; } } - - //*TODO do we really need to notify observers? - if (inventory_changed) gInventory.notifyObservers(); } -// This is intended for use with HTTP Clients/Responders, but is not -// specifically coupled with those classes. -class LLHTTPRetryPolicy: public LLThreadSafeRefCount +bool LLAppearanceMgr::validateClothingOrderingInfo(LLUUID cat_id) { -public: - LLHTTPRetryPolicy() {} - virtual ~LLHTTPRetryPolicy() {} - virtual bool shouldRetry(U32 status, F32& seconds_to_wait) = 0; -}; + // COF is processed if cat_id is not specified + if (cat_id.isNull()) + { + cat_id = getCOF(); + } -// Example of simplest possible policy, not necessarily recommended. -class LLAlwaysRetryImmediatelyPolicy: public LLHTTPRetryPolicy -{ -public: - LLAlwaysRetryImmediatelyPolicy() {} - bool shouldRetry(U32 status, F32& seconds_to_wait) + LLInventoryModel::item_array_t wear_items; + getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); + + // Identify items for which desc needs to change. + desc_map_t desc_map; + getWearableOrderingDescUpdates(wear_items, desc_map); + + for (desc_map_t::const_iterator it = desc_map.begin(); + it != desc_map.end(); ++it) { - seconds_to_wait = 0.0; - return true; + const LLUUID& item_id = it->first; + const std::string& new_order_str = it->second; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_WARNS() << "Order validation fails: " << item->getName() + << " needs to update desc to: " << new_order_str + << " (from: " << item->getActualDescription() << ")" << LL_ENDL; } -}; + + return desc_map.size() == 0; +} -// Very general policy with geometric back-off after failures, -// up to a maximum delay, and maximum number of retries. -class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy +void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, + LLPointer<LLInventoryCallback> cb) { -public: - LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries): - mMinDelay(min_delay), - mMaxDelay(max_delay), - mBackoffFactor(backoff_factor), - mMaxRetries(max_retries), - mDelay(min_delay), - mRetryCount(0) + // COF is processed if cat_id is not specified + if (cat_id.isNull()) { + cat_id = getCOF(); } - bool shouldRetry(U32 status, F32& seconds_to_wait) + LLInventoryModel::item_array_t wear_items; + getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); + + // Identify items for which desc needs to change. + desc_map_t desc_map; + getWearableOrderingDescUpdates(wear_items, desc_map); + + for (desc_map_t::const_iterator it = desc_map.begin(); + it != desc_map.end(); ++it) { - seconds_to_wait = mDelay; - mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay); - mRetryCount++; - return (mRetryCount<=mMaxRetries); + LLSD updates; + const LLUUID& item_id = it->first; + const std::string& new_order_str = it->second; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << item->getName() << " updating desc to: " << new_order_str + << " (was: " << item->getActualDescription() << ")" << LL_ENDL; + updates["desc"] = new_order_str; + update_inventory_item(item_id,updates,cb); } + +} + +class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder +{ + LOG_CLASS(RequestAgentUpdateAppearanceResponder); + + friend class LLAppearanceMgr; + +public: + RequestAgentUpdateAppearanceResponder(); + + virtual ~RequestAgentUpdateAppearanceResponder(); private: - F32 mMinDelay; // delay never less than this value - F32 mMaxDelay; // delay never exceeds this value - F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. - U32 mMaxRetries; // maximum number of times shouldRetry will return true. - F32 mDelay; // current delay. - U32 mRetryCount; // number of times shouldRetry has been called. + // Called when sendServerAppearanceUpdate called. May or may not + // trigger a request depending on various bits of state. + void onRequestRequested(); + + // Post the actual appearance request to cap. + void sendRequest(); + + void debugCOF(const LLSD& content); + +protected: + // Successful completion. + /* virtual */ void httpSuccess(); + + // Error + /*virtual*/ void httpFailure(); + + void onFailure(); + void onSuccess(); + + S32 mInFlightCounter; + LLTimer mInFlightTimer; + LLPointer<LLHTTPRetryPolicy> mRetryPolicy; }; -class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder +RequestAgentUpdateAppearanceResponder::RequestAgentUpdateAppearanceResponder() { -public: - RequestAgentUpdateAppearanceResponder() + bool retry_on_4xx = true; + mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10, retry_on_4xx); + mInFlightCounter = 0; +} + +RequestAgentUpdateAppearanceResponder::~RequestAgentUpdateAppearanceResponder() +{ +} + +void RequestAgentUpdateAppearanceResponder::onRequestRequested() +{ + // If we have already received an update for this or higher cof version, ignore. + S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); + S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; + S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion; + LL_DEBUGS("Avatar") << "cof_version " << cof_version + << " last_rcv " << last_rcv + << " last_req " << last_req + << " in flight " << mInFlightCounter << LL_ENDL; + if ((mInFlightCounter>0) && (mInFlightTimer.hasExpired())) { - mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10); + LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL; + mInFlightCounter = 0; + } + if (cof_version < last_rcv) + { + LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv + << " will not request for " << cof_version << LL_ENDL; + return; + } + if (mInFlightCounter>0 && last_req >= cof_version) + { + LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req + << " will not request for " << cof_version << LL_ENDL; + return; } - virtual ~RequestAgentUpdateAppearanceResponder() + // Actually send the request. + LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL; + mRetryPolicy->reset(); + sendRequest(); +} + +void RequestAgentUpdateAppearanceResponder::sendRequest() +{ + if (gAgentAvatarp->isEditingAppearance()) { + // don't send out appearance updates if in appearance editing mode + return; } - // Successful completion. - /* virtual */ void result(const LLSD& content) + if (!gAgent.getRegion()) { - LL_DEBUGS("Avatar") << "content: " << ll_pretty_print_sd(content) << LL_ENDL; - if (content["success"].asBoolean()) + LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL; + return; + } + if (gAgent.getRegion()->getCentralBakeVersion()==0) + { + LL_WARNS() << "Region does not support baking" << LL_ENDL; + } + std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance"); + if (url.empty()) + { + LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL; + return; + } + + LLSD body; + S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); + if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) + { + body = LLAppearanceMgr::instance().dumpCOF(); + } + else + { + body["cof_version"] = cof_version; + if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) { - LL_DEBUGS("Avatar") << "OK" << LL_ENDL; - if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) + body["cof_version"] = cof_version+999; + } + } + LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL; + + mInFlightCounter++; + mInFlightTimer.setTimerExpirySec(60.0); + LLHTTPClient::post(url, body, this); + llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); + gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; +} + +void RequestAgentUpdateAppearanceResponder::debugCOF(const LLSD& content) +{ + LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger() + << " ================================= " << LL_ENDL; + std::set<LLUUID> ais_items, local_items; + const LLSD& cof_raw = content["cof_raw"]; + for (LLSD::array_const_iterator it = cof_raw.beginArray(); + it != cof_raw.endArray(); ++it) + { + const LLSD& item = *it; + if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) + { + ais_items.insert(item["item_id"].asUUID()); + if (item["type"].asInteger() == 24) // link + { + LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID() + << " linked_item_id: " << item["asset_id"].asUUID() + << " name: " << item["name"].asString() + << LL_ENDL; + } + else if (item["type"].asInteger() == 25) // folder link + { + LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID() + << " linked_item_id: " << item["asset_id"].asUUID() + << " name: " << item["name"].asString() + << LL_ENDL; + } + else { - dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_ok", content); + LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID() + << " linked_item_id: " << item["asset_id"].asUUID() + << " name: " << item["name"].asString() + << " type: " << item["type"].asInteger() + << LL_ENDL; } } - else + } + LL_INFOS("Avatar") << LL_ENDL; + LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() + << " ================================= " << LL_ENDL; + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), + cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); + for (S32 i=0; i<item_array.size(); i++) + { + const LLViewerInventoryItem* inv_item = item_array.at(i).get(); + local_items.insert(inv_item->getUUID()); + LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID() + << " linked_item_id: " << inv_item->getLinkedUUID() + << " name: " << inv_item->getName() + << " parent: " << inv_item->getParentUUID() + << LL_ENDL; + } + LL_INFOS("Avatar") << " ================================= " << LL_ENDL; + S32 local_only = 0, ais_only = 0; + for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) + { + if (ais_items.find(*it) == ais_items.end()) { - onFailure(200); + LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; + local_only++; } } - - // Error - /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) { - LL_WARNS() << "appearance update request failed, status: " << status << " reason: " << reason << " code: " << content["code"].asInteger() << " error: \"" << content["error"].asString() << "\"" << LL_ENDL; - if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) + if (local_items.find(*it) == local_items.end()) { - dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_error", content); - debugCOF(content); - + LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; + ais_only++; } - onFailure(status); - } + } + if (local_only==0 && ais_only==0) + { + LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req " + << content["observed"].asInteger() + << " rcv " << content["expected"].asInteger() + << ")" << LL_ENDL; + } +} - void onFailure(U32 status) +/* virtual */ void RequestAgentUpdateAppearanceResponder::httpSuccess() +{ + const LLSD& content = getContent(); + if (!content.isMap()) { - F32 seconds_to_wait; - if (mRetryPolicy->shouldRetry(status,seconds_to_wait)) - { - LL_INFOS() << "retrying" << LL_ENDL; - doAfterInterval(boost::bind(&LLAppearanceMgr::requestServerAppearanceUpdate, - LLAppearanceMgr::getInstance(), - LLCurl::ResponderPtr(this)), - seconds_to_wait); - } - else + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + if (content["success"].asBoolean()) + { + LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL; + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) { - LL_WARNS() << "giving up after too many retries" << LL_ENDL; + dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content); } - } - void dumpContents(const std::string outprefix, const LLSD& content) + onSuccess(); + } + else { - std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml"); - std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); - std::ofstream ofs(fullpath.c_str(), std::ios_base::out); - ofs << LLSDOStreamer<LLSDXMLFormatter>(content, LLSDFormatter::OPTIONS_PRETTY); - LL_DEBUGS("Avatar") << "results saved to: " << fullpath << LL_ENDL; + failureResult(HTTP_INTERNAL_ERROR, "Non-success response", content); } +} + +void RequestAgentUpdateAppearanceResponder::onSuccess() +{ + mInFlightCounter = llmax(mInFlightCounter-1,0); +} + +/*virtual*/ void RequestAgentUpdateAppearanceResponder::httpFailure() +{ + LL_WARNS("Avatar") << "appearance update request failed, status " + << getStatus() << " reason " << getReason() << LL_ENDL; - void debugCOF(const LLSD& content) + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) { - LL_DEBUGS("Avatar") << "AIS COF, version found: " << content["expected"].asInteger() << LL_ENDL; - std::set<LLUUID> ais_items, local_items; - const LLSD& cof_raw = content["cof_raw"]; - for (LLSD::array_const_iterator it = cof_raw.beginArray(); - it != cof_raw.endArray(); ++it) - { - const LLSD& item = *it; - if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) - { - ais_items.insert(item["item_id"].asUUID()); - if (item["type"].asInteger() == 24) // link - { - LL_DEBUGS("Avatar") << "Link: item_id: " << item["item_id"].asUUID() - << " linked_item_id: " << item["asset_id"].asUUID() - << " name: " << item["name"].asString() - << LL_ENDL; - } - else if (item["type"].asInteger() == 25) // folder link - { - LL_DEBUGS("Avatar") << "Folder link: item_id: " << item["item_id"].asUUID() - << " linked_item_id: " << item["asset_id"].asUUID() - << " name: " << item["name"].asString() - << LL_ENDL; - - } - else - { - LL_DEBUGS("Avatar") << "Other: item_id: " << item["item_id"].asUUID() - << " linked_item_id: " << item["asset_id"].asUUID() - << " name: " << item["name"].asString() - << LL_ENDL; - } - } - } - LL_DEBUGS("Avatar") << LL_ENDL; - LL_DEBUGS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() << LL_ENDL; - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), - cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); - for (S32 i=0; i<item_array.size(); i++) - { - const LLViewerInventoryItem* inv_item = item_array.at(i).get(); - local_items.insert(inv_item->getUUID()); - LL_DEBUGS("Avatar") << "item_id: " << inv_item->getUUID() - << " linked_item_id: " << inv_item->getLinkedUUID() - << " name: " << inv_item->getName() - << LL_ENDL; - } - LL_DEBUGS("Avatar") << LL_ENDL; - for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) - { - if (ais_items.find(*it) == ais_items.end()) - { - LL_DEBUGS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; - } - } - for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) - { - if (local_items.find(*it) == local_items.end()) - { - LL_DEBUGS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; - } - } + const LLSD& content = getContent(); + dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content); + debugCOF(content); } + onFailure(); +} + +void RequestAgentUpdateAppearanceResponder::onFailure() +{ + mInFlightCounter = llmax(mInFlightCounter-1,0); + + F32 seconds_to_wait; + mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); + if (mRetryPolicy->shouldRetry(seconds_to_wait)) + { + LL_INFOS() << "retrying" << LL_ENDL; + doAfterInterval(boost::bind(&RequestAgentUpdateAppearanceResponder::sendRequest,this), + seconds_to_wait); + } + else + { + LL_WARNS() << "giving up after too many retries" << LL_ENDL; + } +} - LLPointer<LLHTTPRetryPolicy> mRetryPolicy; -}; LLSD LLAppearanceMgr::dumpCOF() const { @@ -3215,58 +3419,14 @@ LLSD LLAppearanceMgr::dumpCOF() const return result; } -void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr responder_ptr) +void LLAppearanceMgr::requestServerAppearanceUpdate() { - if (gAgentAvatarp->isEditingAppearance()) - { - // don't send out appearance updates if in appearance editing mode - return; - } - - if (!gAgent.getRegion()) - { - LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL; - return; - } - if (gAgent.getRegion()->getCentralBakeVersion()==0) - { - LL_WARNS() << "Region does not support baking" << LL_ENDL; - } - std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance"); - if (url.empty()) - { - LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL; - return; - } - - LLSD body; - S32 cof_version = getCOFVersion(); - if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) - { - body = dumpCOF(); - } - else - { - body["cof_version"] = cof_version; - if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) - { - body["cof_version"] = cof_version+999; - } - } - LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL; - - //LLCurl::ResponderPtr responder_ptr; - if (!responder_ptr.get()) - { - responder_ptr = new RequestAgentUpdateAppearanceResponder; - } - LLHTTPClient::post(url, body, responder_ptr); - llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); - gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; + mAppearanceResponder->onRequestRequested(); } class LLIncrementCofVersionResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLIncrementCofVersionResponder); public: LLIncrementCofVersionResponder() : LLHTTPClient::Responder() { @@ -3277,22 +3437,31 @@ public: { } - virtual void result(const LLSD &pContent) +protected: + virtual void httpSuccess() { LL_INFOS() << "Successfully incremented agent's COF." << LL_ENDL; - S32 new_version = pContent["category"]["version"].asInteger(); + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + S32 new_version = content["category"]["version"].asInteger(); // cof_version should have increased llassert(new_version > gAgentAvatarp->mLastUpdateRequestCOFVersion); gAgentAvatarp->mLastUpdateRequestCOFVersion = new_version; } - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& content) + + virtual void httpFailure() { - LL_WARNS() << "While attempting to increment the agent's cof we got an error with [status:" - << pStatus << "]: " << content << LL_ENDL; + LL_WARNS("Avatar") << "While attempting to increment the agent's cof we got an error " + << dumpResponse() << LL_ENDL; F32 seconds_to_wait; - if (mRetryPolicy->shouldRetry(pStatus,seconds_to_wait)) + mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); + if (mRetryPolicy->shouldRetry(seconds_to_wait)) { LL_INFOS() << "retrying" << LL_ENDL; doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion, @@ -3306,6 +3475,7 @@ public: } } +private: LLPointer<LLHTTPRetryPolicy> mRetryPolicy; }; @@ -3338,6 +3508,15 @@ void LLAppearanceMgr::incrementCofVersion(LLHTTPClient::ResponderPtr responder_p LLHTTPClient::get(url, body, responder_ptr, headers, 30.0f); } +U32 LLAppearanceMgr::getNumAttachmentsInCOF() +{ + const LLUUID cof = getCOF(); + LLInventoryModel::item_array_t obj_items; + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); + return obj_items.size(); +} + + std::string LLAppearanceMgr::getAppearanceServiceURL() const { if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty()) @@ -3348,57 +3527,91 @@ std::string LLAppearanceMgr::getAppearanceServiceURL() const } void show_created_outfit(LLUUID& folder_id, bool show_panel = true) +{ + if (!LLApp::isRunning()) { - if (!LLApp::isRunning()) - { - LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; - return; - } - - LLSD key; - + LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; + return; + } + + LL_DEBUGS("Avatar") << "called" << LL_ENDL; + LLSD key; + //EXT-7727. For new accounts inventory callback is created during login process // and may be processed after login process is finished if (show_panel) - { - LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); - - } - LLOutfitsList *outfits_list = - dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); - if (outfits_list) - { + { + LL_DEBUGS("Avatar") << "showing panel" << LL_ENDL; + LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); + + } + LLOutfitsList *outfits_list = + dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); + if (outfits_list) + { outfits_list->setSelectedOutfitByUUID(folder_id); - } - - LLAppearanceMgr::getInstance()->updateIsDirty(); - gAgentWearables.notifyLoadingFinished(); // New outfit is saved. - LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); } + + LLAppearanceMgr::getInstance()->updateIsDirty(); + gAgentWearables.notifyLoadingFinished(); // New outfit is saved. + LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); + + // For SSB, need to update appearance after we add a base outfit + // link, since, the COF version has changed. There is a race + // condition in initial outfit setup which can lead to rez + // failures - SH-3860. + LL_DEBUGS("Avatar") << "requesting appearance update after createBaseOutfitLink" << LL_ENDL; + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; + LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb); +} -LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel) +void LLAppearanceMgr::onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel) { - if (!isAgentAvatarValid()) return LLUUID::null; - - gAgentWearables.notifyLoadingStarted(); + LLPointer<LLInventoryCallback> cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, + boost::bind(&LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered,this,folder_id,show_panel)); + updateClothingOrderingInfo(LLUUID::null, cb); +} - // First, make a folder in the My Outfits directory. - const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - LLUUID folder_id = gInventory.createNewCategory( - parent_id, - LLFolderType::FT_OUTFIT, - new_folder_name); +void LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel) +{ + LLPointer<LLInventoryCallback> cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, + boost::bind(show_created_outfit,folder_id,show_panel)); + bool copy_folder_links = false; + slamCategoryLinks(getCOF(), folder_id, copy_folder_links, cb); +} - updateClothingOrderingInfo(); +void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel) +{ + if (!isAgentAvatarValid()) return; - LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(no_op_inventory_func, - boost::bind(show_created_outfit,folder_id,show_panel)); - shallowCopyCategoryContents(getCOF(),folder_id, cb); - createBaseOutfitLink(folder_id, cb); + LL_DEBUGS("Avatar") << "creating new outfit" << LL_ENDL; - dumpCat(folder_id,"COF, new outfit"); + gAgentWearables.notifyLoadingStarted(); - return folder_id; + // First, make a folder in the My Outfits directory. + const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + if (AISCommand::isAPIAvailable()) + { + // cap-based category creation was buggy until recently. use + // existence of AIS as an indicator the fix is present. Does + // not actually use AIS to create the category. + inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel); + LLUUID folder_id = gInventory.createNewCategory( + parent_id, + LLFolderType::FT_OUTFIT, + new_folder_name, + func); + } + else + { + LLUUID folder_id = gInventory.createNewCategory( + parent_id, + LLFolderType::FT_OUTFIT, + new_folder_name); + onOutfitFolderCreated(folder_id, show_panel); + } } void LLAppearanceMgr::wearBaseOutfit() @@ -3414,23 +3627,24 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) if (ids_to_remove.empty()) { LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL; + return; } + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) { const LLUUID& id_to_remove = *it; const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); - removeCOFItemLinks(linked_item_id); + removeCOFItemLinks(linked_item_id, cb); addDoomedTempAttachment(linked_item_id); } - updateAppearanceFromCOF(); } void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) { LLUUID linked_item_id = gInventory.getLinkedItemID(id_to_remove); - removeCOFItemLinks(linked_item_id); + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; + removeCOFItemLinks(linked_item_id, cb); addDoomedTempAttachment(linked_item_id); - updateAppearanceFromCOF(); } @@ -3490,7 +3704,12 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b swap_item->setDescription(item->getActualDescription()); item->setDescription(tmp); + // LL_DEBUGS("Inventory") << "swap, item " + // << ll_pretty_print_sd(item->asLLSD()) + // << " swap_item " + // << ll_pretty_print_sd(swap_item->asLLSD()) << LL_ENDL; + // FIXME switch to use AISv3 where supported. //items need to be updated on a dataserver item->setComplete(TRUE); item->updateServer(FALSE); @@ -3504,7 +3723,7 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b bool result = false; if (result = gAgentWearables.moveWearable(item, closer_to_body)) { - gAgentAvatarp->wearableUpdated(item->getWearableType(), FALSE); + gAgentAvatarp->wearableUpdated(item->getWearableType()); } setOutfitDirty(true); @@ -3566,7 +3785,8 @@ LLAppearanceMgr::LLAppearanceMgr(): mAttachmentInvLinkEnabled(false), mOutfitIsDirty(false), mOutfitLocked(false), - mIsInUpdateAppearanceFromCOF(false) + mIsInUpdateAppearanceFromCOF(false), + mAppearanceResponder(new RequestAgentUpdateAppearanceResponder) { LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); @@ -3616,7 +3836,11 @@ void LLAppearanceMgr::registerAttachment(const LLUUID& item_id) // we have to pass do_update = true to call LLAppearanceMgr::updateAppearanceFromCOF. // it will trigger gAgentWariables.notifyLoadingFinished() // But it is not acceptable solution. See EXT-7777 - LLAppearanceMgr::addCOFItemLink(item_id, false); // Add COF link for item. + if (!isLinkedInCOF(item_id)) + { + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy(); + LLAppearanceMgr::addCOFItemLink(item_id, cb); // Add COF link for item. + } } else { @@ -3640,22 +3864,21 @@ void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id) BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const { - return gInventory.isObjectDescendentOf(obj_id, getCOF()); + const LLUUID& cof = getCOF(); + if (obj_id == cof) + return TRUE; + const LLInventoryObject* obj = gInventory.getObject(obj_id); + if (obj && obj->getParentUUID() == cof) + return TRUE; + return FALSE; } // static bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id) { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLLinkedItemIDMatches find_links(gInventory.getLinkedItemID(obj_id)); - gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - find_links); - - return !items.empty(); + const LLUUID& target_id = gInventory.getLinkedItemID(obj_id); + LLLinkedItemIDMatches find_links(target_id); + return gInventory.hasMatchingDirectDescendent(LLAppearanceMgr::instance().getCOF(), find_links); } BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const @@ -3672,18 +3895,6 @@ BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const // For now, don't allow direct deletion from the COF. Instead, force users // to choose "Detach" or "Take Off". return TRUE; - /* - const LLInventoryObject *obj = gInventory.getObject(obj_id); - if (!obj) return FALSE; - - // Can't delete bodyparts, since this would be equivalent to removing the item. - if (obj->getType() == LLAssetType::AT_BODYPART) return TRUE; - - // Can't delete the folder link, since this is saved for bookkeeping. - if (obj->getActualType() == LLAssetType::AT_LINK_FOLDER) return TRUE; - - return FALSE; - */ } class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver @@ -3824,7 +4035,7 @@ public: LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false); // *TODOw: This may not be necessary if initial outfit is chosen already -- josh - gAgent.setGenderChosen(TRUE); + gAgent.setOutfitChosen(TRUE); } // release avatar picker keyboard focus diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index b5ef0bd935..7742a19c07 100755 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -39,6 +39,7 @@ class LLWearableHoldingPattern; class LLInventoryCallback; class LLOutfitUnLockTimer; +class RequestAgentUpdateAppearanceResponder; class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> { @@ -50,7 +51,9 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> public: typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t; - void updateAppearanceFromCOF(bool update_base_outfit_ordering = false); + void updateAppearanceFromCOF(bool enforce_item_restrictions = true, + bool enforce_ordering = true, + nullary_func_t post_update_func = no_op); bool needToSaveCOF(); void updateCOF(const LLUUID& category, bool append = false); void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); @@ -65,9 +68,18 @@ public: S32 findExcessOrDuplicateItems(const LLUUID& cat_id, LLAssetType::EType type, S32 max_items, - LLInventoryModel::item_array_t& items_to_kill); - void enforceItemRestrictions(); - + LLInventoryObject::object_list_t& items_to_kill); + void findAllExcessOrDuplicateItems(const LLUUID& cat_id, + LLInventoryObject::object_list_t& items_to_kill); + void enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb); + + S32 getActiveCopyOperations() const; + + // Replace category contents with copied links via the slam_inventory_folder + // command (single inventory operation where supported) + void slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id, + bool include_folder_links, LLPointer<LLInventoryCallback> cb); + // Copy all items and the src category itself. void shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id, LLPointer<LLInventoryCallback> cb); @@ -106,15 +118,18 @@ public: const LLUUID getBaseOutfitUUID(); // Wear/attach an item (from a user's inventory) on the agent - bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update = true, bool replace = false, LLPointer<LLInventoryCallback> cb = NULL); + bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update, bool replace = false, + LLPointer<LLInventoryCallback> cb = NULL); // Update the displayed outfit name in UI. void updatePanelOutfitName(const std::string& name); - void purgeBaseOutfitLink(const LLUUID& category); + void purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb = NULL); void createBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> link_waiter); - void updateAgentWearables(LLWearableHoldingPattern* holder, bool append); + void updateAgentWearables(LLWearableHoldingPattern* holder); + + S32 countActiveHoldingPatterns(); // For debugging - could be moved elsewhere. void dumpCat(const LLUUID& cat_id, const std::string& msg); @@ -125,21 +140,17 @@ public: void registerAttachment(const LLUUID& item_id); void setAttachmentInvLinkEnable(bool val); - // utility function for bulk linking. - void linkAll(const LLUUID& category, - LLInventoryModel::item_array_t& items, - LLPointer<LLInventoryCallback> cb); - // Add COF link to individual item. - void addCOFItemLink(const LLUUID& item_id, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); - void addCOFItemLink(const LLInventoryItem *item, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); + void addCOFItemLink(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); + void addCOFItemLink(const LLInventoryItem *item, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); // Find COF entries referencing the given item. LLInventoryModel::item_array_t findCOFItemLinks(const LLUUID& item_id); + bool isLinkedInCOF(const LLUUID& item_id); // Remove COF entries - void removeCOFItemLinks(const LLUUID& item_id); - void removeCOFLinksOfType(LLWearableType::EType type); + void removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL); + void removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb = NULL); void removeAllClothesFromAvatar(); void removeAllAttachmentsFromAvatar(); @@ -156,12 +167,11 @@ public: // should only be necessary to do on initial login. void updateIsDirty(); + void setOutfitLocked(bool locked); + // Called when self avatar is first fully visible. void onFirstFullyVisible(); - // Create initial outfits from library. - void autopopulateOutfits(); - // Copy initial gestures from library. void copyLibraryGestures(); @@ -176,7 +186,10 @@ public: void removeItemFromAvatar(const LLUUID& item_id); - LLUUID makeNewOutfitLinks(const std::string& new_folder_name,bool show_panel = true); + void onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel); + void onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel); + + void makeNewOutfitLinks(const std::string& new_folder_name,bool show_panel = true); bool moveWearable(LLViewerInventoryItem* item, bool closer_to_body); @@ -185,18 +198,27 @@ public: //Divvy items into arrays by wearable type static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type); + typedef std::map<LLUUID,std::string> desc_map_t; + + void getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items, desc_map_t& desc_map); + //Check ordering information on wearables stored in links' descriptions and update if it is invalid // COF is processed if cat_id is not specified - void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, bool update_base_outfit_ordering = false); + bool validateClothingOrderingInfo(LLUUID cat_id = LLUUID::null); + + void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, + LLPointer<LLInventoryCallback> cb = NULL); bool isOutfitLocked() { return mOutfitLocked; } bool isInUpdateAppearanceFromCOF() { return mIsInUpdateAppearanceFromCOF; } - void requestServerAppearanceUpdate(LLCurl::ResponderPtr responder_ptr = NULL); + void requestServerAppearanceUpdate(); void incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr = NULL); + U32 getNumAttachmentsInCOF(); + // *HACK Remove this after server side texture baking is deployed on all sims. void incrementCofVersionLegacy(); @@ -217,24 +239,21 @@ private: void getDescendentsOfAssetType(const LLUUID& category, LLInventoryModel::item_array_t& items, - LLAssetType::EType type, - bool follow_folder_links); + LLAssetType::EType type); void getUserDescendents(const LLUUID& category, LLInventoryModel::item_array_t& wear_items, LLInventoryModel::item_array_t& obj_items, - LLInventoryModel::item_array_t& gest_items, - bool follow_folder_links); + LLInventoryModel::item_array_t& gest_items); - void purgeCategory(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t* keep_items = NULL); static void onOutfitRename(const LLSD& notification, const LLSD& response); - void setOutfitLocked(bool locked); - bool mAttachmentInvLinkEnabled; bool mOutfitIsDirty; bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. + LLPointer<RequestAgentUpdateAppearanceResponder> mAppearanceResponder; + /** * Lock for blocking operations on outfit until server reply or timeout exceed * to avoid unsynchronized outfit state or performing duplicate operations. @@ -266,17 +285,31 @@ public: class LLUpdateAppearanceOnDestroy: public LLInventoryCallback { public: - LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering = false); + LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions = true, + bool enforce_ordering = true, + nullary_func_t post_update_func = no_op); virtual ~LLUpdateAppearanceOnDestroy(); /* virtual */ void fire(const LLUUID& inv_item); private: U32 mFireCount; - bool mUpdateBaseOrder; + bool mEnforceItemRestrictions; + bool mEnforceOrdering; + nullary_func_t mPostUpdateFunc; }; +class LLUpdateAppearanceAndEditWearableOnDestroy: public LLInventoryCallback +{ +public: + LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id); + + /* virtual */ void fire(const LLUUID& item_id) {} -#define SUPPORT_ENSEMBLES 0 + ~LLUpdateAppearanceAndEditWearableOnDestroy(); + +private: + LLUUID mItemID; +}; LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3b9259a966..f52e6625c1 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2019,6 +2019,9 @@ bool LLAppViewer::cleanup() // Non-LLCurl libcurl library mAppCoreHttp.cleanup(); + // NOTE The following call is not thread safe. + ll_cleanup_ares(); + LLFilePickerThread::cleanupClass(); //MUST happen AFTER LLCurl::cleanupClass @@ -2114,6 +2117,8 @@ bool LLAppViewer::cleanup() ll_close_fail_log(); + LLError::LLCallStacks::cleanup(); + removeMarkerFiles(); LL_INFOS() << "Goodbye!" << LL_ENDL; @@ -3181,6 +3186,13 @@ bool LLAppViewer::initWindow() LLNotificationsUI::LLNotificationManager::getInstance(); + +#ifdef LL_DARWIN + //Satisfy both MAINT-3135 (OSX 10.6 and earlier) MAINT-3288 (OSX 10.7 and later) + if (getOSInfo().mMajorVer == 10 && getOSInfo().mMinorVer < 7) + gViewerWindow->getWindow()->setOldResize(true); +#endif + if (gSavedSettings.getBOOL("WindowMaximized")) { gViewerWindow->getWindow()->maximize(); diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 06f081e920..57fb84bbf1 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -438,7 +438,7 @@ void LLAppViewerWin32::disableWinErrorReporting() const S32 MAX_CONSOLE_LINES = 500; -void create_console() +static bool create_console() { int h_con_handle; long l_std_handle; @@ -447,7 +447,7 @@ void create_console() FILE *fp; // allocate a console for this app - AllocConsole(); + const bool isConsoleAllocated = AllocConsole(); // set the screen buffer to be big enough to let us scroll text GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); @@ -495,10 +495,13 @@ void create_console() *stderr = *fp; setvbuf( stderr, NULL, _IONBF, 0 ); } + + return isConsoleAllocated; } LLAppViewerWin32::LLAppViewerWin32(const char* cmd_line) : - mCmdLine(cmd_line) + mCmdLine(cmd_line), + mIsConsoleAllocated(false) { } @@ -542,6 +545,16 @@ bool LLAppViewerWin32::cleanup() gDXHardware.cleanup(); +#ifndef LL_RELEASE_FOR_DOWNLOAD + LLWinDebug::instance().cleanup(); +#endif + + if (mIsConsoleAllocated) + { + FreeConsole(); + mIsConsoleAllocated = false; + } + return result; } @@ -553,7 +566,7 @@ void LLAppViewerWin32::initLoggingAndGetLastDuration() void LLAppViewerWin32::initConsole() { // pop up debug console - create_console(); + mIsConsoleAllocated = create_console(); return LLAppViewer::initConsole(); } diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index fb37df1a2f..59d1ddaa3d 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -61,7 +61,8 @@ protected: private: void disableWinErrorReporting(); - std::string mCmdLine; + std::string mCmdLine; + bool mIsConsoleAllocated; }; #endif // LL_LLAPPVIEWERWIN32_H diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp index 2b428aec4b..8833c57948 100755 --- a/indra/newview/llassetuploadqueue.cpp +++ b/indra/newview/llassetuploadqueue.cpp @@ -36,6 +36,7 @@ class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder { + LOG_CLASS(LLAssetUploadChainResponder); public: LLAssetUploadChainResponder(const LLSD& post_data, @@ -51,52 +52,54 @@ public: mDataSize(data_size), mScriptName(script_name) { - } + } virtual ~LLAssetUploadChainResponder() - { - if(mSupplier) - { - LLAssetUploadQueue *queue = mSupplier->get(); - if (queue) - { - // Give ownership of supplier back to queue. - queue->mSupplier = mSupplier; - mSupplier = NULL; - } - } - delete mSupplier; + { + if(mSupplier) + { + LLAssetUploadQueue *queue = mSupplier->get(); + if (queue) + { + // Give ownership of supplier back to queue. + queue->mSupplier = mSupplier; + mSupplier = NULL; + } + } + delete mSupplier; delete mData; - } + } - virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) - { - LL_WARNS() << "LLAssetUploadChainResponder Error [status:" - << statusNum << "]: " << content << LL_ENDL; - LLUpdateTaskInventoryResponder::errorWithContent(statusNum, reason, content); - LLAssetUploadQueue *queue = mSupplier->get(); - if (queue) +protected: + virtual void httpFailure() + { + // Parent class will spam the failure. + //LL_WARNS() << dumpResponse() << LL_ENDL; + LLUpdateTaskInventoryResponder::httpFailure(); + LLAssetUploadQueue *queue = mSupplier->get(); + if (queue) + { + queue->request(&mSupplier); + } + } + + virtual void httpSuccess() + { + LLUpdateTaskInventoryResponder::httpSuccess(); + LLAssetUploadQueue *queue = mSupplier->get(); + if (queue) { - queue->request(&mSupplier); - } - } - - virtual void result(const LLSD& content) - { - LLUpdateTaskInventoryResponder::result(content); - LLAssetUploadQueue *queue = mSupplier->get(); - if (queue) - { - // Responder is reused across 2 phase upload, - // so only start next upload after 2nd phase complete. - std::string state = content["state"]; - if(state == "complete") - { - queue->request(&mSupplier); - } - } - } + // Responder is reused across 2 phase upload, + // so only start next upload after 2nd phase complete. + const std::string& state = getContent()["state"].asStringRef(); + if(state == "complete") + { + queue->request(&mSupplier); + } + } + } +public: virtual void uploadUpload(const LLSD& content) { std::string uploader = content["uploader"]; diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index d86e63589f..a98ff64d0a 100755 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -225,37 +225,41 @@ LLAssetUploadResponder::~LLAssetUploadResponder() } // virtual -void LLAssetUploadResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +void LLAssetUploadResponder::httpFailure() { - LL_INFOS() << "LLAssetUploadResponder::error [status:" - << statusNum << "]: " << content << LL_ENDL; + // *TODO: Add adaptive retry policy? + LL_WARNS() << dumpResponse() << LL_ENDL; LLSD args; - switch(statusNum) + if (isHttpClientErrorStatus(getStatus())) { - case 400: - args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); - args["REASON"] = "Error in upload request. Please visit " - "http://secondlife.com/support for help fixing this problem."; - LLNotificationsUtil::add("CannotUploadReason", args); - break; - case 500: - default: - args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); - args["REASON"] = "The server is experiencing unexpected " - "difficulties."; - LLNotificationsUtil::add("CannotUploadReason", args); - break; + args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); + args["REASON"] = "Error in upload request. Please visit " + "http://secondlife.com/support for help fixing this problem."; + LLNotificationsUtil::add("CannotUploadReason", args); + } + else + { + args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); + args["REASON"] = "The server is experiencing unexpected " + "difficulties."; + LLNotificationsUtil::add("CannotUploadReason", args); } LLUploadDialog::modalUploadFinished(); LLFilePicker::instance().reset(); // unlock file picker when bulk upload fails } //virtual -void LLAssetUploadResponder::result(const LLSD& content) +void LLAssetUploadResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LL_DEBUGS() << "LLAssetUploadResponder::result from capabilities" << LL_ENDL; - std::string state = content["state"]; + const std::string& state = content["state"].asStringRef(); if (state == "upload") { @@ -280,7 +284,7 @@ void LLAssetUploadResponder::result(const LLSD& content) void LLAssetUploadResponder::uploadUpload(const LLSD& content) { - std::string uploader = content["uploader"]; + const std::string& uploader = content["uploader"].asStringRef(); if (mFileName.empty()) { LLHTTPClient::postFile(uploader, mVFileID, mAssetType, this); @@ -293,6 +297,7 @@ void LLAssetUploadResponder::uploadUpload(const LLSD& content) void LLAssetUploadResponder::uploadFailure(const LLSD& content) { + LL_WARNS() << dumpResponse() << LL_ENDL; // remove the "Uploading..." message LLUploadDialog::modalUploadFinished(); LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot"); @@ -301,7 +306,7 @@ void LLAssetUploadResponder::uploadFailure(const LLSD& content) floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "inventory"))); } - std::string reason = content["state"]; + const std::string& reason = content["state"].asStringRef(); // deal with L$ errors if (reason == "insufficient funds") { @@ -340,9 +345,9 @@ LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( } // virtual -void LLNewAgentInventoryResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +void LLNewAgentInventoryResponder::httpFailure() { - LLAssetUploadResponder::errorWithContent(statusNum, reason, content); + LLAssetUploadResponder::httpFailure(); //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE); } @@ -445,58 +450,6 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE); } -LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type, - LLBakedUploadData * baked_upload_data) : - LLAssetUploadResponder(post_data, vfile_id, asset_type), - mBakedUploadData(baked_upload_data) -{ -} - -LLSendTexLayerResponder::~LLSendTexLayerResponder() -{ - // mBakedUploadData is normally deleted by calls to LLViewerTexLayerSetBuffer::onTextureUploadComplete() below - if (mBakedUploadData) - { // ...but delete it in the case where uploadComplete() is never called - delete mBakedUploadData; - mBakedUploadData = NULL; - } -} - - -// Baked texture upload completed -void LLSendTexLayerResponder::uploadComplete(const LLSD& content) -{ - LLUUID item_id = mPostData["item_id"]; - - std::string result = content["state"]; - LLUUID new_id = content["new_asset"]; - - LL_INFOS() << "result: " << result << " new_id: " << new_id << LL_ENDL; - if (result == "complete" - && mBakedUploadData != NULL) - { // Invoke - LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, 0, LL_EXSTAT_NONE); - mBakedUploadData = NULL; // deleted in onTextureUploadComplete() - } - else - { // Invoke the original callback with an error result - LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); - mBakedUploadData = NULL; // deleted in onTextureUploadComplete() - } -} - -void LLSendTexLayerResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) -{ - LL_INFOS() << "LLSendTexLayerResponder error [status:" - << statusNum << "]: " << content << LL_ENDL; - - // Invoke the original callback with an error result - LLViewerTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); - mBakedUploadData = NULL; // deleted in onTextureUploadComplete() -} - LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder( const LLSD& post_data, const LLUUID& vfile_id, @@ -1009,19 +962,14 @@ LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResp delete mImpl; } -void LLNewAgentInventoryVariablePriceResponder::errorWithContent( - U32 statusNum, - const std::string& reason, - const LLSD& content) +void LLNewAgentInventoryVariablePriceResponder::httpFailure() { - LL_DEBUGS() - << "LLNewAgentInventoryVariablePrice::error " << statusNum - << " reason: " << reason << LL_ENDL; + const LLSD& content = getContent(); + LL_WARNS("Upload") << dumpResponse() << LL_ENDL; - if ( content.has("error") ) + static const std::string _ERROR = "error"; + if ( content.has(_ERROR) ) { - static const std::string _ERROR = "error"; - mImpl->onTransportError(content[_ERROR]); } else @@ -1030,8 +978,14 @@ void LLNewAgentInventoryVariablePriceResponder::errorWithContent( } } -void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) +void LLNewAgentInventoryVariablePriceResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } // Parse out application level errors and the appropriate // responses for them static const std::string _ERROR = "error"; @@ -1047,6 +1001,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) // Check for application level errors if ( content.has(_ERROR) ) { + LL_WARNS("Upload") << dumpResponse() << LL_ENDL; onApplicationLevelError(content[_ERROR]); return; } @@ -1090,6 +1045,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) } else { + LL_WARNS("Upload") << dumpResponse() << LL_ENDL; onApplicationLevelError(""); } } diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index a6d1016136..7fbebc7481 100755 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -33,6 +33,8 @@ // via capabilities class LLAssetUploadResponder : public LLHTTPClient::Responder { +protected: + LOG_CLASS(LLAssetUploadResponder); public: LLAssetUploadResponder(const LLSD& post_data, const LLUUID& vfile_id, @@ -42,8 +44,11 @@ public: LLAssetType::EType asset_type); ~LLAssetUploadResponder(); - virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content); - virtual void result(const LLSD& content); +protected: + virtual void httpFailure(); + virtual void httpSuccess(); + +public: virtual void uploadUpload(const LLSD& content); virtual void uploadComplete(const LLSD& content); virtual void uploadFailure(const LLSD& content); @@ -58,6 +63,7 @@ protected: // TODO*: Remove this once deprecated class LLNewAgentInventoryResponder : public LLAssetUploadResponder { + LOG_CLASS(LLNewAgentInventoryResponder); public: LLNewAgentInventoryResponder( const LLSD& post_data, @@ -67,9 +73,10 @@ public: const LLSD& post_data, const std::string& file_name, LLAssetType::EType asset_type); - virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content); virtual void uploadComplete(const LLSD& content); virtual void uploadFailure(const LLSD& content); +protected: + virtual void httpFailure(); }; // A base class which goes through and performs some default @@ -79,6 +86,7 @@ public: class LLNewAgentInventoryVariablePriceResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLNewAgentInventoryVariablePriceResponder); public: LLNewAgentInventoryVariablePriceResponder( const LLUUID& vfile_id, @@ -91,12 +99,11 @@ public: const LLSD& inventory_info); virtual ~LLNewAgentInventoryVariablePriceResponder(); - void errorWithContent( - U32 statusNum, - const std::string& reason, - const LLSD& content); - void result(const LLSD& content); +private: + /* virtual */ void httpFailure(); + /* virtual */ void httpSuccess(); +public: virtual void onApplicationLevelError( const LLSD& error); virtual void showConfirmationDialog( @@ -109,24 +116,6 @@ private: Impl* mImpl; }; -struct LLBakedUploadData; -class LLSendTexLayerResponder : public LLAssetUploadResponder -{ - LOG_CLASS(LLSendTexLayerResponder); -public: - LLSendTexLayerResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type, - LLBakedUploadData * baked_upload_data); - - ~LLSendTexLayerResponder(); - - virtual void uploadComplete(const LLSD& content); - virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content); - - LLBakedUploadData * mBakedUploadData; -}; - class LLUpdateAgentInventoryResponder : public LLAssetUploadResponder { public: diff --git a/indra/newview/llbreastmotion.cpp b/indra/newview/llbreastmotion.cpp index 9a8cd5ceae..3a88bab3b3 100755 --- a/indra/newview/llbreastmotion.cpp +++ b/indra/newview/llbreastmotion.cpp @@ -340,8 +340,7 @@ BOOL LLBreastMotion::onUpdate(F32 time, U8* joint_mask) if (mBreastParamsDriven[i]) { mCharacter->setVisualParamWeight(mBreastParamsDriven[i], - new_local_pt[i], - FALSE); + new_local_pt[i]); } } diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp index 928c3baafa..b0537a83f1 100755 --- a/indra/newview/llchannelmanager.cpp +++ b/indra/newview/llchannelmanager.cpp @@ -113,33 +113,29 @@ void LLChannelManager::onLoginCompleted() } else { - // TODO: Seems this code leads to MAINT-3536 new crash in XML_ParserFree. - // Need to investigate this and fix possible problems with notifications in startup time - // Viewer can normally receive and show of postponed notifications about purchasing in marketplace on startup time. - // Other types of postponed notifications did not tested. - //// create a channel for the StartUp Toast - //LLScreenChannelBase::Params p; - //p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID")); - //p.channel_align = CA_RIGHT; - //mStartUpChannel = createChannel(p); - - //if(!mStartUpChannel) - //{ - // onStartUpToastClose(); - //} - //else - //{ - // gViewerWindow->getRootView()->addChild(mStartUpChannel); - - // // init channel's position and size - // S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); - // S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth"); - // mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound); - // mStartUpChannel->setMouseDownCallback(boost::bind(&LLNotificationWellWindow::onStartUpToastClick, LLNotificationWellWindow::getInstance(), _2, _3, _4)); - - // mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this)); - // mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime")); - //} + // create a channel for the StartUp Toast + LLScreenChannelBase::Params p; + p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID")); + p.channel_align = CA_RIGHT; + mStartUpChannel = createChannel(p); + + if(!mStartUpChannel) + { + onStartUpToastClose(); + } + else + { + gViewerWindow->getRootView()->addChild(mStartUpChannel); + + // init channel's position and size + S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); + S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth"); + mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound); + mStartUpChannel->setMouseDownCallback(boost::bind(&LLNotificationWellWindow::onStartUpToastClick, LLNotificationWellWindow::getInstance(), _2, _3, _4)); + + mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this)); + mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime")); + } } LLPersistentNotificationStorage::getInstance()->loadNotifications(); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 05c4181714..84b9ac756a 100755 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -107,6 +107,7 @@ class LLChatHistoryHeader: public LLPanel public: LLChatHistoryHeader() : LLPanel(), + mInfoCtrl(NULL), mPopupMenuHandleAvatar(), mPopupMenuHandleObject(), mAvatarID(), @@ -129,9 +130,6 @@ public: ~LLChatHistoryHeader() { - // Detach the info button so that it doesn't get destroyed (EXT-8463). - hideInfoCtrl(); - if (mAvatarNameCacheConnection.connected()) { mAvatarNameCacheConnection.disconnect(); @@ -292,6 +290,11 @@ public: mUserNameTextBox = getChild<LLTextBox>("user_name"); mTimeBoxTextBox = getChild<LLTextBox>("time_box"); + mInfoCtrl = LLUICtrlFactory::getInstance()->createFromFile<LLUICtrl>("inspector_info_ctrl.xml", this, LLPanel::child_registry_t::instance()); + llassert(mInfoCtrl != NULL); + mInfoCtrl->setCommitCallback(boost::bind(&LLChatHistoryHeader::onClickInfoCtrl, mInfoCtrl)); + mInfoCtrl->setVisible(FALSE); + return LLPanel::postBuild(); } @@ -589,39 +592,19 @@ protected: void showInfoCtrl() { - if (mAvatarID.isNull() || mFrom.empty() || CHAT_SOURCE_SYSTEM == mSourceType) return; - - if (!sInfoCtrl) - { - // *TODO: Delete the button at exit. - sInfoCtrl = LLUICtrlFactory::createFromFile<LLUICtrl>("inspector_info_ctrl.xml", NULL, LLPanel::child_registry_t::instance()); - if (sInfoCtrl) - { - sInfoCtrl->setCommitCallback(boost::bind(&LLChatHistoryHeader::onClickInfoCtrl, sInfoCtrl)); - } - } - - if (!sInfoCtrl) + const bool isVisible = !mAvatarID.isNull() && !mFrom.empty() && CHAT_SOURCE_SYSTEM != mSourceType; + if (isVisible) { - llassert(sInfoCtrl != NULL); - return; + const LLRect sticky_rect = mUserNameTextBox->getRect(); + S32 icon_x = llmin(sticky_rect.mLeft + mUserNameTextBox->getTextBoundingRect().getWidth() + 7, sticky_rect.mRight - 3); + mInfoCtrl->setOrigin(icon_x, sticky_rect.getCenterY() - mInfoCtrl->getRect().getHeight() / 2 ) ; } - - LLTextBox* name = getChild<LLTextBox>("user_name"); - LLRect sticky_rect = name->getRect(); - S32 icon_x = llmin(sticky_rect.mLeft + name->getTextBoundingRect().getWidth() + 7, sticky_rect.mRight - 3); - sInfoCtrl->setOrigin(icon_x, sticky_rect.getCenterY() - sInfoCtrl->getRect().getHeight() / 2 ) ; - addChild(sInfoCtrl); + mInfoCtrl->setVisible(isVisible); } void hideInfoCtrl() { - if (!sInfoCtrl) return; - - if (sInfoCtrl->getParent() == this) - { - removeChild(sInfoCtrl); - } + mInfoCtrl->setVisible(FALSE); } private: @@ -692,7 +675,7 @@ protected: LLHandle<LLView> mPopupMenuHandleAvatar; LLHandle<LLView> mPopupMenuHandleObject; - static LLUICtrl* sInfoCtrl; + LLUICtrl* mInfoCtrl; LLUUID mAvatarID; LLSD mObjectData; @@ -709,8 +692,6 @@ private: boost::signals2::connection mAvatarNameCacheConnection; }; -LLUICtrl* LLChatHistoryHeader::sInfoCtrl = NULL; - LLChatHistory::LLChatHistory(const LLChatHistory::Params& p) : LLUICtrl(p), mMessageHeaderFilename(p.message_header), diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h index bb6d4fb59c..44736a0489 100755 --- a/indra/newview/llchathistory.h +++ b/indra/newview/llchathistory.h @@ -93,14 +93,15 @@ class LLChatHistory : public LLUICtrl * @return pointer to LLView separator object. */ LLView* getSeparator(); + + void onClickMoreText(); + + private: /** * Builds a message header. * @return pointer to LLView header object. */ LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args); - - void onClickMoreText(); - public: ~LLChatHistory(); LLSD getValue() const; diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index fd4f17b694..cfc62c07b6 100755 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -29,7 +29,6 @@ #include "llchatitemscontainerctrl.h" #include "lltextbox.h" -#include "llchatmsgbox.h" #include "llavatariconctrl.h" #include "llcommandhandler.h" #include "llfloaterreg.h" @@ -130,7 +129,6 @@ void LLFloaterIMNearbyChatToastPanel::addMessage(LLSD& notification) { std::string messageText = notification["message"].asString(); // UTF-8 line of text - LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text", false); std::string color_name = notification["text_color"].asString(); @@ -171,7 +169,7 @@ void LLFloaterIMNearbyChatToastPanel::addMessage(LLSD& notification) { style_params.font.style = "ITALIC"; } - msg_text->appendText(messageText, TRUE, style_params); + mMsgText->appendText(messageText, TRUE, style_params); } snapToMessageHeight(); @@ -204,9 +202,10 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) case 2: messageFont = LLFontGL::getFontSansSerifBig(); break; } - LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text", false); + mMsgText = getChild<LLChatMsgBox>("msg_text", false); + mMsgText->setContentTrusted(false); - msg_text->setText(std::string("")); + mMsgText->setText(std::string("")); if ( notification["chat_style"].asInteger() != CHAT_STYLE_IRC ) { @@ -232,12 +231,12 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) style_params_name.link_href = notification["sender_slurl"].asString(); style_params_name.is_link = true; - msg_text->appendText(str_sender, FALSE, style_params_name); + mMsgText->appendText(str_sender, FALSE, style_params_name); } else { - msg_text->appendText(str_sender, false); + mMsgText->appendText(str_sender, false); } } @@ -264,7 +263,7 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) { style_params.font.style = "ITALIC"; } - msg_text->appendText(messageText, FALSE, style_params); + mMsgText->appendText(messageText, FALSE, style_params); } @@ -275,8 +274,7 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) void LLFloaterIMNearbyChatToastPanel::snapToMessageHeight () { - LLChatMsgBox* text_box = getChild<LLChatMsgBox>("msg_text", false); - S32 new_height = llmax (text_box->getTextPixelHeight() + 2*text_box->getVPad() + 2*msg_height_pad, 25); + S32 new_height = llmax (mMsgText->getTextPixelHeight() + 2*mMsgText->getVPad() + 2*msg_height_pad, 25); LLRect panel_rect = getRect(); @@ -312,14 +310,13 @@ BOOL LLFloaterIMNearbyChatToastPanel::handleMouseUp (S32 x, S32 y, MASK mask) return LLPanel::handleMouseUp(x,y,mask); */ - LLChatMsgBox* text_box = getChild<LLChatMsgBox>("msg_text", false); - S32 local_x = x - text_box->getRect().mLeft; - S32 local_y = y - text_box->getRect().mBottom; + S32 local_x = x - mMsgText->getRect().mLeft; + S32 local_y = y - mMsgText->getRect().mBottom; //if text_box process mouse up (ussually this is click on url) - we didn't show nearby_chat. - if (text_box->pointInView(local_x, local_y) ) + if (mMsgText->pointInView(local_x, local_y) ) { - if (text_box->handleMouseUp(local_x,local_y,mask) == TRUE) + if (mMsgText->handleMouseUp(local_x,local_y,mask) == TRUE) return TRUE; else { diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h index 54b6499d52..f66670ec8c 100755 --- a/indra/newview/llchatitemscontainerctrl.h +++ b/indra/newview/llchatitemscontainerctrl.h @@ -28,6 +28,7 @@ #define LL_LLCHATITEMSCONTAINERCTRL_H_ #include "llchat.h" +#include "llchatmsgbox.h" #include "llpanel.h" #include "llscrollbar.h" #include "llviewerchat.h" @@ -85,6 +86,7 @@ private: LLUUID mFromID; // agent id or object id std::string mFromName; EChatSourceType mSourceType; + LLChatMsgBox* mMsgText; diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index b1dce42dfd..c0823182c0 100755 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -204,6 +204,7 @@ void LLNotificationChiclet::createMenu() enable_registrar.add("NotificationWellChicletMenu.EnableItem", boost::bind(&LLNotificationChiclet::enableMenuItem, this, _2)); + llassert(LLMenuGL::sMenuContainer != NULL); mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu> ("menu_notification_well_button.xml", LLMenuGL::sMenuContainer, diff --git a/indra/newview/llclassifiedstatsresponder.cpp b/indra/newview/llclassifiedstatsresponder.cpp index bc7815fba2..f1ef8e9a03 100755 --- a/indra/newview/llclassifiedstatsresponder.cpp +++ b/indra/newview/llclassifiedstatsresponder.cpp @@ -42,8 +42,14 @@ LLClassifiedStatsResponder::LLClassifiedStatsResponder(LLUUID classified_id) {} /*virtual*/ -void LLClassifiedStatsResponder::result(const LLSD& content) +void LLClassifiedStatsResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } S32 teleport = content["teleport_clicks"].asInteger(); S32 map = content["map_clicks"].asInteger(); S32 profile = content["profile_clicks"].asInteger(); @@ -59,7 +65,8 @@ void LLClassifiedStatsResponder::result(const LLSD& content) } /*virtual*/ -void LLClassifiedStatsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLClassifiedStatsResponder::httpFailure() { - LL_INFOS() << "LLClassifiedStatsResponder::error [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; } + diff --git a/indra/newview/llclassifiedstatsresponder.h b/indra/newview/llclassifiedstatsresponder.h index 06dcb62fd0..efa4d82411 100755 --- a/indra/newview/llclassifiedstatsresponder.h +++ b/indra/newview/llclassifiedstatsresponder.h @@ -33,13 +33,15 @@ class LLClassifiedStatsResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLClassifiedStatsResponder); public: LLClassifiedStatsResponder(LLUUID classified_id); + +protected: //If we get back a normal response, handle it here - virtual void result(const LLSD& content); + virtual void httpSuccess(); //If we get back an error (not found, etc...), handle it here - - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + virtual void httpFailure(); protected: LLUUID mClassifiedID; diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h index d8cdcdfc97..dc74506c53 100644 --- a/indra/newview/llconversationmodel.h +++ b/indra/newview/llconversationmodel.h @@ -291,6 +291,9 @@ class LLConversationViewModel { public: typedef LLFolderViewModel<LLConversationSort, LLConversationItem, LLConversationItem, LLConversationFilter> base_t; + LLConversationViewModel() + : base_t(new LLConversationSort(), new LLConversationFilter()) + {} void sort(LLFolderViewFolder* folder); bool contentsReady() { return true; } // *TODO : we need to check that participants names are available somewhat diff --git a/indra/newview/lldeferredsounds.cpp b/indra/newview/lldeferredsounds.cpp index 9416e7cd29..e1613e4719 100755 --- a/indra/newview/lldeferredsounds.cpp +++ b/indra/newview/lldeferredsounds.cpp @@ -39,7 +39,10 @@ void LLDeferredSounds::playdeferredSounds() { while(soundVector.size()) { - gAudiop->triggerSound(soundVector.back()); + if (gAudiop) + { + gAudiop->triggerSound(soundVector.back()); + } soundVector.pop_back(); } } diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 0ecdabbbe9..90e6dfe351 100755 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -1518,6 +1518,18 @@ void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer> } //LL_INFOS() << "Rebuilt face " << face->getTEOffset() << " of " << face->getDrawable() << " at " << gFrameTimeSeconds << LL_ENDL; + + // Let getGeometryVolume know if a texture matrix is in play + if (face->mTextureMatrix) + { + face->setState(LLFace::TEXTURE_ANIM); + } + else + { + face->clearState(LLFace::TEXTURE_ANIM); + } + + face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true); buffer->flush(); diff --git a/indra/newview/llemote.cpp b/indra/newview/llemote.cpp index 510ff69acf..b9ef297c00 100755 --- a/indra/newview/llemote.cpp +++ b/indra/newview/llemote.cpp @@ -79,13 +79,13 @@ BOOL LLEmote::onActivate() LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" ); if( default_param ) { - default_param->setWeight( default_param->getMaxWeight(), FALSE ); + default_param->setWeight( default_param->getMaxWeight()); } mParam = mCharacter->getVisualParam(mName.c_str()); if (mParam) { - mParam->setWeight(0.f, FALSE); + mParam->setWeight(0.f); mCharacter->updateVisualParams(); } @@ -101,7 +101,7 @@ BOOL LLEmote::onUpdate(F32 time, U8* joint_mask) if( mParam ) { F32 weight = mParam->getMinWeight() + mPose.getWeight() * (mParam->getMaxWeight() - mParam->getMinWeight()); - mParam->setWeight(weight, FALSE); + mParam->setWeight(weight); // Cross fade against the default parameter LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" ); @@ -110,7 +110,7 @@ BOOL LLEmote::onUpdate(F32 time, U8* joint_mask) F32 default_param_weight = default_param->getMinWeight() + (1.f - mPose.getWeight()) * ( default_param->getMaxWeight() - default_param->getMinWeight() ); - default_param->setWeight( default_param_weight, FALSE ); + default_param->setWeight( default_param_weight); } mCharacter->updateVisualParams(); @@ -127,13 +127,13 @@ void LLEmote::onDeactivate() { if( mParam ) { - mParam->setWeight( mParam->getDefaultWeight(), FALSE ); + mParam->setWeight( mParam->getDefaultWeight()); } LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" ); if( default_param ) { - default_param->setWeight( default_param->getMaxWeight(), FALSE ); + default_param->setWeight( default_param->getMaxWeight()); } mCharacter->updateVisualParams(); diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp index 761adc5942..78d619a315 100755 --- a/indra/newview/llestateinfomodel.cpp +++ b/indra/newview/llestateinfomodel.cpp @@ -112,19 +112,19 @@ void LLEstateInfoModel::notifyCommit() class LLEstateChangeInfoResponder : public LLHTTPClient::Responder { -public: - + LOG_CLASS(LLEstateChangeInfoResponder); +protected: // if we get a normal response, handle it here - virtual void result(const LLSD& content) + virtual void httpSuccesss() { LL_INFOS() << "Committed estate info" << LL_ENDL; LLEstateInfoModel::instance().notifyCommit(); } // if we get an error response - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + virtual void httpFailure() { - LL_WARNS() << "Failed to commit estate info [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS() << "Failed to commit estate info " << dumpResponse() << LL_ENDL; } }; diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index fbd9466afe..4de6ad4d2f 100755 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -31,7 +31,7 @@ #include "llagent.h" #include "llhttpclient.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h" #include "llsdserialize.h" #include "lleventtimer.h" #include "llviewerregion.h" @@ -49,6 +49,7 @@ namespace class LLEventPollResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLEventPollResponder); public: static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender); @@ -56,19 +57,19 @@ namespace void makeRequest(); + /* virtual */ void completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer); + private: LLEventPollResponder(const std::string& pollURL, const LLHost& sender); ~LLEventPollResponder(); void handleMessage(const LLSD& content); - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - virtual void result(const LLSD& content); - virtual void completedRaw(U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); + /* virtual */ void httpFailure(); + /* virtual */ void httpSuccess(); + private: bool mDone; @@ -149,20 +150,18 @@ namespace } // virtual - void LLEventPollResponder::completedRaw(U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) + void LLEventPollResponder::completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { - if (status == HTTP_BAD_GATEWAY) + if (getStatus() == HTTP_BAD_GATEWAY) { // These errors are not parsable as LLSD, // which LLHTTPClient::Responder::completedRaw will try to do. - completed(status, reason, LLSD()); + httpCompleted(); } else { - LLHTTPClient::Responder::completedRaw(status,reason,channels,buffer); + LLHTTPClient::Responder::completedRaw(channels,buffer); } } @@ -187,13 +186,13 @@ namespace } //virtual - void LLEventPollResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) + void LLEventPollResponder::httpFailure() { if (mDone) return; // A HTTP_BAD_GATEWAY (502) error is our standard timeout response // we get this when there are no events. - if ( status == HTTP_BAD_GATEWAY ) + if ( getStatus() == HTTP_BAD_GATEWAY ) { mErrorCount = 0; makeRequest(); @@ -207,13 +206,13 @@ namespace + mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC , this); - LL_WARNS() << "LLEventPollResponder error [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; } else { - LL_WARNS() << "LLEventPollResponder error <" << mCount - << "> [status:" << status << "]: " << content - << (mDone ? " -- done" : "") << LL_ENDL; + LL_WARNS() << dumpResponse() + << " [count:" << mCount << "] " + << (mDone ? " -- done" : "") << LL_ENDL; stop(); // At this point we have given up and the viewer will not receive HTTP messages from the simulator. @@ -234,7 +233,7 @@ namespace } //virtual - void LLEventPollResponder::result(const LLSD& content) + void LLEventPollResponder::httpSuccess() { LL_DEBUGS() << "LLEventPollResponder::result <" << mCount << ">" << (mDone ? " -- done" : "") << LL_ENDL; @@ -243,10 +242,12 @@ namespace mErrorCount = 0; - if (!content.get("events") || + const LLSD& content = getContent(); + if (!content.isMap() || + !content.get("events") || !content.get("id")) { - LL_WARNS() << "received event poll with no events or id key" << LL_ENDL; + LL_WARNS() << "received event poll with no events or id key: " << dumpResponse() << LL_ENDL; makeRequest(); return; } @@ -260,8 +261,8 @@ namespace } // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG - LL_DEBUGS() << "LLEventPollResponder::completed <" << mCount << "> " << events.size() << "events (id " - << LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL; + LL_DEBUGS() << "LLEventPollResponder::httpSuccess <" << mCount << "> " << events.size() << "events (id " + << LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL; LLSD::array_const_iterator i = events.beginArray(); LLSD::array_const_iterator end = events.endArray(); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 0b080cbdd7..32b510b21a 100755 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1638,7 +1638,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, do_xform = false; } - if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) + if (getVirtualSize() >= MIN_TEX_ANIM_SIZE || isState(LLFace::RIGGED)) { //don't override texture transform during tc bake tex_mode = 0; } diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp index 514aac46fc..e2fa117453 100644..100755 --- a/indra/newview/llfacebookconnect.cpp +++ b/indra/newview/llfacebookconnect.cpp @@ -110,28 +110,36 @@ public: LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS); } - virtual void completed(U32 status, const std::string& reason, const LLSD& content) + /* virtual */ void httpSuccess() { - if (isGoodStatus(status)) + LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; + LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); + } + + /* virtual */ void httpFailure() + { + if ( HTTP_FOUND == getStatus() ) { - LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL; - - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); + const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); + if (location.empty()) + { + LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() + << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; + } + else + { + LLFacebookConnect::instance().openFacebookWeb(location); + } } - else if (status != 302) + else { - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); - log_facebook_connect_error("Connect", status, reason, content.get("error_code"), content.get("error_description")); + LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; + LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); + const LLSD& content = getContent(); + log_facebook_connect_error("Connect", getStatus(), getReason(), + content.get("error_code"), content.get("error_description")); } } - - void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - if (status == 302) - { - LLFacebookConnect::instance().openFacebookWeb(content["location"]); - } - } }; /////////////////////////////////////////////////////////////////////////////// @@ -145,34 +153,42 @@ public: { LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTING); } - - virtual void completed(U32 status, const std::string& reason, const LLSD& content) + + /* virtual */ void httpSuccess() + { + toast_user_for_success(); + LL_DEBUGS("FacebookConnect") << "Post successful. " << dumpResponse() << LL_ENDL; + LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED); + } + + /* virtual */ void httpFailure() { - if (isGoodStatus(status)) + if ( HTTP_FOUND == getStatus() ) { - toast_user_for_success(); - LL_DEBUGS("FacebookConnect") << "Post successful. content: " << content << LL_ENDL; - - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED); + const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); + if (location.empty()) + { + LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() + << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; + } + else + { + LLFacebookConnect::instance().openFacebookWeb(location); + } } - else if (status == 404) + else if ( HTTP_NOT_FOUND == getStatus() ) { LLFacebookConnect::instance().connectToFacebook(); } else { - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POST_FAILED); - log_facebook_connect_error("Share", status, reason, content.get("error_code"), content.get("error_description")); + LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; + LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POST_FAILED); + const LLSD& content = getContent(); + log_facebook_connect_error("Share", getStatus(), getReason(), + content.get("error_code"), content.get("error_description")); } } - - void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - if (status == 302) - { - LLFacebookConnect::instance().openFacebookWeb(content["location"]); - } - } }; /////////////////////////////////////////////////////////////////////////////// @@ -196,24 +212,27 @@ public: LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); } - virtual void completed(U32 status, const std::string& reason, const LLSD& content) + /* virtual */ void httpSuccess() { - if (isGoodStatus(status)) - { - LL_DEBUGS("FacebookConnect") << "Disconnect successful. content: " << content << LL_ENDL; - setUserDisconnected(); + LL_DEBUGS("FacebookConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL; + setUserDisconnected(); + } - } + /* virtual */ void httpFailure() + { //User not found so already disconnected - else if(status == 404) + if ( HTTP_NOT_FOUND == getStatus() ) { - LL_DEBUGS("FacebookConnect") << "Already disconnected. content: " << content << LL_ENDL; + LL_DEBUGS("FacebookConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL; setUserDisconnected(); } else { + LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); - log_facebook_connect_error("Disconnect", status, reason, content.get("error_code"), content.get("error_description")); + const LLSD& content = getContent(); + log_facebook_connect_error("Disconnect", getStatus(), getReason(), + content.get("error_code"), content.get("error_description")); } } }; @@ -229,34 +248,35 @@ public: { LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS); } - - virtual void completed(U32 status, const std::string& reason, const LLSD& content) + + /* virtual */ void httpSuccess() { - if (isGoodStatus(status)) + LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; + LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); + } + + /* virtual */ void httpFailure() + { + // show the facebook login page if not connected yet + if ( HTTP_NOT_FOUND == getStatus() ) { - LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL; - - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); + LL_DEBUGS("FacebookConnect") << "Not connected. " << dumpResponse() << LL_ENDL; + if (mAutoConnect) + { + LLFacebookConnect::instance().connectToFacebook(); + } + else + { + LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); + } } else { - // show the facebook login page if not connected yet - if (status == 404) - { - if (mAutoConnect) - { - LLFacebookConnect::instance().connectToFacebook(); - } - else - { - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); - } - } - else - { - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); - log_facebook_connect_error("Connected", status, reason, content.get("error_code"), content.get("error_description")); - } + LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; + LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); + const LLSD& content = getContent(); + log_facebook_connect_error("Connected", getStatus(), getReason(), + content.get("error_code"), content.get("error_description")); } } @@ -271,25 +291,27 @@ class LLFacebookInfoResponder : public LLHTTPClient::Responder LOG_CLASS(LLFacebookInfoResponder); public: - virtual void completed(U32 status, const std::string& reason, const LLSD& info) + /* virtual */ void httpSuccess() + { + LL_INFOS("FacebookConnect") << "Facebook: Info received" << LL_ENDL; + LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. " << dumpResponse() << LL_ENDL; + LLFacebookConnect::instance().storeInfo(getContent()); + } + + /* virtual */ void httpFailure() { - if (isGoodStatus(status)) + if ( HTTP_FOUND == getStatus() ) { LL_INFOS() << "Facebook: Info received" << LL_ENDL; - LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. info: " << info << LL_ENDL; - LLFacebookConnect::instance().storeInfo(info); + LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. info: " << getContent() << LL_ENDL; + LLFacebookConnect::instance().storeInfo(getContent()); } else { - log_facebook_connect_error("Info", status, reason, info.get("error_code"), info.get("error_description")); - } - } - - void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - if (status == 302) - { - LLFacebookConnect::instance().openFacebookWeb(content["location"]); + LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; + const LLSD& content = getContent(); + log_facebook_connect_error("Info", getStatus(), getReason(), + content.get("error_code"), content.get("error_description")); } } }; @@ -300,27 +322,36 @@ class LLFacebookFriendsResponder : public LLHTTPClient::Responder { LOG_CLASS(LLFacebookFriendsResponder); public: + + /* virtual */ void httpSuccess() + { + LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. " << dumpResponse() << LL_ENDL; + LLFacebookConnect::instance().storeContent(getContent()); + } - virtual void completed(U32 status, const std::string& reason, const LLSD& content) + /* virtual */ void httpFailure() { - if (isGoodStatus(status)) + if ( HTTP_FOUND == getStatus() ) { - LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. content: " << content << LL_ENDL; - LLFacebookConnect::instance().storeContent(content); + const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); + if (location.empty()) + { + LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() + << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; + } + else + { + LLFacebookConnect::instance().openFacebookWeb(location); + } } else { - log_facebook_connect_error("Friends", status, reason, content.get("error_code"), content.get("error_description")); + LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; + const LLSD& content = getContent(); + log_facebook_connect_error("Friends", getStatus(), getReason(), + content.get("error_code"), content.get("error_description")); } } - - void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - if (status == 302) - { - LLFacebookConnect::instance().openFacebookWeb(content["location"]); - } - } }; /////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 8c3a4bb5c0..d0555477ea 100755 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -39,6 +39,7 @@ #include "llgl.h" #include "llappviewer.h" +#include "llbufferstream.h" #include "llhttpclient.h" #include "llnotificationsutil.h" #include "llviewercontrol.h" @@ -609,6 +610,7 @@ bool LLFeatureManager::parseGPUTable(std::string filename) // responder saves table into file class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLHTTPFeatureTableResponder); public: LLHTTPFeatureTableResponder(std::string filename) : @@ -617,11 +619,10 @@ public: } - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, + virtual void completedRaw(const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - if (isGoodStatus(status)) + if (isGoodStatus()) { // write to file @@ -640,7 +641,18 @@ public: out.close(); } } - + else + { + char body[1025]; + body[1024] = '\0'; + LLBufferStream istr(channels, buffer.get()); + istr.get(body,1024); + if (strlen(body) > 0) + { + mContent["body"] = body; + } + LL_WARNS() << dumpResponse() << LL_ENDL; + } } private: diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 4698f2da1a..a7f5cd9dac 100755 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -570,6 +570,7 @@ std::vector<std::string>* LLFilePicker::navOpenFilterProc(ELoadFilter filter) // allowedv->push_back("lsl"); allowedv->push_back("dic"); allowedv->push_back("xcu"); + allowedv->push_back("gif"); case FFLOAD_IMAGE: allowedv->push_back("jpg"); allowedv->push_back("jpeg"); @@ -661,7 +662,7 @@ bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena case FFSAVE_TGAPNG: type = "PNG"; creator = "prvw"; - extension = "png"; + extension = "png,tga"; break; case FFSAVE_BMP: type = "BMPf"; @@ -779,7 +780,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) if(filter == FFLOAD_ALL) // allow application bundles etc. to be traversed; important for DEV-16869, but generally useful { - mPickOptions &= F_NAV_SUPPORT; + mPickOptions |= F_NAV_SUPPORT; } if (blocking) @@ -1104,9 +1105,9 @@ static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) { GtkFileFilter *gfilter = gtk_file_filter_new(); gtk_file_filter_add_pattern(gfilter, "*.tga"); - gtk_file_filter_add_mime_type(gfilter, "image/jpeg"); - gtk_file_filter_add_mime_type(gfilter, "image/png"); - gtk_file_filter_add_mime_type(gfilter, "image/bmp"); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str()); std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; add_common_filters_to_gtkchooser(gfilter, picker, filtername); return filtername; @@ -1114,13 +1115,13 @@ static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) static std::string add_script_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, "text/plain", + return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, LLTrans::getString("script_files") + " (*.lsl)"); } static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, "text/plain", + return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); } @@ -1176,7 +1177,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename break; case FFSAVE_BMP: caption += add_simple_mime_filter_to_gtkchooser - (picker, "image/bmp", LLTrans::getString("bitmap_image_files") + " (*.bmp)"); + (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)"); suggest_ext = ".bmp"; break; case FFSAVE_PNG: @@ -1210,6 +1211,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename suggest_ext = ".raw"; break; case FFSAVE_J2C: + // *TODO: Should this be 'image/j2c' ? caption += add_simple_mime_filter_to_gtkchooser (picker, "images/jp2", LLTrans::getString("compressed_image_files") + " (*.j2c)"); diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm index 13757904e3..1438e4dc0a 100644 --- a/indra/newview/llfilepicker_mac.mm +++ b/indra/newview/llfilepicker_mac.mm @@ -107,7 +107,7 @@ std::string* doSaveDialog(const std::string* file, NSSavePanel *panel = [NSSavePanel savePanel]; NSString *extensionns = [NSString stringWithCString:extension->c_str() encoding:[NSString defaultCStringEncoding]]; - NSArray *fileType = [[NSArray alloc] initWithObjects:extensionns,nil]; + NSArray *fileType = [extensionns componentsSeparatedByString:@","]; //[panel setMessage:@"Save Image File"]; [panel setTreatsFilePackagesAsDirectories: ( flags & F_NAV_SUPPORT ) ]; diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index efaba1d7a4..15b94034bb 100755 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -76,14 +76,9 @@ class LLServerReleaseNotesURLFetcher : public LLHTTPClient::Responder { LOG_CLASS(LLServerReleaseNotesURLFetcher); public: - static void startFetch(); - /*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content); - /*virtual*/ void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); +private: + /* virtual */ void httpCompleted(); }; ///---------------------------------------------------------------------------- @@ -303,16 +298,15 @@ void LLServerReleaseNotesURLFetcher::startFetch() } // virtual -void LLServerReleaseNotesURLFetcher::completedHeader(U32 status, const std::string& reason, const LLSD& content) +void LLServerReleaseNotesURLFetcher::httpCompleted() { - LL_DEBUGS() << "Status: " << status << LL_ENDL; - LL_DEBUGS() << "Reason: " << reason << LL_ENDL; - LL_DEBUGS() << "Headers: " << content << LL_ENDL; + LL_DEBUGS("ServerReleaseNotes") << dumpResponse() + << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; LLFloaterAbout* floater_about = LLFloaterReg::getTypedInstance<LLFloaterAbout>("sl_about"); if (floater_about) { - std::string location = content["location"].asString(); + std::string location = getResponseHeader(HTTP_IN_HEADER_LOCATION); if (location.empty()) { location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL"); @@ -321,14 +315,3 @@ void LLServerReleaseNotesURLFetcher::completedHeader(U32 status, const std::stri } } -// virtual -void LLServerReleaseNotesURLFetcher::completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) -{ - // Do nothing. - // We're overriding just because the base implementation tries to - // deserialize LLSD which triggers warnings. -} diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index c1e6673406..3e032d0e4a 100755 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -458,13 +458,15 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const class LLAvatarPickerResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLAvatarPickerResponder); public: LLUUID mQueryID; std::string mName; LLAvatarPickerResponder(const LLUUID& id, const std::string& name) : mQueryID(id), mName(name) { } - /*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content) +protected: + /*virtual*/ void httpCompleted() { //std::ostringstream ss; //LLSDSerialize::toPrettyXML(content, ss); @@ -472,19 +474,18 @@ public: // in case of invalid characters, the avatar picker returns a 400 // just set it to process so it displays 'not found' - if (isGoodStatus(status) || status == 400) + if (isGoodStatus() || getStatus() == HTTP_BAD_REQUEST) { LLFloaterAvatarPicker* floater = LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", mName); if (floater) { - floater->processResponse(mQueryID, content); + floater->processResponse(mQueryID, getContent()); } } else { - LL_WARNS() << "avatar picker failed [status:" << status << "]: " << content << LL_ENDL; - + LL_WARNS() << "avatar picker failed " << dumpResponse() << LL_ENDL; } } }; diff --git a/indra/newview/llfloaterbuycurrencyhtml.cpp b/indra/newview/llfloaterbuycurrencyhtml.cpp index 0c408f556d..a69aa8d227 100755 --- a/indra/newview/llfloaterbuycurrencyhtml.cpp +++ b/indra/newview/llfloaterbuycurrencyhtml.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llfloaterbuycurrencyhtml.h" +#include "llhttpconstants.h" #include "llstatusbar.h" //////////////////////////////////////////////////////////////////////////////// @@ -85,7 +86,7 @@ void LLFloaterBuyCurrencyHTML::navigateToFinalURL() LL_INFOS() << "Buy currency HTML parsed URL is " << buy_currency_url << LL_ENDL; // kick off the navigation - mBrowser->navigateTo( buy_currency_url, "text/html" ); + mBrowser->navigateTo( buy_currency_url, HTTP_CONTENT_TEXT_HTML ); } //////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp index a303c2c6b3..a358b7c10b 100755 --- a/indra/newview/llfloaterconversationpreview.cpp +++ b/indra/newview/llfloaterconversationpreview.cpp @@ -32,6 +32,7 @@ #include "llfloaterimnearbychat.h" #include "llspinctrl.h" #include "lltrans.h" +#include "llnotificationsutil.h" const std::string LL_FCP_COMPLETE_NAME("complete_name"); const std::string LL_FCP_ACCOUNT_NAME("user_name"); @@ -45,14 +46,20 @@ LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_i mAccountName(session_id[LL_FCP_ACCOUNT_NAME]), mCompleteName(session_id[LL_FCP_COMPLETE_NAME]), mMutex(NULL), - mShowHistory(false) + mShowHistory(false), + mMessages(NULL), + mHistoryThreadsBusy(false), + mOpened(false) +{ +} + +LLFloaterConversationPreview::~LLFloaterConversationPreview() { } BOOL LLFloaterConversationPreview::postBuild() { mChatHistory = getChild<LLChatHistory>("chat_history"); - LLLoadHistoryThread::setLoadEndSignal(boost::bind(&LLFloaterConversationPreview::setPages, this, _1, _2)); const LLConversation* conv = LLConversationLog::instance().getConversation(mSessionID); std::string name; @@ -79,31 +86,21 @@ BOOL LLFloaterConversationPreview::postBuild() std::string title = getString("Title", args); setTitle(title); - LLSD load_params; - load_params["load_all_history"] = true; - load_params["cut_off_todays_date"] = false; - - - LLSD loading; - loading[LL_IM_TEXT] = LLTrans::getString("loading_chat_logs"); - mMessages.push_back(loading); - mPageSpinner = getChild<LLSpinCtrl>("history_page_spin"); - mPageSpinner->setCommitCallback(boost::bind(&LLFloaterConversationPreview::onMoreHistoryBtnClick, this)); - mPageSpinner->setMinValue(1); - mPageSpinner->set(1); - mPageSpinner->setEnabled(false); - LLLogChat::startChatHistoryThread(file, load_params); return LLFloater::postBuild(); } -void LLFloaterConversationPreview::setPages(std::list<LLSD>& messages,const std::string& file_name) +void LLFloaterConversationPreview::setPages(std::list<LLSD>* messages, const std::string& file_name) { - if(file_name == mChatHistoryFileName) + if(file_name == mChatHistoryFileName && messages) { // additional protection to avoid changes of mMessages in setPages() LLMutexLock lock(&mMutex); + if (mMessages) + { + delete mMessages; // Clean up temporary message list with "Loading..." text + } mMessages = messages; - mCurrentPage = (mMessages.size() ? (mMessages.size() - 1) / mPageSize : 0); + mCurrentPage = (mMessages->size() ? (mMessages->size() - 1) / mPageSize : 0); mPageSpinner->setEnabled(true); mPageSpinner->setMaxValue(mCurrentPage+1); @@ -113,6 +110,11 @@ void LLFloaterConversationPreview::setPages(std::list<LLSD>& messages,const std: getChild<LLTextBox>("page_num_label")->setValue(total_page_num); mShowHistory = true; } + LLLoadHistoryThread* loadThread = LLLogChat::getLoadHistoryThread(mSessionID); + if (loadThread) + { + loadThread->removeLoadEndSignal(boost::bind(&LLFloaterConversationPreview::setPages, this, _1, _2)); + } } void LLFloaterConversationPreview::draw() @@ -127,24 +129,82 @@ void LLFloaterConversationPreview::draw() void LLFloaterConversationPreview::onOpen(const LLSD& key) { + if (mOpened) + { + return; + } + mOpened = true; + if (!LLLogChat::historyThreadsFinished(mSessionID)) + { + LLNotificationsUtil::add("ChatHistoryIsBusyAlert"); + mHistoryThreadsBusy = true; + closeFloater(); + return; + } + LLSD load_params; + load_params["load_all_history"] = true; + load_params["cut_off_todays_date"] = false; + + // The temporary message list with "Loading..." text + // Will be deleted upon loading completion in setPages() method + mMessages = new std::list<LLSD>(); + + + LLSD loading; + loading[LL_IM_TEXT] = LLTrans::getString("loading_chat_logs"); + mMessages->push_back(loading); + mPageSpinner = getChild<LLSpinCtrl>("history_page_spin"); + mPageSpinner->setCommitCallback(boost::bind(&LLFloaterConversationPreview::onMoreHistoryBtnClick, this)); + mPageSpinner->setMinValue(1); + mPageSpinner->set(1); + mPageSpinner->setEnabled(false); + + // The actual message list to load from file + // Will be deleted in a separate thread LLDeleteHistoryThread not to freeze UI + // LLDeleteHistoryThread is started in destructor + std::list<LLSD>* messages = new std::list<LLSD>(); + + LLLogChat::cleanupHistoryThreads(); + + LLLoadHistoryThread* loadThread = new LLLoadHistoryThread(mChatHistoryFileName, messages, load_params); + loadThread->setLoadEndSignal(boost::bind(&LLFloaterConversationPreview::setPages, this, _1, _2)); + loadThread->start(); + LLLogChat::addLoadHistoryThread(mSessionID, loadThread); + + LLDeleteHistoryThread* deleteThread = new LLDeleteHistoryThread(messages, loadThread); + LLLogChat::addDeleteHistoryThread(mSessionID, deleteThread); + mShowHistory = true; } +void LLFloaterConversationPreview::onClose(bool app_quitting) +{ + mOpened = false; + if (!mHistoryThreadsBusy) + { + LLDeleteHistoryThread* deleteThread = LLLogChat::getDeleteHistoryThread(mSessionID); + if (deleteThread) + { + deleteThread->start(); + } + } +} + void LLFloaterConversationPreview::showHistory() { // additional protection to avoid changes of mMessages in setPages LLMutexLock lock(&mMutex); - if (!mMessages.size() || mCurrentPage * mPageSize >= mMessages.size()) + if(mMessages == NULL || !mMessages->size() || mCurrentPage * mPageSize >= mMessages->size()) { return; } mChatHistory->clear(); std::ostringstream message; - std::list<LLSD>::const_iterator iter = mMessages.begin(); + std::list<LLSD>::const_iterator iter = mMessages->begin(); std::advance(iter, mCurrentPage * mPageSize); - for (int msg_num = 0; iter != mMessages.end() && msg_num < mPageSize; ++iter, ++msg_num) + for (int msg_num = 0; iter != mMessages->end() && msg_num < mPageSize; ++iter, ++msg_num) { LLSD msg = *iter; diff --git a/indra/newview/llfloaterconversationpreview.h b/indra/newview/llfloaterconversationpreview.h index b0488f4ff1..a8dbbc9ffe 100755 --- a/indra/newview/llfloaterconversationpreview.h +++ b/indra/newview/llfloaterconversationpreview.h @@ -39,13 +39,14 @@ class LLFloaterConversationPreview : public LLFloater public: LLFloaterConversationPreview(const LLSD& session_id); - virtual ~LLFloaterConversationPreview(){}; + virtual ~LLFloaterConversationPreview(); virtual BOOL postBuild(); - void setPages(std::list<LLSD>& messages,const std::string& file_name); + void setPages(std::list<LLSD>* messages,const std::string& file_name); virtual void draw(); virtual void onOpen(const LLSD& key); + virtual void onClose(bool app_quitting); private: void onMoreHistoryBtnClick(); @@ -58,11 +59,13 @@ private: int mCurrentPage; int mPageSize; - std::list<LLSD> mMessages; + std::list<LLSD>* mMessages; std::string mAccountName; std::string mCompleteName; - std::string mChatHistoryFileName; + std::string mChatHistoryFileName; bool mShowHistory; + bool mHistoryThreadsBusy; + bool mOpened; }; #endif /* LLFLOATERCONVERSATIONPREVIEW_H_ */ diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 1452d53265..9797b5c062 100755 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -617,9 +617,10 @@ void LLFloaterGesture::addToCurrentOutFit() uuid_vec_t ids; getSelectedIds(ids); LLAppearanceMgr* am = LLAppearanceMgr::getInstance(); + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; for(uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); it++) { - am->addCOFItemLink(*it); + am->addCOFItemLink(*it, cb); } } diff --git a/indra/newview/llfloatergroupbulkban.cpp b/indra/newview/llfloatergroupbulkban.cpp new file mode 100644 index 0000000000..54a2283b13 --- /dev/null +++ b/indra/newview/llfloatergroupbulkban.cpp @@ -0,0 +1,134 @@ +/** +* @file llfloatergroupbulkban.cpp +* @brief Floater to ban Residents from a group. +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, 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 "llfloatergroupbulkban.h" +#include "llpanelgroupbulkban.h" +#include "lltrans.h" +#include "lldraghandle.h" + + +class LLFloaterGroupBulkBan::impl +{ +public: + impl(const LLUUID& group_id) : mGroupID(group_id), mBulkBanPanelp(NULL) {} + ~impl() {} + + static void closeFloater(void* data); + +public: + LLUUID mGroupID; + LLPanelGroupBulkBan* mBulkBanPanelp; + + static std::map<LLUUID, LLFloaterGroupBulkBan*> sInstances; +}; + +// +// Globals +// +std::map<LLUUID, LLFloaterGroupBulkBan*> LLFloaterGroupBulkBan::impl::sInstances; + +void LLFloaterGroupBulkBan::impl::closeFloater(void* data) +{ + LLFloaterGroupBulkBan* floaterp = (LLFloaterGroupBulkBan*)data; + if(floaterp) + floaterp->closeFloater(); +} + +//----------------------------------------------------------------------------- +// Implementation +//----------------------------------------------------------------------------- +LLFloaterGroupBulkBan::LLFloaterGroupBulkBan(const LLUUID& group_id/*=LLUUID::null*/) + : LLFloater(group_id) +{ + S32 floater_header_size = getHeaderHeight(); + LLRect contents; + + mImpl = new impl(group_id); + mImpl->mBulkBanPanelp = new LLPanelGroupBulkBan(group_id); + + contents = mImpl->mBulkBanPanelp->getRect(); + contents.mTop -= floater_header_size; + + setTitle(mImpl->mBulkBanPanelp->getString("GroupBulkBan")); + mImpl->mBulkBanPanelp->setCloseCallback(impl::closeFloater, this); + mImpl->mBulkBanPanelp->setRect(contents); + + addChild(mImpl->mBulkBanPanelp); +} + +LLFloaterGroupBulkBan::~LLFloaterGroupBulkBan() +{ + if(mImpl->mGroupID.notNull()) + { + impl::sInstances.erase(mImpl->mGroupID); + } + + delete mImpl->mBulkBanPanelp; + delete mImpl; +} + +void LLFloaterGroupBulkBan::showForGroup(const LLUUID& group_id, uuid_vec_t* agent_ids) +{ + const LLFloater::Params& floater_params = LLFloater::getDefaultParams(); + S32 floater_header_size = floater_params.header_height; + LLRect contents; + + // Make sure group_id isn't null + if (group_id.isNull()) + { + llwarns << "LLFloaterGroupInvite::showForGroup with null group_id!" << llendl; + return; + } + + // If we don't have a floater for this group, create one. + LLFloaterGroupBulkBan* fgb = get_if_there(impl::sInstances, + group_id, + (LLFloaterGroupBulkBan*)NULL); + if (!fgb) + { + fgb = new LLFloaterGroupBulkBan(group_id); + contents = fgb->mImpl->mBulkBanPanelp->getRect(); + contents.mTop += floater_header_size; + fgb->setRect(contents); + fgb->getDragHandle()->setRect(contents); + fgb->getDragHandle()->setTitle(fgb->mImpl->mBulkBanPanelp->getString("GroupBulkBan")); + + impl::sInstances[group_id] = fgb; + + fgb->mImpl->mBulkBanPanelp->clear(); + } + + if (agent_ids != NULL) + { + fgb->mImpl->mBulkBanPanelp->addUsers(*agent_ids); + } + + fgb->center(); + fgb->openFloater(); + fgb->mImpl->mBulkBanPanelp->update(); +} diff --git a/indra/newview/llfloatergroupbulkban.h b/indra/newview/llfloatergroupbulkban.h new file mode 100644 index 0000000000..5b680a1ba4 --- /dev/null +++ b/indra/newview/llfloatergroupbulkban.h @@ -0,0 +1,48 @@ +/** +* @file llfloatergroupbulkban.h +* @brief This floater is a wrapper for LLPanelGroupBulkBan, which +* is used to ban Residents from a specific group. +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, 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_LLFLOATERGROUPBULKBAN_H +#define LL_LLFLOATERGROUPBULKBAN_H + +#include "llfloater.h" +#include "lluuid.h" + +class LLFloaterGroupBulkBan : public LLFloater +{ +public: + virtual ~LLFloaterGroupBulkBan(); + + static void showForGroup(const LLUUID& group_id, uuid_vec_t* agent_ids = NULL); + +protected: + LLFloaterGroupBulkBan(const LLUUID& group_id = LLUUID::null); + + class impl; + impl* mImpl; +}; + +#endif // LL_LLFLOATERGROUPBULKBAN_H diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp index 4cb632bd6a..c0bb213540 100755 --- a/indra/newview/llfloaterhelpbrowser.cpp +++ b/indra/newview/llfloaterhelpbrowser.cpp @@ -29,6 +29,7 @@ #include "llfloaterhelpbrowser.h" #include "llfloaterreg.h" +#include "llhttpconstants.h" #include "llpluginclassmedia.h" #include "llmediactrl.h" #include "llviewerwindow.h" @@ -37,7 +38,6 @@ #include "llui.h" #include "llurlhistory.h" -#include "llmediactrl.h" #include "llviewermedia.h" #include "llviewerhelp.h" @@ -148,7 +148,7 @@ void LLFloaterHelpBrowser::openMedia(const std::string& media_url) { // explicitly make the media mime type for this floater since it will // only ever display one type of content (Web). - mBrowser->setHomePageUrl(media_url, "text/html"); - mBrowser->navigateTo(media_url, "text/html"); + mBrowser->setHomePageUrl(media_url, HTTP_CONTENT_TEXT_HTML); + mBrowser->navigateTo(media_url, HTTP_CONTENT_TEXT_HTML); setCurrentURL(media_url); } diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index bb39a54f76..ebb44561da 100755 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -1318,7 +1318,12 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v // Extract the single select info bool is_single_select = (uuids.size() == 1); const LLUUID& single_id = uuids.front(); - + + if ("can_chat_history" == item && is_single_select) + { + return LLLogChat::isTranscriptExist(uuids.front(),false); + } + // Handle options that are applicable to all including the user agent if ("can_view_profile" == item) { diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index ec506d1c7e..7852a1f7b3 100644..100755 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -716,7 +716,7 @@ void LLFloaterIMSession::setVisible(BOOL visible) if (visible && isInVisibleChain()) { sIMFloaterShowedSignal(mSessionID); - + updateMessages(); } } @@ -1181,16 +1181,17 @@ BOOL LLFloaterIMSession::isInviteAllowed() const class LLSessionInviteResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLSessionInviteResponder); public: LLSessionInviteResponder(const LLUUID& session_id) { mSessionID = session_id; } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +protected: + void httpFailure() { - LL_WARNS() << "Error inviting all agents to session [status:" - << statusNum << "]: " << content << LL_ENDL; + LL_WARNS() << "Error inviting all agents to session " << dumpResponse() << LL_ENDL; //throw something back to the viewer here? } diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index e30bff1edf..7213064746 100755 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -2336,7 +2336,7 @@ BOOL LLPanelLandAccess::postBuild() childSetCommitCallback("public_access", onCommitPublicAccess, this); childSetCommitCallback("limit_payment", onCommitAny, this); childSetCommitCallback("limit_age_verified", onCommitAny, this); - childSetCommitCallback("GroupCheck", onCommitAny, this); + childSetCommitCallback("GroupCheck", onCommitGroupCheck, this); childSetCommitCallback("PassCheck", onCommitAny, this); childSetCommitCallback("pass_combo", onCommitAny, this); childSetCommitCallback("PriceSpin", onCommitAny, this); @@ -2501,11 +2501,11 @@ void LLPanelLandAccess::refresh() } BOOL use_pass = parcel->getParcelFlag(PF_USE_PASS_LIST); - getChild<LLUICtrl>("PassCheck")->setValue(use_pass ); + getChild<LLUICtrl>("PassCheck")->setValue(use_pass); LLCtrlSelectionInterface* passcombo = childGetSelectionInterface("pass_combo"); if (passcombo) { - if (public_access || !use_pass || !use_group) + if (public_access || !use_pass) { passcombo->selectByValue("anyone"); } @@ -2598,12 +2598,11 @@ void LLPanelLandAccess::refresh_ui() getChildView("limit_age_verified")->setEnabled(FALSE); - BOOL group_access = getChild<LLUICtrl>("GroupCheck")->getValue().asBoolean(); BOOL sell_passes = getChild<LLUICtrl>("PassCheck")->getValue().asBoolean(); getChildView("PassCheck")->setEnabled(can_manage_allowed); if (sell_passes) { - getChildView("pass_combo")->setEnabled(group_access && can_manage_allowed); + getChildView("pass_combo")->setEnabled(can_manage_allowed); getChildView("PriceSpin")->setEnabled(can_manage_allowed); getChildView("HoursSpin")->setEnabled(can_manage_allowed); } @@ -2662,6 +2661,32 @@ void LLPanelLandAccess::onCommitPublicAccess(LLUICtrl *ctrl, void *userdata) onCommitAny(ctrl, userdata); } +void LLPanelLandAccess::onCommitGroupCheck(LLUICtrl *ctrl, void *userdata) +{ + LLPanelLandAccess *self = (LLPanelLandAccess *)userdata; + LLParcel* parcel = self->mParcel->getParcel(); + if (!parcel) + { + return; + } + + BOOL use_pass_list = !self->getChild<LLUICtrl>("public_access")->getValue().asBoolean(); + BOOL use_access_group = self->getChild<LLUICtrl>("GroupCheck")->getValue().asBoolean(); + LLCtrlSelectionInterface* passcombo = self->childGetSelectionInterface("pass_combo"); + if (passcombo) + { + if (use_access_group && use_pass_list) + { + if (passcombo->getSelectedValue().asString() == "group") + { + passcombo->selectByValue("anyone"); + } + } + } + + onCommitAny(ctrl, userdata); +} + // static void LLPanelLandAccess::onCommitAny(LLUICtrl *ctrl, void *userdata) { @@ -2699,14 +2724,14 @@ void LLPanelLandAccess::onCommitAny(LLUICtrl *ctrl, void *userdata) { use_access_list = TRUE; use_pass_list = self->getChild<LLUICtrl>("PassCheck")->getValue().asBoolean(); - if (use_access_group && use_pass_list) + LLCtrlSelectionInterface* passcombo = self->childGetSelectionInterface("pass_combo"); + if (passcombo) { - LLCtrlSelectionInterface* passcombo = self->childGetSelectionInterface("pass_combo"); - if (passcombo) + if (use_access_group && use_pass_list) { if (passcombo->getSelectedValue().asString() == "group") { - use_access_list = FALSE; + use_access_group = FALSE; } } } diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h index dccdfc9acb..1d9bd33720 100755 --- a/indra/newview/llfloaterland.h +++ b/indra/newview/llfloaterland.h @@ -366,6 +366,7 @@ public: static void onCommitPublicAccess(LLUICtrl* ctrl, void *userdata); static void onCommitAny(LLUICtrl* ctrl, void *userdata); + static void onCommitGroupCheck(LLUICtrl* ctrl, void *userdata); static void onClickRemoveAccess(void*); static void onClickRemoveBanned(void*); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 12c1a68ccd..b17ce97a2e 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -5861,7 +5861,7 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived() mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty()); } -void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) +void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) { LL_WARNS() << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << LL_ENDL; doOnIdleOneTime(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, true)); @@ -5937,7 +5937,7 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result) getChild<LLTextBox>("warning_message")->setVisible(!mHasUploadPerm); } -void LLFloaterModelPreview::setPermissonsErrorStatus(U32 status, const std::string& reason) +void LLFloaterModelPreview::setPermissonsErrorStatus(S32 status, const std::string& reason) { LL_WARNS() << "LLFloaterModelPreview::setPermissonsErrorStatus(" << status << " : " << reason << ")" << LL_ENDL; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index e588418f7b..6c0c60b87f 100755 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -200,11 +200,11 @@ public: /*virtual*/ void onPermissionsReceived(const LLSD& result); // called when error occurs during permissions request - /*virtual*/ void setPermissonsErrorStatus(U32 status, const std::string& reason); + /*virtual*/ void setPermissonsErrorStatus(S32 status, const std::string& reason); /*virtual*/ void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url); void handleModelPhysicsFeeReceived(); - /*virtual*/ void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason); + /*virtual*/ void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason); /*virtual*/ void onModelUploadSuccess(); diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp index 2ad2d32652..22a8ac4705 100755 --- a/indra/newview/llfloatermodeluploadbase.cpp +++ b/indra/newview/llfloatermodeluploadbase.cpp @@ -44,8 +44,10 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions() if (!url.empty()) { - LL_INFOS()<< typeid(*this).name() <<"::requestAgentUploadPermissions() requesting for upload model permissions from: "<< url <<LL_ENDL; - LLHTTPClient::get(url, new LLUploadModelPremissionsResponder(getPermObserverHandle())); + LL_INFOS()<< typeid(*this).name() + << "::requestAgentUploadPermissions() requesting for upload model permissions from: " + << url << LL_ENDL; + LLHTTPClient::get(url, new LLUploadModelPermissionsResponder(getPermObserverHandle())); } else { diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h index a52bc28687..d9a8879687 100755 --- a/indra/newview/llfloatermodeluploadbase.h +++ b/indra/newview/llfloatermodeluploadbase.h @@ -37,13 +37,13 @@ public: virtual ~LLFloaterModelUploadBase(){}; - virtual void setPermissonsErrorStatus(U32 status, const std::string& reason) = 0; + virtual void setPermissonsErrorStatus(S32 status, const std::string& reason) = 0; virtual void onPermissionsReceived(const LLSD& result) = 0; virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; - virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0; + virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0; virtual void onModelUploadSuccess() {}; diff --git a/indra/newview/llfloaterobjectweights.cpp b/indra/newview/llfloaterobjectweights.cpp index 94bf8974bb..feaeef4ad0 100755 --- a/indra/newview/llfloaterobjectweights.cpp +++ b/indra/newview/llfloaterobjectweights.cpp @@ -123,7 +123,7 @@ void LLFloaterObjectWeights::onWeightsUpdate(const SelectionCost& selection_cost } //virtual -void LLFloaterObjectWeights::setErrorStatus(U32 status, const std::string& reason) +void LLFloaterObjectWeights::setErrorStatus(S32 status, const std::string& reason) { const std::string text = getString("nothing_selected"); diff --git a/indra/newview/llfloaterobjectweights.h b/indra/newview/llfloaterobjectweights.h index 9a244573be..1a2c317bad 100755 --- a/indra/newview/llfloaterobjectweights.h +++ b/indra/newview/llfloaterobjectweights.h @@ -63,7 +63,7 @@ public: /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ void onWeightsUpdate(const SelectionCost& selection_cost); - /*virtual*/ void setErrorStatus(U32 status, const std::string& reason); + /*virtual*/ void setErrorStatus(S32 status, const std::string& reason); void updateLandImpacts(const LLParcel* parcel); void refresh(); diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index 4bfef8b45f..9986bdbd7f 100755 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -162,21 +162,17 @@ void LLFloaterOpenObject::moveToInventory(bool wear) { parent_category_id = gInventory.getRootFolderID(); } - - LLCategoryCreate* cat_data = new LLCategoryCreate(object_id, wear); - + + inventory_func_type func = boost::bind(LLFloaterOpenObject::callbackCreateInventoryCategory,_1,object_id,wear); LLUUID category_id = gInventory.createNewCategory(parent_category_id, LLFolderType::FT_NONE, name, - callbackCreateInventoryCategory, - (void*)cat_data); + func); //If we get a null category ID, we are using a capability in createNewCategory and we will //handle the following in the callbackCreateInventoryCategory routine. if ( category_id.notNull() ) { - delete cat_data; - LLCatAndWear* data = new LLCatAndWear; data->mCatID = category_id; data->mWear = wear; @@ -198,20 +194,17 @@ void LLFloaterOpenObject::moveToInventory(bool wear) } // static -void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLSD& result, void* data) +void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear) { - LLCategoryCreate* cat_data = (LLCategoryCreate*)data; - - LLUUID category_id = result["folder_id"].asUUID(); LLCatAndWear* wear_data = new LLCatAndWear; wear_data->mCatID = category_id; - wear_data->mWear = cat_data->mWear; + wear_data->mWear = wear; wear_data->mFolderResponded = true; // Copy and/or move the items into the newly created folder. // Ignore any "you're going to break this item" messages. - BOOL success = move_inv_category_world_to_agent(cat_data->mObjectID, category_id, TRUE, + BOOL success = move_inv_category_world_to_agent(object_id, category_id, TRUE, callbackMoveInventory, (void*)wear_data); if (!success) @@ -221,7 +214,6 @@ void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLSD& result, vo LLNotificationsUtil::add("OpenObjectCannotCopy"); } - delete cat_data; } // static diff --git a/indra/newview/llfloateropenobject.h b/indra/newview/llfloateropenobject.h index bf7fe69c65..8e472804a4 100755 --- a/indra/newview/llfloateropenobject.h +++ b/indra/newview/llfloateropenobject.h @@ -45,15 +45,6 @@ public: void dirty(); - class LLCategoryCreate - { - public: - LLCategoryCreate(LLUUID object_id, bool wear) : mObjectID(object_id), mWear(wear) {} - public: - LLUUID mObjectID; - bool mWear; - }; - struct LLCatAndWear { LLUUID mCatID; @@ -72,7 +63,7 @@ protected: void onClickMoveToInventory(); void onClickMoveAndWear(); - static void callbackCreateInventoryCategory(const LLSD& result, void* data); + static void callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear); static void callbackMoveInventory(S32 result, void* data); private: diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp index bed34abee8..40757a4d04 100755 --- a/indra/newview/llfloaterregiondebugconsole.cpp +++ b/indra/newview/llfloaterregiondebugconsole.cpp @@ -73,24 +73,29 @@ namespace // called if this request times out. class AsyncConsoleResponder : public LLHTTPClient::Responder { - public: + LOG_CLASS(AsyncConsoleResponder); + protected: /* virtual */ - void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + void httpFailure() { + LL_WARNS("Console") << dumpResponse() << LL_ENDL; sConsoleReplySignal(UNABLE_TO_SEND_COMMAND); } }; class ConsoleResponder : public LLHTTPClient::Responder { + LOG_CLASS(ConsoleResponder); public: ConsoleResponder(LLTextEditor *output) : mOutput(output) { } + protected: /*virtual*/ - void error(U32 status, const std::string& reason) + void httpFailure() { + LL_WARNS("Console") << dumpResponse() << LL_ENDL; if (mOutput) { mOutput->appendText( @@ -100,8 +105,10 @@ namespace } /*virtual*/ - void result(const LLSD& content) + void httpSuccess() { + const LLSD& content = getContent(); + LL_DEBUGS("Console") << content << LL_ENDL; if (mOutput) { mOutput->appendText( @@ -109,6 +116,7 @@ namespace } } + public: LLTextEditor * mOutput; }; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 8d1114e056..5e9b25b474 100755 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -366,6 +366,7 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) panel->getChild<LLUICtrl>("block_terraform_check")->setValue((region_flags & REGION_FLAGS_BLOCK_TERRAFORM) ? TRUE : FALSE ); panel->getChild<LLUICtrl>("block_fly_check")->setValue((region_flags & REGION_FLAGS_BLOCK_FLY) ? TRUE : FALSE ); + panel->getChild<LLUICtrl>("block_fly_over_check")->setValue((region_flags & REGION_FLAGS_BLOCK_FLYOVER) ? TRUE : FALSE ); panel->getChild<LLUICtrl>("allow_damage_check")->setValue((region_flags & REGION_FLAGS_ALLOW_DAMAGE) ? TRUE : FALSE ); panel->getChild<LLUICtrl>("restrict_pushobject")->setValue((region_flags & REGION_FLAGS_RESTRICT_PUSHOBJECT) ? TRUE : FALSE ); panel->getChild<LLUICtrl>("allow_land_resell_check")->setValue((region_flags & REGION_FLAGS_BLOCK_LAND_RESELL) ? FALSE : TRUE ); @@ -635,6 +636,7 @@ BOOL LLPanelRegionGeneralInfo::postBuild() // Enable the "Apply" button if something is changed. JC initCtrl("block_terraform_check"); initCtrl("block_fly_check"); + initCtrl("block_fly_over_check"); initCtrl("allow_damage_check"); initCtrl("allow_land_resell_check"); initCtrl("allow_parcel_changes_check"); @@ -757,12 +759,12 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L class ConsoleRequestResponder : public LLHTTPClient::Responder { -public: + LOG_CLASS(ConsoleRequestResponder); +protected: /*virtual*/ - void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + void httpFailure() { - LL_WARNS() << "ConsoleRequestResponder error requesting mesh_rez_enabled [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS() << "error requesting mesh_rez_enabled " << dumpResponse() << LL_ENDL; } }; @@ -770,12 +772,12 @@ public: // called if this request times out. class ConsoleUpdateResponder : public LLHTTPClient::Responder { -public: + LOG_CLASS(ConsoleUpdateResponder); +protected: /* virtual */ - void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + void httpFailure() { - LL_WARNS() << "ConsoleRequestResponder error updating mesh enabled region setting [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS() << "error updating mesh enabled region setting " << dumpResponse() << LL_ENDL; } }; @@ -816,6 +818,7 @@ BOOL LLPanelRegionGeneralInfo::sendUpdate() { body["block_terraform"] = getChild<LLUICtrl>("block_terraform_check")->getValue(); body["block_fly"] = getChild<LLUICtrl>("block_fly_check")->getValue(); + body["block_fly_over"] = getChild<LLUICtrl>("block_fly_over_check")->getValue(); body["allow_damage"] = getChild<LLUICtrl>("allow_damage_check")->getValue(); body["allow_land_resell"] = getChild<LLUICtrl>("allow_land_resell_check")->getValue(); body["agent_limit"] = getChild<LLUICtrl>("agent_limit_spin")->getValue(); @@ -891,6 +894,7 @@ BOOL LLPanelRegionDebugInfo::postBuild() childSetAction("top_scripts_btn", onClickTopScripts, this); childSetAction("restart_btn", onClickRestart, this); childSetAction("cancel_restart_btn", onClickCancelRestart, this); + childSetAction("region_debug_console_btn", onClickDebugConsole, this); return TRUE; } @@ -912,6 +916,7 @@ bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region) getChildView("top_scripts_btn")->setEnabled(allow_modify); getChildView("restart_btn")->setEnabled(allow_modify); getChildView("cancel_restart_btn")->setEnabled(allow_modify); + getChildView("region_debug_console_btn")->setEnabled(allow_modify); return LLPanelRegionInfo::refreshFromRegion(region); } @@ -1074,6 +1079,11 @@ void LLPanelRegionDebugInfo::onClickCancelRestart(void* data) self->sendEstateOwnerMessage(gMessageSystem, "restart", invoice, strings); } +// static +void LLPanelRegionDebugInfo::onClickDebugConsole(void* data) +{ + LLFloaterReg::showInstance("region_debug_console"); +} BOOL LLPanelRegionTerrainInfo::validateTextureSizes() { @@ -2234,14 +2244,16 @@ void LLPanelEstateInfo::getEstateOwner() class LLEstateChangeInfoResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLEstateChangeInfoResponder); public: LLEstateChangeInfoResponder(LLPanelEstateInfo* panel) { mpPanel = panel->getHandle(); } +protected: // if we get a normal response, handle it here - virtual void result(const LLSD& content) + virtual void httpSuccess() { LL_INFOS("Windlight") << "Successfully committed estate info" << LL_ENDL; @@ -2252,10 +2264,9 @@ public: } // if we get an error response - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + virtual void httpFailure() { - LL_INFOS() << "LLEstateChangeInfoResponder::error [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS("Windlight") << dumpResponse() << LL_ENDL; } private: LLHandle<LLPanel> mpPanel; diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index dd961e21b2..5bc4273d5f 100755 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -209,6 +209,7 @@ protected: static void onClickRestart(void* data); bool callbackRestart(const LLSD& notification, const LLSD& response); static void onClickCancelRestart(void* data); + static void onClickDebugConsole(void* data); private: LLUUID mTargetAvatar; diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 825159703c..a3b9713e3e 100755 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -707,16 +707,18 @@ public: class LLUserReportResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLUserReportResponder); public: LLUserReportResponder(): LLHTTPClient::Responder() {} - void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - { - // *TODO do some user messaging here - LLUploadDialog::modalUploadFinished(); - } - void result(const LLSD& content) +private: + void httpCompleted() { + if (!isGoodStatus()) + { + // *TODO do some user messaging here + LL_WARNS("UserReport") << dumpResponse() << LL_ENDL; + } // we don't care about what the server returns LLUploadDialog::modalUploadFinished(); } diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 2ed7bb842d..5fbdd75e97 100755 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -183,8 +183,14 @@ void LLPanelScriptLimitsInfo::updateChild(LLUICtrl* child_ctr) // Responders ///---------------------------------------------------------------------------- -void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content) +void fetchScriptLimitsRegionInfoResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } //we don't need to test with a fake respose here (shouldn't anyway) #ifdef DUMP_REPLIES_TO_LLINFOS @@ -221,13 +227,14 @@ void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content) } } -void fetchScriptLimitsRegionInfoResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsRegionInfoResponder::httpFailure() { - LL_WARNS() << "fetchScriptLimitsRegionInfoResponder error [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; } -void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) +void fetchScriptLimitsRegionSummaryResponder::httpSuccess() { + const LLSD& content_ref = getContent(); #ifdef USE_FAKE_RESPONSES LLSD fake_content; @@ -268,6 +275,12 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) #endif + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + #ifdef DUMP_REPLIES_TO_LLINFOS @@ -291,7 +304,7 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); if(tab) { - LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); + LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); if(panel_memory) { panel_memory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string(""))); @@ -301,20 +314,21 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) { btn->setEnabled(true); } - - panel_memory->setRegionSummary(content); - } -} + + panel_memory->setRegionSummary(content); + } + } } } -void fetchScriptLimitsRegionSummaryResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsRegionSummaryResponder::httpFailure() { - LL_WARNS() << "fetchScriptLimitsRegionSummaryResponder error [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; } -void fetchScriptLimitsRegionDetailsResponder::result(const LLSD& content_ref) +void fetchScriptLimitsRegionDetailsResponder::httpSuccess() { + const LLSD& content_ref = getContent(); #ifdef USE_FAKE_RESPONSES /* Updated detail service, ** denotes field added: @@ -377,6 +391,12 @@ result (map) #endif + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + #ifdef DUMP_REPLIES_TO_LLINFOS LLSDNotationStreamer notation_streamer(content); @@ -417,13 +437,14 @@ result (map) } } -void fetchScriptLimitsRegionDetailsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsRegionDetailsResponder::httpFailure() { - LL_WARNS() << "fetchScriptLimitsRegionDetailsResponder error [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; } -void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) +void fetchScriptLimitsAttachmentInfoResponder::httpSuccess() { + const LLSD& content_ref = getContent(); #ifdef USE_FAKE_RESPONSES @@ -465,6 +486,12 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) #endif + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + #ifdef DUMP_REPLIES_TO_LLINFOS LLSDNotationStreamer notation_streamer(content); @@ -513,9 +540,9 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) } } -void fetchScriptLimitsAttachmentInfoResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsAttachmentInfoResponder::httpFailure() { - LL_WARNS() << "fetchScriptLimitsAttachmentInfoResponder error [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; } ///---------------------------------------------------------------------------- @@ -586,7 +613,7 @@ void LLPanelScriptLimitsRegionMemory::setParcelID(const LLUUID& parcel_id) } // virtual -void LLPanelScriptLimitsRegionMemory::setErrorStatus(U32 status, const std::string& reason) +void LLPanelScriptLimitsRegionMemory::setErrorStatus(S32 status, const std::string& reason) { LL_WARNS() << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<LL_ENDL; } diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h index f8732ef94b..a5cb1b6184 100755 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -85,49 +85,49 @@ protected: class fetchScriptLimitsRegionInfoResponder: public LLHTTPClient::Responder { - public: - fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {}; - - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - public: - protected: - LLSD mInfo; + LOG_CLASS(fetchScriptLimitsRegionInfoResponder); +public: + fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {}; + +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); + LLSD mInfo; }; class fetchScriptLimitsRegionSummaryResponder: public LLHTTPClient::Responder { - public: - fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {}; - - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - public: - protected: - LLSD mInfo; + LOG_CLASS(fetchScriptLimitsRegionSummaryResponder); +public: + fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {}; + +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); + LLSD mInfo; }; class fetchScriptLimitsRegionDetailsResponder: public LLHTTPClient::Responder { - public: - fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {}; - - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - public: - protected: - LLSD mInfo; + LOG_CLASS(fetchScriptLimitsRegionDetailsResponder); +public: + fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {}; + +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); + LLSD mInfo; }; class fetchScriptLimitsAttachmentInfoResponder: public LLHTTPClient::Responder { - public: - fetchScriptLimitsAttachmentInfoResponder() {}; + LOG_CLASS(fetchScriptLimitsAttachmentInfoResponder); +public: + fetchScriptLimitsAttachmentInfoResponder() {}; - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - public: - protected: +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); }; ///////////////////////////////////////////////////////////////////////////// @@ -190,7 +190,7 @@ protected: // LLRemoteParcelInfoObserver interface: /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); /*virtual*/ void setParcelID(const LLUUID& parcel_id); -/*virtual*/ void setErrorStatus(U32 status, const std::string& reason); +/*virtual*/ void setErrorStatus(S32 status, const std::string& reason); static void onClickRefresh(void* userdata); static void onClickHighlight(void* userdata); diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 2a946b1edf..a446b767ac 100755 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -30,6 +30,7 @@ #include "llcommandhandler.h" #include "llfloaterreg.h" #include "llfloatersearch.h" +#include "llhttpconstants.h" #include "llmediactrl.h" #include "llnotificationsutil.h" #include "lllogininstance.h" @@ -200,5 +201,5 @@ void LLFloaterSearch::search(const SearchQuery &p) url = LLWeb::expandURLSubstitutions(url, subs); // and load the URL in the web view - mWebBrowser->navigateTo(url, "text/html"); + mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML); } diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 8e92821aac..3d5b297fbe 100755 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -44,7 +44,6 @@ #include "lltoolfocus.h" #include "lltoolmgr.h" #include "llwebprofile.h" -#include "llwebsharing.h" ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -360,10 +359,6 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater) ESnapshotFormat shot_format = (ESnapshotFormat)gSavedSettings.getS32("SnapshotFormat"); LLViewerWindow::ESnapshotType layer_type = getLayerType(floater); -#if 0 - floater->getChildView("share_to_web")->setVisible( gSavedSettings.getBOOL("SnapshotSharingEnabled")); -#endif - floater->getChild<LLComboBox>("local_format_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFormat")); enableAspectRatioCheckbox(floater, !floater->impl.mAspectRatioCheckOff); setAspectRatioCheckboxValue(floater, gSavedSettings.getBOOL("KeepAspectForSnapshot")); @@ -1032,12 +1027,6 @@ LLFloaterSnapshot::~LLFloaterSnapshot() BOOL LLFloaterSnapshot::postBuild() { - // Kick start Web Sharing, to fetch its config data if it needs to. - if (gSavedSettings.getBOOL("SnapshotSharingEnabled")) - { - LLWebSharing::instance().init(); - } - mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn"); childSetAction("new_snapshot_btn", Impl::onClickNewSnapshot, this); mRefreshLabel = getChild<LLUICtrl>("refresh_lbl"); @@ -1263,7 +1252,7 @@ S32 LLFloaterSnapshot::notify(const LLSD& info) //static void LLFloaterSnapshot::update() { - LLFloaterSnapshot* inst = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); + LLFloaterSnapshot* inst = findInstance(); LLFloaterSocial* floater_social = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social"); if (!inst && !floater_social) @@ -1291,12 +1280,18 @@ LLFloaterSnapshot* LLFloaterSnapshot::getInstance() } // static +LLFloaterSnapshot* LLFloaterSnapshot::findInstance() +{ + return LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); +} + +// static void LLFloaterSnapshot::saveTexture() { LL_DEBUGS() << "saveTexture" << LL_ENDL; // FIXME: duplicated code - LLFloaterSnapshot* instance = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); + LLFloaterSnapshot* instance = findInstance(); if (!instance) { llassert(instance != NULL); @@ -1317,7 +1312,7 @@ BOOL LLFloaterSnapshot::saveLocal() { LL_DEBUGS() << "saveLocal" << LL_ENDL; // FIXME: duplicated code - LLFloaterSnapshot* instance = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); + LLFloaterSnapshot* instance = findInstance(); if (!instance) { llassert(instance != NULL); @@ -1337,7 +1332,7 @@ BOOL LLFloaterSnapshot::saveLocal() void LLFloaterSnapshot::preUpdate() { // FIXME: duplicated code - LLFloaterSnapshot* instance = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); + LLFloaterSnapshot* instance = findInstance(); if (instance) { // Disable the send/post/save buttons until snapshot is ready. @@ -1352,7 +1347,7 @@ void LLFloaterSnapshot::preUpdate() void LLFloaterSnapshot::postUpdate() { // FIXME: duplicated code - LLFloaterSnapshot* instance = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); + LLFloaterSnapshot* instance = findInstance(); if (instance) { // Enable the send/post/save buttons. @@ -1373,7 +1368,7 @@ void LLFloaterSnapshot::postUpdate() // static void LLFloaterSnapshot::postSave() { - LLFloaterSnapshot* instance = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); + LLFloaterSnapshot* instance = findInstance(); if (!instance) { llassert(instance != NULL); @@ -1399,7 +1394,7 @@ LLPointer<LLImageFormatted> LLFloaterSnapshot::getImageData() { // FIXME: May not work for textures. - LLFloaterSnapshot* instance = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); + LLFloaterSnapshot* instance = findInstance(); if (!instance) { llassert(instance != NULL); @@ -1426,7 +1421,7 @@ LLPointer<LLImageFormatted> LLFloaterSnapshot::getImageData() // static const LLVector3d& LLFloaterSnapshot::getPosTakenGlobal() { - LLFloaterSnapshot* instance = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); + LLFloaterSnapshot* instance = findInstance(); if (!instance) { llassert(instance != NULL); @@ -1446,7 +1441,7 @@ const LLVector3d& LLFloaterSnapshot::getPosTakenGlobal() // static void LLFloaterSnapshot::setAgentEmail(const std::string& email) { - LLFloaterSnapshot* instance = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); + LLFloaterSnapshot* instance = findInstance(); if (instance) { LLSideTrayPanelContainer* panel_container = instance->getChild<LLSideTrayPanelContainer>("panel_container"); diff --git a/indra/newview/llfloatersnapshot.h b/indra/newview/llfloatersnapshot.h index 82af8c7a9d..c757bf21c2 100755 --- a/indra/newview/llfloatersnapshot.h +++ b/indra/newview/llfloatersnapshot.h @@ -56,6 +56,7 @@ public: // TODO: create a snapshot model instead static LLFloaterSnapshot* getInstance(); + static LLFloaterSnapshot* findInstance(); static void saveTexture(); static BOOL saveLocal(); static void preUpdate(); diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index a242b224cd..0613ffc94d 100755 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -36,7 +36,7 @@ #include "llbutton.h" #include "llevents.h" #include "llhttpclient.h" -#include "llhttpstatuscodes.h" // for HTTP_FOUND +#include "llhttpconstants.h" #include "llnotificationsutil.h" #include "llradiogroup.h" #include "lltextbox.h" @@ -62,42 +62,46 @@ LLFloaterTOS::LLFloaterTOS(const LLSD& data) // on parent class indicating if the web server is working or not class LLIamHere : public LLHTTPClient::Responder { - private: - LLIamHere( LLFloaterTOS* parent ) : - mParent( parent ) - {} + LOG_CLASS(LLIamHere); +private: + LLIamHere( LLFloaterTOS* parent ) : + mParent( parent ) + {} - LLFloaterTOS* mParent; + LLFloaterTOS* mParent; - public: - - static LLIamHere* build( LLFloaterTOS* parent ) - { - return new LLIamHere( parent ); - }; - - virtual void setParent( LLFloaterTOS* parentIn ) - { - mParent = parentIn; - }; - - virtual void result( const LLSD& content ) +public: + static LLIamHere* build( LLFloaterTOS* parent ) + { + return new LLIamHere( parent ); + } + + virtual void setParent( LLFloaterTOS* parentIn ) + { + mParent = parentIn; + } + +protected: + virtual void httpSuccess() + { + if ( mParent ) { - if ( mParent ) - mParent->setSiteIsAlive( true ); - }; + mParent->setSiteIsAlive( true ); + } + } - virtual void error( U32 status, const std::string& reason ) + virtual void httpFailure() + { + LL_DEBUGS("LLIamHere") << dumpResponse() << LL_ENDL; + if ( mParent ) { - if ( mParent ) - { - // *HACK: For purposes of this alive check, 302 Found - // (aka Moved Temporarily) is considered alive. The web site - // redirects this link to a "cache busting" temporary URL. JC - bool alive = (status == HTTP_FOUND); - mParent->setSiteIsAlive( alive ); - } - }; + // *HACK: For purposes of this alive check, 302 Found + // (aka Moved Temporarily) is considered alive. The web site + // redirects this link to a "cache busting" temporary URL. JC + bool alive = (getStatus() == HTTP_FOUND); + mParent->setSiteIsAlive( alive ); + } + } }; // this is global and not a class member to keep crud out of the header file diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index e85d849c9a..e26f1e9ea5 100755 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -48,31 +48,30 @@ static LLFloaterURLEntry* sInstance = NULL; // on the Panel Land Media and to discover the MIME type class LLMediaTypeResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLMediaTypeResponder); public: LLMediaTypeResponder( const LLHandle<LLFloater> parent ) : - mParent( parent ) - {} - - LLHandle<LLFloater> mParent; - - - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - std::string media_type = content["content-type"].asString(); - std::string::size_type idx1 = media_type.find_first_of(";"); - std::string mime_type = media_type.substr(0, idx1); - completeAny(status, mime_type); - } - - void completeAny(U32 status, const std::string& mime_type) - { - // Set empty type to none/none. Empty string is reserved for legacy parcels - // which have no mime type set. - std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType(); - LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get(); - if ( floater_url_entry ) - floater_url_entry->headerFetchComplete( status, resolved_mime_type ); - } + mParent( parent ) + {} + + LLHandle<LLFloater> mParent; + +private: + /* virtual */ void httpCompleted() + { + const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE); + std::string::size_type idx1 = media_type.find_first_of(";"); + std::string mime_type = media_type.substr(0, idx1); + + // Set empty type to none/none. Empty string is reserved for legacy parcels + // which have no mime type set. + std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType(); + LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get(); + if ( floater_url_entry ) + { + floater_url_entry->headerFetchComplete( getStatus(), resolved_mime_type ); + } + } }; //----------------------------------------------------------------------------- @@ -136,7 +135,7 @@ void LLFloaterURLEntry::buildURLHistory() } } -void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_type) +void LLFloaterURLEntry::headerFetchComplete(S32 status, const std::string& mime_type) { LLPanelLandMedia* panel_media = dynamic_cast<LLPanelLandMedia*>(mPanelLandMediaHandle.get()); if (panel_media) diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index dfb49fe5ac..bdd1ebe592 100755 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -40,7 +40,7 @@ public: // that panel via the handle. static LLHandle<LLFloater> show(LLHandle<LLPanel> panel_land_media_handle, const std::string media_url); /*virtual*/ BOOL postBuild(); - void headerFetchComplete(U32 status, const std::string& mime_type); + void headerFetchComplete(S32 status, const std::string& mime_type); bool addURLToCombobox(const std::string& media_url); diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index a3a78b5d8b..f72adbb880 100755 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -29,6 +29,7 @@ #include "llcombobox.h" #include "lliconctrl.h" #include "llfloaterreg.h" +#include "llhttpconstants.h" #include "llfacebookconnect.h" #include "lllayoutstack.h" #include "llpluginclassmedia.h" @@ -240,9 +241,9 @@ void LLFloaterWebContent::open_media(const Params& p) { // Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin. LLViewerMedia::proxyWindowOpened(p.target(), p.id()); - mWebBrowser->setHomePageUrl(p.url, "text/html"); + mWebBrowser->setHomePageUrl(p.url, HTTP_CONTENT_TEXT_HTML); mWebBrowser->setTarget(p.target); - mWebBrowser->navigateTo(p.url, "text/html"); + mWebBrowser->navigateTo(p.url, HTTP_CONTENT_TEXT_HTML); set_current_url(p.url); @@ -489,7 +490,7 @@ void LLFloaterWebContent::onEnterAddress() LLStringUtil::trim(url); if ( url.length() > 0 ) { - mWebBrowser->navigateTo( url, "text/html"); + mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML); }; } diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h index 9dcfdfa185..8772185ad0 100755 --- a/indra/newview/llfolderviewmodelinventory.h +++ b/indra/newview/llfolderviewmodelinventory.h @@ -105,6 +105,10 @@ class LLFolderViewModelInventory public: typedef LLFolderViewModel<LLInventorySort, LLFolderViewModelItemInventory, LLFolderViewModelItemInventory, LLInventoryFilter> base_t; + LLFolderViewModelInventory(const std::string& name) + : base_t(new LLInventorySort(), new LLInventoryFilter(LLInventoryFilter::Params().name(name))) + {} + void setTaskID(const LLUUID& id) {mTaskID = id;} void sort(LLFolderViewFolder* folder); diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp index 6566ef5dca..307e259006 100755 --- a/indra/newview/llfriendcard.cpp +++ b/indra/newview/llfriendcard.cpp @@ -38,6 +38,7 @@ #include "llcallingcard.h" // for LLAvatarTracker #include "llviewerinventory.h" #include "llinventorymodel.h" +#include "llcallbacklist.h" // Constants; @@ -86,7 +87,7 @@ const LLUUID& get_folder_uuid(const LLUUID& parentFolderUUID, LLInventoryCollect if (cats_count > 1) { - LL_WARNS("LLFriendCardsManager") + LL_WARNS_ONCE("LLFriendCardsManager") << "There is more than one Friend card folder." << "The first folder will be used." << LL_ENDL; @@ -154,7 +155,7 @@ void LLInitialFriendCardsFetch::done() // This observer is no longer needed. gInventory.removeObserver(this); - mCheckFolderCallback(); + doOnIdleOneTime(mCheckFolderCallback); delete this; } diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 9fa40bc6b9..b15556d73d 100755 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -299,6 +299,12 @@ void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id, } +void notify_update_label(const LLUUID& base_item_id) +{ + gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id); + LLGestureMgr::instance().notifyObservers(); +} + void LLGestureMgr::deactivateGesture(const LLUUID& item_id) { const LLUUID& base_item_id = get_linked_uuid(item_id); @@ -322,7 +328,6 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id) } mActive.erase(it); - gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id); // Inform the database of this change LLMessageSystem* msg = gMessageSystem; @@ -338,9 +343,11 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id) gAgent.sendReliableMessage(); - LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id); + LLPointer<LLInventoryCallback> cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, + boost::bind(notify_update_label,base_item_id)); - notifyObservers(); + LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id, cb); } @@ -1337,6 +1344,7 @@ BOOL LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) { S32 in_len = in_str.length(); + //return whole trigger, if received text equals to it item_map_t::iterator it; for (it = mActive.begin(); it != mActive.end(); ++it) { @@ -1344,7 +1352,24 @@ BOOL LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) if (gesture) { const std::string& trigger = gesture->getTrigger(); - + if (!LLStringUtil::compareInsensitive(in_str, trigger)) + { + *out_str = trigger; + return TRUE; + } + } + } + + //return common chars, if more than one trigger matches the prefix + std::string rest_of_match = ""; + std::string buf = ""; + for (it = mActive.begin(); it != mActive.end(); ++it) + { + LLMultiGesture* gesture = (*it).second; + if (gesture) + { + const std::string& trigger = gesture->getTrigger(); + if (in_len > (S32)trigger.length()) { // too short, bail out @@ -1355,11 +1380,49 @@ BOOL LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) LLStringUtil::truncate(trigger_trunc, in_len); if (!LLStringUtil::compareInsensitive(in_str, trigger_trunc)) { - *out_str = trigger; - return TRUE; + if (rest_of_match.compare("") == 0) + { + rest_of_match = trigger.substr(in_str.size()); + } + std::string cur_rest_of_match = trigger.substr(in_str.size()); + buf = ""; + S32 i=0; + + while (i<rest_of_match.length() && i<cur_rest_of_match.length()) + { + if (rest_of_match[i]==cur_rest_of_match[i]) + { + buf.push_back(rest_of_match[i]); + } + else + { + if(i==0) + { + rest_of_match = ""; + } + break; + } + i++; + } + if (rest_of_match.compare("") == 0) + { + return FALSE; + } + if (buf.compare("") != 0) + { + rest_of_match = buf; + } + } } } + + if (rest_of_match.compare("") != 0) + { + *out_str = in_str+rest_of_match; + return TRUE; + } + return FALSE; } diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp index 493dea62ff..813d2081ce 100755 --- a/indra/newview/llgiveinventory.cpp +++ b/indra/newview/llgiveinventory.cpp @@ -139,7 +139,7 @@ bool LLGiveInventory::isInventoryGiveAcceptable(const LLInventoryItem* item) BOOL copyable = false; if (item->getPermissions().allowCopyBy(gAgentID)) copyable = true; - if (!copyable && get_is_item_worn(item->getUUID())) + if (!copyable || get_is_item_worn(item->getUUID())) { acceptable = false; } diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index bede9b1e6c..c386030329 100755 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -624,7 +624,8 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); LLGLDisable cull(GL_CULL_FACE); - if (mCollisionBanned == BA_BANNED) + if (mCollisionBanned == BA_BANNED || + regionp->getRegionFlag(REGION_FLAGS_BLOCK_FLYOVER)) { collision_height = BAN_HEIGHT; } diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index f514729aa1..913efd6434 100755 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -149,7 +149,7 @@ public: void changed(LLGroupChange gc) { - if (gc == GC_MEMBER_DATA && !mRequestProcessed) + if (gc == GC_PROPERTIES && !mRequestProcessed) { LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupId); if (!gdatap) @@ -159,9 +159,6 @@ public: else if (!gdatap->isMemberDataComplete()) { LL_WARNS() << "LLGroupMgr::getInstance()->getGroupData()->isMemberDataComplete() was FALSE" << LL_ENDL; - } - else - { processGroupData(); mRequestProcessed = true; } diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 18cdc6ec6d..61c3bbb13a 100755 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -234,11 +234,11 @@ LLGroupMgrGroupData::LLGroupMgrGroupData(const LLUUID& id) : mMemberCount(0), mRoleCount(0), mReceivedRoleMemberPairs(0), - mMemberDataComplete(FALSE), - mRoleDataComplete(FALSE), - mRoleMemberDataComplete(FALSE), - mGroupPropertiesDataComplete(FALSE), - mPendingRoleMemberRequest(FALSE), + mMemberDataComplete(false), + mRoleDataComplete(false), + mRoleMemberDataComplete(false), + mGroupPropertiesDataComplete(false), + mPendingRoleMemberRequest(false), mAccessTime(0.0f) { mMemberVersion.generate(); @@ -427,7 +427,7 @@ void LLGroupMgrGroupData::removeMemberData() delete mi->second; } mMembers.clear(); - mMemberDataComplete = FALSE; + mMemberDataComplete = false; mMemberVersion.generate(); } @@ -449,8 +449,8 @@ void LLGroupMgrGroupData::removeRoleData() } mRoles.clear(); mReceivedRoleMemberPairs = 0; - mRoleDataComplete = FALSE; - mRoleMemberDataComplete = FALSE; + mRoleDataComplete = false; + mRoleMemberDataComplete= false; } void LLGroupMgrGroupData::removeRoleMemberData() @@ -474,7 +474,7 @@ void LLGroupMgrGroupData::removeRoleMemberData() } mReceivedRoleMemberPairs = 0; - mRoleMemberDataComplete = FALSE; + mRoleMemberDataComplete= false; } LLGroupMgrGroupData::~LLGroupMgrGroupData() @@ -611,6 +611,11 @@ void LLGroupMgrGroupData::recalcAgentPowers(const LLUUID& agent_id) } } +bool LLGroupMgrGroupData::isSingleMemberNotOwner() +{ + return mMembers.size() == 1 && !mMembers.begin()->second->isOwner(); +} + bool packRoleUpdateMessageBlock(LLMessageSystem* msg, const LLUUID& group_id, const LLUUID& role_id, @@ -745,6 +750,20 @@ void LLGroupMgrGroupData::cancelRoleChanges() // Clear out all changes! mRoleChanges.clear(); } + +void LLGroupMgrGroupData::createBanEntry(const LLUUID& ban_id, const LLGroupBanData& ban_data) +{ + mBanList[ban_id] = ban_data; +} + +void LLGroupMgrGroupData::removeBanEntry(const LLUUID& ban_id) +{ + mBanList.erase(ban_id); +} + + + + // // LLGroupMgr // @@ -954,12 +973,12 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) if (group_datap->mMembers.size() == (U32)group_datap->mMemberCount) { - group_datap->mMemberDataComplete = TRUE; + group_datap->mMemberDataComplete = true; group_datap->mMemberRequestID.setNull(); // We don't want to make role-member data requests until we have all the members if (group_datap->mPendingRoleMemberRequest) { - group_datap->mPendingRoleMemberRequest = FALSE; + group_datap->mPendingRoleMemberRequest = false; LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_datap->mID); } } @@ -1029,7 +1048,7 @@ void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data) group_datap->mMemberCount = num_group_members; group_datap->mRoleCount = num_group_roles + 1; // Add the everyone role. - group_datap->mGroupPropertiesDataComplete = TRUE; + group_datap->mGroupPropertiesDataComplete = true; group_datap->mChanged = TRUE; LLGroupMgr::getInstance()->notifyObservers(GC_PROPERTIES); @@ -1106,12 +1125,12 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) if (group_datap->mRoles.size() == (U32)group_datap->mRoleCount) { - group_datap->mRoleDataComplete = TRUE; + group_datap->mRoleDataComplete = true; group_datap->mRoleDataRequestID.setNull(); // We don't want to make role-member data requests until we have all the role data if (group_datap->mPendingRoleMemberRequest) { - group_datap->mPendingRoleMemberRequest = FALSE; + group_datap->mPendingRoleMemberRequest = false; LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_datap->mID); } } @@ -1220,7 +1239,7 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) } } - group_datap->mRoleMemberDataComplete = TRUE; + group_datap->mRoleMemberDataComplete= true; group_datap->mRoleMembersRequestID.setNull(); } @@ -1844,25 +1863,176 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id, // Responder class for capability group management -class GroupMemberDataResponder : public LLHTTPClient::Responder +class GroupBanDataResponder : public LLHTTPClient::Responder { public: - GroupMemberDataResponder() {} - virtual ~GroupMemberDataResponder() {} - virtual void result(const LLSD& pContent); - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); + GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh=false); + virtual ~GroupBanDataResponder() {} + virtual void result(const LLSD& pContent); + virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); private: - LLSD mMemberData; + LLUUID mGroupID; + BOOL mForceRefresh; }; -void GroupMemberDataResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +GroupBanDataResponder::GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh) : + mGroupID(gropup_id), + mForceRefresh(force_refresh) +{} + +void GroupBanDataResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) { LL_WARNS("GrpMgr") << "Error receiving group member data [status:" << pStatus << "]: " << pContent << LL_ENDL; } -void GroupMemberDataResponder::result(const LLSD& content) +void GroupBanDataResponder::result(const LLSD& content) +{ + if ( content.size()) + { + if (content.has("ban_list")) + { + // group data received + LLGroupMgr::processGroupBanRequest(content); + } + // no group data received, this is either CREATE or DELETE operation + // complete confirmation. Local data may be obsolete. + else if (mForceRefresh) + { + // providing mGroupId and not extracting it from content since it is not + // included into CREATE and DELETE responses + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID); + } + } + else + { + LL_WARNS("GrpMgr") << "No group member data received." << LL_ENDL; + return; + } +} + +void LLGroupMgr::sendGroupBanRequest( EBanRequestType request_type, + const LLUUID& group_id, + U32 ban_action, /* = BAN_NO_ACTION */ + const std::vector<LLUUID> ban_list) /* = std::vector<LLUUID>() */ +{ + LLViewerRegion* currentRegion = gAgent.getRegion(); + if(!currentRegion) + { + LL_WARNS("GrpMgr") << "Agent does not have a current region. Uh-oh!" << LL_ENDL; + return; + } + + // Check to make sure we have our capabilities + if(!currentRegion->capabilitiesReceived()) + { + LL_WARNS("GrpMgr") << " Capabilities not received!" << LL_ENDL; + return; + } + + // Get our capability + std::string cap_url = currentRegion->getCapability("GroupAPIv1"); + if(cap_url.empty()) + { + return; + } + cap_url += "?group_id=" + group_id.asString(); + + LLSD body = LLSD::emptyMap(); + body["ban_action"] = (LLSD::Integer)(ban_action & ~BAN_UPDATE); + // Add our list of potential banned residents to the list + body["ban_ids"] = LLSD::emptyArray(); + LLSD ban_entry; + + uuid_vec_t::const_iterator iter = ban_list.begin(); + for(;iter != ban_list.end(); ++iter) + { + ban_entry = (*iter); + body["ban_ids"].append(ban_entry); + } + + LLHTTPClient::ResponderPtr grp_ban_responder = new GroupBanDataResponder(group_id, ban_action & BAN_UPDATE); + switch(request_type) + { + case REQUEST_GET: + LLHTTPClient::get(cap_url, grp_ban_responder); + break; + case REQUEST_POST: + LLHTTPClient::post(cap_url, body, grp_ban_responder); + break; + case REQUEST_PUT: + case REQUEST_DEL: + break; + } +} + + +void LLGroupMgr::processGroupBanRequest(const LLSD& content) { + // Did we get anything in content? + if(!content.size()) + { + LL_WARNS("GrpMgr") << "No group member data received." << LL_ENDL; + return; + } + + LLUUID group_id = content["group_id"].asUUID(); + + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id); + if (!gdatap) + return; + + LLSD::map_const_iterator i = content["ban_list"].beginMap(); + LLSD::map_const_iterator iEnd = content["ban_list"].endMap(); + for(;i != iEnd; ++i) + { + const LLUUID ban_id(i->first); + LLSD ban_entry(i->second); + + LLGroupBanData ban_data; + if(ban_entry.has("ban_date")) + { + ban_data.mBanDate = ban_entry["ban_date"].asDate(); + // TODO: Ban Reason + } + + gdatap->createBanEntry(ban_id, ban_data); + } + + gdatap->mChanged = TRUE; + LLGroupMgr::getInstance()->notifyObservers(GC_BANLIST); +} + + + +// Responder class for capability group management +class GroupMemberDataResponder : public LLHTTPClient::Responder +{ + LOG_CLASS(GroupMemberDataResponder); +public: + GroupMemberDataResponder() {} + virtual ~GroupMemberDataResponder() {} + +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); + LLSD mMemberData; +}; + +void GroupMemberDataResponder::httpFailure() +{ + LL_WARNS("GrpMgr") << "Error receiving group member data " + << dumpResponse() << LL_ENDL; +} + +void GroupMemberDataResponder::httpSuccess() +{ + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLGroupMgr::processCapGroupMembersRequest(content); } @@ -1928,7 +2098,7 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) if(num_members < 1) return; - LLUUID group_id = content["group_id"].asUUID(); + LLUUID group_id = content["group_id"].asUUID(); LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); if(!group_datap) @@ -2011,12 +2181,12 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) LLGroupMgr::getInstance()->sendGroupTitlesRequest(group_id); - group_datap->mMemberDataComplete = TRUE; + group_datap->mMemberDataComplete = true; group_datap->mMemberRequestID.setNull(); // Make the role-member data request if (group_datap->mPendingRoleMemberRequest) { - group_datap->mPendingRoleMemberRequest = FALSE; + group_datap->mPendingRoleMemberRequest = false; LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_id); } diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h index d107fceb49..970d6d5a2d 100755 --- a/indra/newview/llgroupmgr.h +++ b/indra/newview/llgroupmgr.h @@ -33,8 +33,10 @@ #include <string> #include <map> +// Forward Declarations class LLMessageSystem; - +class LLGroupRoleData; +class LLGroupMgr; enum LLGroupChange { @@ -43,6 +45,7 @@ enum LLGroupChange GC_ROLE_DATA, GC_ROLE_MEMBER_DATA, GC_TITLES, + GC_BANLIST, GC_ALL }; @@ -65,8 +68,6 @@ public: virtual void changed(const LLUUID& group_id, LLGroupChange gc) = 0; }; -class LLGroupRoleData; - class LLGroupMemberData { friend class LLGroupMgrGroupData; @@ -201,6 +202,17 @@ struct lluuid_pair_less } }; + +struct LLGroupBanData +{ + LLGroupBanData(): mBanDate() {} + ~LLGroupBanData() {} + + LLDate mBanDate; + // TODO: std:string ban_reason; +}; + + struct LLGroupTitle { std::string mTitle; @@ -208,8 +220,6 @@ struct LLGroupTitle BOOL mSelected; }; -class LLGroupMgr; - class LLGroupMgrGroupData { friend class LLGroupMgr; @@ -239,27 +249,38 @@ public: void recalcAllAgentPowers(); void recalcAgentPowers(const LLUUID& agent_id); - BOOL isMemberDataComplete() { return mMemberDataComplete; } - BOOL isRoleDataComplete() { return mRoleDataComplete; } - BOOL isRoleMemberDataComplete() { return mRoleMemberDataComplete; } - BOOL isGroupPropertiesDataComplete() { return mGroupPropertiesDataComplete; } + bool isMemberDataComplete() { return mMemberDataComplete; } + bool isRoleDataComplete() { return mRoleDataComplete; } + bool isRoleMemberDataComplete() { return mRoleMemberDataComplete; } + bool isGroupPropertiesDataComplete() { return mGroupPropertiesDataComplete; } + + bool isSingleMemberNotOwner(); F32 getAccessTime() const { return mAccessTime; } void setAccessed(); const LLUUID& getMemberVersion() const { return mMemberVersion; } + void clearBanList() { mBanList.clear(); } + void getBanList(const LLUUID& group_id, LLGroupBanData& ban_data); + const LLGroupBanData& getBanEntry(const LLUUID& ban_id) { return mBanList[ban_id]; } + + void createBanEntry(const LLUUID& ban_id, const LLGroupBanData& ban_data = LLGroupBanData()); + void removeBanEntry(const LLUUID& ban_id); + + public: typedef std::map<LLUUID,LLGroupMemberData*> member_list_t; typedef std::map<LLUUID,LLGroupRoleData*> role_list_t; typedef std::map<lluuid_pair,LLRoleMemberChange,lluuid_pair_less> change_map_t; typedef std::map<LLUUID,LLRoleData> role_data_map_t; + typedef std::map<LLUUID,LLGroupBanData> ban_list_t; + member_list_t mMembers; role_list_t mRoles; - - change_map_t mRoleMemberChanges; role_data_map_t mRoleChanges; + ban_list_t mBanList; std::vector<LLGroupTitle> mTitles; @@ -290,12 +311,12 @@ private: LLUUID mTitlesRequestID; U32 mReceivedRoleMemberPairs; - BOOL mMemberDataComplete; - BOOL mRoleDataComplete; - BOOL mRoleMemberDataComplete; - BOOL mGroupPropertiesDataComplete; + bool mMemberDataComplete; + bool mRoleDataComplete; + bool mRoleMemberDataComplete; + bool mGroupPropertiesDataComplete; - BOOL mPendingRoleMemberRequest; + bool mPendingRoleMemberRequest; F32 mAccessTime; // Generate a new ID every time mMembers @@ -323,6 +344,23 @@ class LLGroupMgr : public LLSingleton<LLGroupMgr> LOG_CLASS(LLGroupMgr); public: + enum EBanRequestType + { + REQUEST_GET = 0, + REQUEST_POST, + REQUEST_PUT, + REQUEST_DEL + }; + + enum EBanRequestAction + { + BAN_NO_ACTION = 0, + BAN_CREATE = 1, + BAN_DELETE = 2, + BAN_UPDATE = 4 + }; + +public: LLGroupMgr(); ~LLGroupMgr(); @@ -355,8 +393,14 @@ public: static void sendGroupMemberInvites(const LLUUID& group_id, std::map<LLUUID,LLUUID>& role_member_pairs); static void sendGroupMemberEjects(const LLUUID& group_id, uuid_vec_t& member_ids); + + static void sendGroupBanRequest(EBanRequestType request_type, + const LLUUID& group_id, + U32 ban_action = BAN_NO_ACTION, + const uuid_vec_t ban_list = uuid_vec_t()); + + static void processGroupBanRequest(const LLSD& content); - // BAKER void sendCapGroupMembersRequest(const LLUUID& group_id); static void processCapGroupMembersRequest(const LLSD& content); @@ -401,4 +445,3 @@ private: #endif - diff --git a/indra/newview/llhomelocationresponder.cpp b/indra/newview/llhomelocationresponder.cpp index eefa8bd42a..d0492bcdb4 100755 --- a/indra/newview/llhomelocationresponder.cpp +++ b/indra/newview/llhomelocationresponder.cpp @@ -33,71 +33,76 @@ #include "llagent.h" #include "llviewerregion.h" -void LLHomeLocationResponder::result( const LLSD& content ) +void LLHomeLocationResponder::httpSuccess() { + const LLSD& content = getContent(); LLVector3 agent_pos; bool error = true; - + do { - + // was the call to /agent/<agent-id>/home-location successful? // If not, we keep error set to true if( ! content.has("success") ) { break; } - + if( 0 != strncmp("true", content["success"].asString().c_str(), 4 ) ) { break; } - + // did the simulator return a "justified" home location? // If no, we keep error set to true if( ! content.has( "HomeLocation" ) ) { break; } - + if( ! content["HomeLocation"].has("LocationPos") ) { break; } - + if( ! content["HomeLocation"]["LocationPos"].has("X") ) { break; } agent_pos.mV[VX] = content["HomeLocation"]["LocationPos"]["X"].asInteger(); - + if( ! content["HomeLocation"]["LocationPos"].has("Y") ) { break; } agent_pos.mV[VY] = content["HomeLocation"]["LocationPos"]["Y"].asInteger(); - + if( ! content["HomeLocation"]["LocationPos"].has("Z") ) { break; } agent_pos.mV[VZ] = content["HomeLocation"]["LocationPos"]["Z"].asInteger(); - + error = false; } while( 0 ); - - if( ! error ) + + if( error ) + { + failureResult(HTTP_INTERNAL_ERROR, "Invalid server response content", content); + } + else { LL_INFOS() << "setting home position" << LL_ENDL; - + LLViewerRegion *viewer_region = gAgent.getRegion(); gAgent.setHomePosRegion( viewer_region->getHandle(), agent_pos ); } } -void LLHomeLocationResponder::errorWithContent( U32 status, const std::string& reason, const LLSD& content ) +void LLHomeLocationResponder::httpFailure() { - LL_WARNS() << "LLHomeLocationResponder error [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; } diff --git a/indra/newview/llhomelocationresponder.h b/indra/newview/llhomelocationresponder.h index 9bf4b12c4e..adc6c8cb58 100755 --- a/indra/newview/llhomelocationresponder.h +++ b/indra/newview/llhomelocationresponder.h @@ -35,8 +35,10 @@ /* Typedef, Enum, Class, Struct, etc. */ class LLHomeLocationResponder : public LLHTTPClient::Responder { - virtual void result( const LLSD& content ); - virtual void errorWithContent( U32 status, const std::string& reason, const LLSD& content ); + LOG_CLASS(LLHomeLocationResponder); +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); }; #endif diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp new file mode 100755 index 0000000000..2d4ce6c883 --- /dev/null +++ b/indra/newview/llhttpretrypolicy.cpp @@ -0,0 +1,142 @@ +/** + * @file llhttpretrypolicy.h + * @brief Header for a retry policy class intended for use with http responders. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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 "llhttpretrypolicy.h" + +LLAdaptiveRetryPolicy::LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx): + mMinDelay(min_delay), + mMaxDelay(max_delay), + mBackoffFactor(backoff_factor), + mMaxRetries(max_retries), + mRetryOn4xx(retry_on_4xx) +{ + init(); +} + +void LLAdaptiveRetryPolicy::init() +{ + mDelay = mMinDelay; + mRetryCount = 0; + mShouldRetry = true; +} + +void LLAdaptiveRetryPolicy::reset() +{ + init(); +} + +bool LLAdaptiveRetryPolicy::getRetryAfter(const LLSD& headers, F32& retry_header_time) +{ + return (headers.has(HTTP_IN_HEADER_RETRY_AFTER) + && getSecondsUntilRetryAfter(headers[HTTP_IN_HEADER_RETRY_AFTER].asStringRef(), retry_header_time)); +} + +bool LLAdaptiveRetryPolicy::getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time) +{ + if (headers) + { + const std::string *retry_value = headers->find(HTTP_IN_HEADER_RETRY_AFTER.c_str()); + if (retry_value && + getSecondsUntilRetryAfter(*retry_value, retry_header_time)) + { + return true; + } + } + return false; +} + +void LLAdaptiveRetryPolicy::onSuccess() +{ + init(); +} + +void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers) +{ + F32 retry_header_time; + bool has_retry_header_time = getRetryAfter(headers,retry_header_time); + onFailureCommon(status, has_retry_header_time, retry_header_time); +} + +void LLAdaptiveRetryPolicy::onFailure(const LLCore::HttpResponse *response) +{ + F32 retry_header_time; + const LLCore::HttpHeaders *headers = response->getHeaders(); + bool has_retry_header_time = getRetryAfter(headers,retry_header_time); + onFailureCommon(response->getStatus().mType, has_retry_header_time, retry_header_time); +} + +void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time) +{ + if (!mShouldRetry) + { + LL_INFOS() << "keep on failing" << LL_ENDL; + return; + } + if (mRetryCount > 0) + { + mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay); + } + // Honor server Retry-After header. + // Status 503 may ask us to wait for a certain amount of time before retrying. + F32 wait_time = mDelay; + if (has_retry_header_time) + { + wait_time = retry_header_time; + } + + if (mRetryCount>=mMaxRetries) + { + LL_INFOS() << "Too many retries " << mRetryCount << ", will not retry" << LL_ENDL; + mShouldRetry = false; + } + if (!mRetryOn4xx && !isHttpServerErrorStatus(status)) + { + LL_INFOS() << "Non-server error " << status << ", will not retry" << LL_ENDL; + mShouldRetry = false; + } + if (mShouldRetry) + { + LL_INFOS() << "Retry count " << mRetryCount << " should retry after " << wait_time << LL_ENDL; + mRetryTimer.reset(); + mRetryTimer.setTimerExpirySec(wait_time); + } + mRetryCount++; +} + + +bool LLAdaptiveRetryPolicy::shouldRetry(F32& seconds_to_wait) const +{ + if (mRetryCount == 0) + { + // Called shouldRetry before any failure. + seconds_to_wait = F32_MAX; + return false; + } + seconds_to_wait = mShouldRetry ? (F32) mRetryTimer.getRemainingTimeF32() : F32_MAX; + return mShouldRetry; +} diff --git a/indra/newview/llhttpretrypolicy.h b/indra/newview/llhttpretrypolicy.h new file mode 100755 index 0000000000..cf79e0b401 --- /dev/null +++ b/indra/newview/llhttpretrypolicy.h @@ -0,0 +1,98 @@ +/** + * @file file llhttpretrypolicy.h + * @brief declarations for http retry policy class. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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_RETRYPOLICY_H +#define LL_RETRYPOLICY_H + +#include "lltimer.h" +#include "llthread.h" + +#include "llhttpconstants.h" + +// For compatibility with new core http lib. +#include "httpresponse.h" +#include "httpheaders.h" + +// This is intended for use with HTTP Clients/Responders, but is not +// specifically coupled with those classes. +class LLHTTPRetryPolicy: public LLThreadSafeRefCount +{ +public: + LLHTTPRetryPolicy() {} + + virtual ~LLHTTPRetryPolicy() {} + // Call after a sucess to reset retry state. + + virtual void onSuccess() = 0; + // Call once after an HTTP failure to update state. + virtual void onFailure(S32 status, const LLSD& headers) = 0; + + virtual void onFailure(const LLCore::HttpResponse *response) = 0; + + virtual bool shouldRetry(F32& seconds_to_wait) const = 0; + + virtual void reset() = 0; +}; + +// Very general policy with geometric back-off after failures, +// up to a maximum delay, and maximum number of retries. +class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy +{ +public: + LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx = false); + + // virtual + void onSuccess(); + + void reset(); + + // virtual + void onFailure(S32 status, const LLSD& headers); + // virtual + void onFailure(const LLCore::HttpResponse *response); + // virtual + bool shouldRetry(F32& seconds_to_wait) const; + +protected: + void init(); + bool getRetryAfter(const LLSD& headers, F32& retry_header_time); + bool getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time); + void onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time); + +private: + + const F32 mMinDelay; // delay never less than this value + const F32 mMaxDelay; // delay never exceeds this value + const F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. + const U32 mMaxRetries; // maximum number of times shouldRetry will return true. + F32 mDelay; // current default delay. + U32 mRetryCount; // number of times shouldRetry has been called. + LLTimer mRetryTimer; // time until next retry. + bool mShouldRetry; // Becomes false after too many retries, or the wrong sort of status received, etc. + bool mRetryOn4xx; // Normally only retry on 5xx server errors. +}; + +#endif diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 34ccab0302..c194dc05b0 100755 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -388,16 +388,17 @@ void LLFloaterIMPanel::draw() class LLSessionInviteResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLSessionInviteResponder); public: LLSessionInviteResponder(const LLUUID& session_id) { mSessionID = session_id; } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +protected: + void httpFailure() { - LL_WARNS() << "Error inviting all agents to session [status:" - << statusNum << "]: " << content << LL_ENDL; + LL_WARNS() << "Error inviting all agents to session " << dumpResponse() << LL_ENDL; //throw something back to the viewer here? } diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index af93778c10..8917c07759 100755 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -1460,6 +1460,7 @@ void start_deprecated_conference_chat( class LLStartConferenceChatResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLStartConferenceChatResponder); public: LLStartConferenceChatResponder( const LLUUID& temp_session_id, @@ -1473,10 +1474,12 @@ public: mAgents = agents_to_invite; } - virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +protected: + virtual void httpFailure() { //try an "old school" way. - if ( statusNum == 400 ) + // *TODO: What about other error status codes? 4xx 5xx? + if ( getStatus() == HTTP_BAD_REQUEST ) { start_deprecated_conference_chat( mTempSessionID, @@ -1485,8 +1488,7 @@ public: mAgents); } - LL_WARNS() << "LLStartConferenceChatResponder error [status:" - << statusNum << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; //else throw an error back to the client? //in theory we should have just have these error strings @@ -1578,6 +1580,7 @@ bool LLIMModel::sendStartSession( class LLViewerChatterBoxInvitationAcceptResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLViewerChatterBoxInvitationAcceptResponder); public: LLViewerChatterBoxInvitationAcceptResponder( const LLUUID& session_id, @@ -1587,8 +1590,15 @@ public: mInvitiationType = invitation_type; } - void result(const LLSD& content) +private: + void httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } if ( gIMMgr) { LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); @@ -1633,19 +1643,17 @@ public: } } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) + void httpFailure() { - LL_WARNS() << "LLViewerChatterBoxInvitationAcceptResponder error [status:" - << statusNum << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; //throw something back to the viewer here? if ( gIMMgr ) { gIMMgr->clearPendingAgentListUpdates(mSessionID); gIMMgr->clearPendingInvitation(mSessionID); - if ( 404 == statusNum ) + if ( HTTP_NOT_FOUND == getStatus() ) { - std::string error_string; - error_string = "session_does_not_exist_error"; + static const std::string error_string("session_does_not_exist_error"); gIMMgr->showSessionStartError(error_string, mSessionID); } } diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index b75140238e..1e15dc832c 100755 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -292,11 +292,6 @@ void LLInspectAvatar::processAvatarData(LLAvatarData* data) delete mPropertiesRequest; mPropertiesRequest = NULL; } -/* -prep# - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - LL_WARNS() << "MuteVoiceResponder error [status:" << status << "]: " << content << LL_ENDL; - */ void LLInspectAvatar::updateVolumeSlider() { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index c538fb6c68..5df28ccb73 100755 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -202,6 +202,7 @@ const std::string& LLInvFVBridge::getDisplayName() const { buildDisplayName(); } + return mDisplayName; } @@ -1161,17 +1162,10 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) { - LLInventoryCategory* cat = model->getCategory(uuid); - if (cat) - { - model->purgeDescendentsOf(uuid); - model->notifyObservers(); - } LLInventoryObject* obj = model->getObject(uuid); if (obj) { - model->purgeObject(uuid); - model->notifyObservers(); + remove_inventory_object(uuid, NULL); } } @@ -1607,18 +1601,18 @@ void LLItemBridge::buildDisplayName() const else { mDisplayName.assign(LLStringUtil::null); -} - + } + mSearchableName.assign(mDisplayName); mSearchableName.append(getLabelSuffix()); LLStringUtil::toUpper(mSearchableName); - + //Name set, so trigger a sort if(mParent) -{ - mParent->requestSort(); - } + { + mParent->requestSort(); } +} LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const { @@ -1732,13 +1726,9 @@ BOOL LLItemBridge::renameItem(const std::string& new_name) LLViewerInventoryItem* item = getItem(); if(item && (item->getName() != new_name)) { - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); - new_item->rename(new_name); - new_item->updateServer(FALSE); - model->updateItem(new_item); - - model->notifyObservers(); - buildDisplayName(); + LLSD updates; + updates["name"] = new_name; + update_inventory_item(item->getUUID(),updates, NULL); } // return FALSE because we either notified observers (& therefore // rebuilt) or we didn't update. @@ -1774,16 +1764,8 @@ BOOL LLItemBridge::removeItem() { if (!item->getIsLinkType()) { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLLinkedItemIDMatches is_linked_item_match(mUUID); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - item_array, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); - - const U32 num_links = cat_array.size() + item_array.size(); + LLInventoryModel::item_array_t item_array = gInventory.collectLinksTo(mUUID); + const U32 num_links = item_array.size(); if (num_links > 0) { // Warn if the user is will break any links when deleting this item. @@ -1935,49 +1917,19 @@ void LLFolderBridge::buildDisplayName() const void LLFolderBridge::update() { - bool possibly_has_children = false; - bool up_to_date = isUpToDate(); - if(!up_to_date && hasChildren()) // we know we have children but haven't fetched them (doesn't obey filter) - { - possibly_has_children = true; - } - - bool loading = (possibly_has_children - && !up_to_date ); + // we know we have children but haven't fetched them (doesn't obey filter) + bool loading = !isUpToDate() && hasChildren() && mFolderViewItem->isOpen(); if (loading != mIsLoading) { - if ( loading && !mIsLoading ) + if ( loading ) { // Measure how long we've been in the loading state mTimeSinceRequestStart.reset(); } + mIsLoading = loading; - const BOOL in_inventory = gInventory.isObjectDescendentOf(getUUID(), gInventory.getRootFolderID()); - const BOOL in_library = gInventory.isObjectDescendentOf(getUUID(), gInventory.getLibraryRootFolderID()); - - bool root_is_loading = false; - if (in_inventory) - { - root_is_loading = LLInventoryModelBackgroundFetch::instance().inventoryFetchInProgress(); - } - if (in_library) - { - root_is_loading = LLInventoryModelBackgroundFetch::instance().libraryFetchInProgress(); - } - if ((mIsLoading - && mTimeSinceRequestStart.getElapsedTimeF32() >= gSavedSettings.getF32("FolderLoadingMessageWaitTime")) - || (LLInventoryModelBackgroundFetch::instance().folderFetchActive() - && root_is_loading)) - { - mDisplayName = LLInvFVBridge::getDisplayName() + " ( " + LLTrans::getString("LoadingData") + " ) "; - mIsLoading = true; - } - else - { - mDisplayName = LLInvFVBridge::getDisplayName(); - mIsLoading = false; - } + mFolderViewItem->refresh(); } } @@ -2490,49 +2442,13 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } } } - // if target is an outfit or current outfit folder we use link - if (move_is_into_current_outfit || move_is_into_outfit) + // if target is current outfit folder we use link + if (move_is_into_current_outfit && + inv_cat->getPreferredType() == LLFolderType::FT_NONE) { - if (inv_cat->getPreferredType() == LLFolderType::FT_NONE) - { - if (move_is_into_current_outfit) - { - // traverse category and add all contents to currently worn. - BOOL append = true; - LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append); - } - else - { - // Recursively create links in target outfit. - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - model->collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); - LLAppearanceMgr::instance().linkAll(mUUID,items,NULL); - } - } - else - { -#if SUPPORT_ENSEMBLES - // BAP - should skip if dup. - if (move_is_into_current_outfit) - { - LLAppearanceMgr::instance().addEnsembleLink(inv_cat); - } - else - { - LLPointer<LLInventoryCallback> cb = NULL; - const std::string empty_description = ""; - link_inventory_item( - gAgent.getID(), - cat_id, - mUUID, - inv_cat->getName(), - empty_description, - LLAssetType::AT_LINK_FOLDER, - cb); - } -#endif - } + // traverse category and add all contents to currently worn. + BOOL append = true; + LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append); } else if (move_is_into_outbox && !move_is_from_outbox) { @@ -2924,17 +2840,6 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) modifyOutfit(FALSE); return; } -#if SUPPORT_ENSEMBLES - else if ("wearasensemble" == action) - { - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - LLViewerInventoryCategory* cat = getCategory(); - if(!cat) return; - LLAppearanceMgr::instance().addEnsembleLink(cat,true); - return; - } -#endif else if ("addtooutfit" == action) { modifyOutfit(TRUE); @@ -3097,9 +3002,20 @@ LLUIImagePtr LLFolderBridge::getIconOverlay() const return NULL; } +std::string LLFolderBridge::getLabelSuffix() const +{ + static LLCachedControl<F32> folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime", 0.5f); + return mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay() + ? llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()) + : LLStringUtil::null; +} BOOL LLFolderBridge::renameItem(const std::string& new_name) { + + LLScrollOnRenameObserver *observer = new LLScrollOnRenameObserver(mUUID, mRoot); + gInventory.addObserver(observer); + rename_category(getInventoryModel(), mUUID, new_name); // return FALSE because we either notified observers (& therefore @@ -3337,28 +3253,9 @@ void LLFolderBridge::pasteLinkFromClipboard() dropToOutfit(item, move_is_into_current_outfit); } } - else if (LLInventoryCategory *cat = model->getCategory(object_id)) + else if (LLConstPointer<LLInventoryObject> obj = model->getObject(object_id)) { - const std::string empty_description = ""; - link_inventory_item( - gAgent.getID(), - cat->getUUID(), - parent_id, - cat->getName(), - empty_description, - LLAssetType::AT_LINK_FOLDER, - LLPointer<LLInventoryCallback>(NULL)); - } - else if (LLInventoryItem *item = model->getItem(object_id)) - { - link_inventory_item( - gAgent.getID(), - item->getLinkedUUID(), - parent_id, - item->getName(), - item->getDescription(), - LLAssetType::AT_LINK, - LLPointer<LLInventoryCallback>(NULL)); + link_inventory_object(parent_id, obj, LLPointer<LLInventoryCallback>(NULL)); } } // Change mode to paste for next paste @@ -3449,16 +3346,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items items.push_back(std::string("New Clothes")); items.push_back(std::string("New Body Parts")); } -#if SUPPORT_ENSEMBLES - // Changing folder types is an unfinished unsupported feature - // and can lead to unexpected behavior if enabled. - items.push_back(std::string("Change Type")); - const LLViewerInventoryCategory *cat = getCategory(); - if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType())) - { - disabled_items.push_back(std::string("Change Type")); - } -#endif getClipboardEntries(false, items, disabled_items, flags); } else @@ -3620,6 +3507,10 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& { disabled_items.push_back(std::string("Replace Outfit")); } + if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID)) + { + disabled_items.push_back(std::string("Add To Outfit")); + } items.push_back(std::string("Outfit Separator")); } } @@ -3950,14 +3841,7 @@ void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_c else { LLPointer<LLInventoryCallback> cb = NULL; - link_inventory_item( - gAgent.getID(), - inv_item->getLinkedUUID(), - mUUID, - inv_item->getName(), - inv_item->getDescription(), - LLAssetType::AT_LINK, - cb); + link_inventory_object(mUUID, LLConstPointer<LLInventoryObject>(inv_item), cb); } } diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index bc875e8f37..02134c7cc5 100755 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -252,7 +252,7 @@ public: LLFolderBridge(LLInventoryPanel* inventory, LLFolderView* root, const LLUUID& uuid) - : LLInvFVBridge(inventory, root, uuid), + : LLInvFVBridge(inventory, root, uuid), mCallingCards(FALSE), mWearables(FALSE), mIsLoading(false) @@ -276,6 +276,8 @@ public: virtual LLUIImagePtr getIconOverlay() const; static LLUIImagePtr getIcon(LLFolderType::EType preferred_type); + + virtual std::string getLabelSuffix() const; virtual BOOL renameItem(const std::string& new_name); diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 55904eb028..000eee3317 100755 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -938,7 +938,10 @@ void LLInventoryFilter::toParams(Params& params) const { params.filter_ops.types = getFilterObjectTypes(); params.filter_ops.category_types = getFilterCategoryTypes(); - params.filter_ops.wearable_types = getFilterWearableTypes(); + if (getFilterObjectTypes() & FILTERTYPE_WEARABLE) + { + params.filter_ops.wearable_types = getFilterWearableTypes(); + } params.filter_ops.date_range.min_date = getMinDate(); params.filter_ops.date_range.max_date = getMaxDate(); params.filter_ops.hours_ago = getHoursAgo(); @@ -957,7 +960,10 @@ void LLInventoryFilter::fromParams(const Params& params) setFilterObjectTypes(params.filter_ops.types); setFilterCategoryTypes(params.filter_ops.category_types); - setFilterWearableTypes(params.filter_ops.wearable_types); + if (params.filter_ops.wearable_types.isProvided()) + { + setFilterWearableTypes(params.filter_ops.wearable_types); + } setDateRange(params.filter_ops.date_range.min_date, params.filter_ops.date_range.max_date); setHoursAgo(params.filter_ops.hours_ago); setShowFolderState(params.filter_ops.show_folder_state); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index f16b9330be..1e7825a13e 100755 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -123,12 +123,9 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s return; } - LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat); - new_cat->rename(new_name); - new_cat->updateServer(FALSE); - model->updateCategory(new_cat); - - model->notifyObservers(); + LLSD updates; + updates["name"] = new_name; + update_inventory_category(cat_id, updates, NULL); } void copy_inventory_category(LLInventoryModel* model, @@ -741,6 +738,13 @@ bool LLIsOfAssetType::operator()(LLInventoryCategory* cat, LLInventoryItem* item return FALSE; } +bool LLIsValidItemLink::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ + LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); + if (!vitem) return false; + return (vitem->getActualType() == LLAssetType::AT_LINK && !vitem->getIsBrokenLink()); +} + bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { if(mType == LLAssetType::AT_CATEGORY) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index f1066a4dc9..6b3861aa79 100755 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -186,6 +186,13 @@ protected: LLAssetType::EType mType; }; +class LLIsValidItemLink : public LLInventoryCollectFunctor +{ +public: + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +}; + class LLIsTypeWithPermissions : public LLInventoryCollectFunctor { public: diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 7db1f29797..14ca0095ae 100755 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llinventorymodel.h" +#include "llaisapi.h" #include "llagent.h" #include "llagentwearables.h" #include "llappearancemgr.h" @@ -48,6 +49,7 @@ #include "llcallbacklist.h" #include "llvoavatarself.h" #include "llgesturemgr.h" +#include "llsdutil.h" #include <typeinfo> //#define DIFF_INVENTORY_FILES @@ -103,17 +105,7 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { S32 descendents_server = c->getDescendentCount(); - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - mModel->getDirectDescendentsOf( - c->getUUID(), - cats, - items); - S32 descendents_actual = 0; - if(cats && items) - { - descendents_actual = cats->size() + items->size(); - } + S32 descendents_actual = c->getViewerDescendentCount(); if(descendents_server == descendents_actual) { mCachedCatIDs.insert(c->getUUID()); @@ -135,6 +127,7 @@ LLInventoryModel gInventory; LLInventoryModel::LLInventoryModel() : mModifyMask(LLInventoryObserver::ALL), mChangedItemIDs(), + mBacklinkMMap(), mCategoryMap(), mItemMap(), mCategoryLock(), @@ -252,6 +245,23 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL return NULL; } +bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const +{ + LLInventoryObject *object = getObject(object_id); + while (object && object->getParentUUID().notNull()) + { + LLInventoryObject *parent_object = getObject(object->getParentUUID()); + if (!parent_object) + { + LL_WARNS() << "unable to trace topmost ancestor, missing item for uuid " << object->getParentUUID() << LL_ENDL; + return false; + } + object = parent_object; + } + result = object->getUUID(); + return true; +} + // Get the object by id. Returns NULL if not found. LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const { @@ -429,15 +439,12 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E } } -// findCategoryUUIDForType() returns the uuid of the category that -// specifies 'type' as what it defaults to containing. The category is -// not necessarily only for that type. *NOTE: This will create a new -// inventory category on the fly if one does not exist. -const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder/*, - bool find_in_library*/) +const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( + LLFolderType::EType preferred_type, + bool create_folder, + const LLUUID& root_id) { LLUUID rv = LLUUID::null; - const LLUUID &root_id = /*(find_in_library) ? gInventory.getLibraryRootFolderID() :*/ gInventory.getRootFolderID(); if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) { rv = root_id; @@ -453,14 +460,17 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType prefe { if(cats->at(i)->getPreferredType() == preferred_type) { - rv = cats->at(i)->getUUID(); - break; + const LLUUID& folder_id = cats->at(i)->getUUID(); + if (rv.isNull() || folder_id < rv) + { + rv = folder_id; + } } } } } - if(rv.isNull() && isInventoryUsable() && (create_folder && true/*!find_in_library*/)) + if(rv.isNull() && isInventoryUsable() && create_folder) { if(root_id.notNull()) { @@ -470,68 +480,49 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType prefe return rv; } -const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder) +// findCategoryUUIDForType() returns the uuid of the category that +// specifies 'type' as what it defaults to containing. The category is +// not necessarily only for that type. *NOTE: This will create a new +// inventory category on the fly if one does not exist. +const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder) { - LLUUID rv = LLUUID::null; - - const LLUUID &root_id = gInventory.getLibraryRootFolderID(); - if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) - { - rv = root_id; - } - else if (root_id.notNull()) - { - cat_array_t* cats = NULL; - cats = get_ptr_in_map(mParentChildCategoryTree, root_id); - if(cats) - { - S32 count = cats->size(); - for(S32 i = 0; i < count; ++i) - { - if(cats->at(i)->getPreferredType() == preferred_type) - { - rv = cats->at(i)->getUUID(); - break; - } - } - } - } + return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getRootFolderID()); +} - if(rv.isNull() && isInventoryUsable() && (create_folder && true/*!find_in_library*/)) - { - if(root_id.notNull()) - { - return createNewCategory(root_id, preferred_type, LLStringUtil::null); - } - } - return rv; +const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder) +{ + return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getLibraryRootFolderID()); } class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLCreateInventoryCategoryResponder); public: LLCreateInventoryCategoryResponder(LLInventoryModel* model, - void (*callback)(const LLSD&, void*), - void* user_data) : - mModel(model), - mCallback(callback), - mData(user_data) + boost::optional<inventory_func_type> callback): + mModel(model), + mCallback(callback) { } - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +protected: + virtual void httpFailure() { - LL_WARNS("InvAPI") << "CreateInventoryCategory failed [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS("InvAPI") << dumpResponse() << LL_ENDL; } - virtual void result(const LLSD& content) + virtual void httpSuccess() { //Server has created folder. - + const LLSD& content = getContent(); + if (!content.isMap() || !content.has("folder_id")) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLUUID category_id = content["folder_id"].asUUID(); - + LL_DEBUGS("Avatar") << ll_pretty_print_sd(content) << LL_ENDL; // Add the category to the internal representation LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory( category_id, @@ -544,17 +535,15 @@ public: LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); mModel->accountForUpdate(update); mModel->updateCategory(cat); - - if (mCallback && mData) + + if (mCallback) { - mCallback(content, mData); + mCallback.get()(category_id); } - } private: - void (*mCallback)(const LLSD&, void*); - void* mData; + boost::optional<inventory_func_type> mCallback; LLInventoryModel* mModel; }; @@ -565,8 +554,7 @@ private: LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, const std::string& pname, - void (*callback)(const LLSD&, void*), //Default to NULL - void* user_data) //Default to NULL + boost::optional<inventory_func_type> callback) { LLUUID id; @@ -593,33 +581,32 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); } - if ( callback && user_data ) //callback required for acked message. + LLViewerRegion* viewer_region = gAgent.getRegion(); + std::string url; + if ( viewer_region ) + url = viewer_region->getCapability("CreateInventoryCategory"); + + if (!url.empty() && callback.get_ptr()) { - LLViewerRegion* viewer_region = gAgent.getRegion(); - std::string url; - if ( viewer_region ) - url = viewer_region->getCapability("CreateInventoryCategory"); + //Let's use the new capability. - if (!url.empty()) - { - //Let's use the new capability. - - LLSD request, body; - body["folder_id"] = id; - body["parent_id"] = parent_id; - body["type"] = (LLSD::Integer) preferred_type; - body["name"] = name; - - request["message"] = "CreateInventoryCategory"; - request["payload"] = body; - - // viewer_region->getCapAPI().post(request); - LLHTTPClient::post( - url, - body, - new LLCreateInventoryCategoryResponder(this, callback, user_data) ); - return LLUUID::null; - } + LLSD request, body; + body["folder_id"] = id; + body["parent_id"] = parent_id; + body["type"] = (LLSD::Integer) preferred_type; + body["name"] = name; + + request["message"] = "CreateInventoryCategory"; + request["payload"] = body; + + LL_DEBUGS("Avatar") << "create category request: " << ll_pretty_print_sd(request) << LL_ENDL; + // viewer_region->getCapAPI().post(request); + LLHTTPClient::post( + url, + body, + new LLCreateInventoryCategoryResponder(this, callback) ); + + return LLUUID::null; } // Add the category to the internal representation @@ -646,6 +633,40 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, return id; } +// This is optimized for the case that we just want to know whether a +// category has any immediate children meeting a condition, without +// needing to recurse or build up any lists. +bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, + LLInventoryCollectFunctor& filter) +{ + LLInventoryModel::cat_array_t *cats; + LLInventoryModel::item_array_t *items; + getDirectDescendentsOf(cat_id, cats, items); + if (cats) + { + for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin(); + it != cats->end(); ++it) + { + if (filter(*it,NULL)) + { + return true; + } + } + } + if (items) + { + for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); + it != items->end(); ++it) + { + if (filter(NULL,*it)) + { + return true; + } + } + } + return false; +} + // Starting with the object specified, add its descendents to the // array provided, but do not add the inventory object specified by // id. There is no guaranteed order. Neither array will be erased @@ -677,8 +698,7 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, cat_array_t& cats, item_array_t& items, BOOL include_trash, - LLInventoryCollectFunctor& add, - BOOL follow_folder_links) + LLInventoryCollectFunctor& add) { // Start with categories if(!include_trash) @@ -705,36 +725,6 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, LLViewerInventoryItem* item = NULL; item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); - // Follow folder links recursively. Currently never goes more - // than one level deep (for current outfit support) - // Note: if making it fully recursive, need more checking against infinite loops. - if (follow_folder_links && item_array) - { - S32 count = item_array->size(); - for(S32 i = 0; i < count; ++i) - { - item = item_array->at(i); - if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER) - { - LLViewerInventoryCategory *linked_cat = item->getLinkedCategory(); - if (linked_cat && linked_cat->getPreferredType() != LLFolderType::FT_OUTFIT) - // BAP - was - // LLAssetType::lookupIsEnsembleCategoryType(linked_cat->getPreferredType())) - // Change back once ensemble typing is in place. - { - if(add(linked_cat,NULL)) - { - // BAP should this be added here? May not - // matter if it's only being used in current - // outfit traversal. - cats.push_back(LLPointer<LLViewerInventoryCategory>(linked_cat)); - } - collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, FALSE); - } - } - } - } - // Move onto items if(item_array) { @@ -756,26 +746,7 @@ void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) if (!obj || obj->getIsLinkType()) return; - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLLinkedItemIDMatches is_linked_item_match(object_id); - collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - item_array, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); - if (cat_array.empty() && item_array.empty()) - { - return; - } - for (LLInventoryModel::cat_array_t::iterator cat_iter = cat_array.begin(); - cat_iter != cat_array.end(); - cat_iter++) - { - LLViewerInventoryCategory *linked_cat = (*cat_iter); - addChangedMask(mask, linked_cat->getUUID()); - }; - + LLInventoryModel::item_array_t item_array = collectLinksTo(object_id); for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); iter != item_array.end(); iter++) @@ -803,17 +774,27 @@ LLViewerInventoryItem* LLInventoryModel::getLinkedItem(const LLUUID& object_id) return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL; } -LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID& id, - const LLUUID& start_folder_id) +LLInventoryModel::item_array_t LLInventoryModel::collectLinksTo(const LLUUID& id) { + // Get item list via collectDescendents (slow!) item_array_t items; - LLInventoryModel::cat_array_t cat_array; - LLLinkedItemIDMatches is_linked_item_match(id); - collectDescendentsIf((start_folder_id == LLUUID::null ? gInventory.getRootFolderID() : start_folder_id), - cat_array, - items, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); + const LLInventoryObject *obj = getObject(id); + // FIXME - should be as in next line, but this is causing a + // stack-smashing crash of cause TBD... check in the REBUILD code. + //if (obj && obj->getIsLinkType()) + if (!obj || obj->getIsLinkType()) + return items; + + std::pair<backlink_mmap_t::iterator, backlink_mmap_t::iterator> range = mBacklinkMMap.equal_range(id); + for (backlink_mmap_t::iterator it = range.first; it != range.second; ++it) + { + LLViewerInventoryItem *item = getItem(it->second); + if (item) + { + items.push_back(item); + } + } + return items; } @@ -830,9 +811,8 @@ bool LLInventoryModel::isInventoryUsable() const // Calling this method with an inventory item will either change an // existing item with a matching item_id, or will add the item to the // current inventory. -U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) +U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) { - U32 mask = LLInventoryObserver::NONE; if(item->getUUID().isNull()) { return mask; @@ -1011,7 +991,7 @@ LLInventoryModel::item_array_t* LLInventoryModel::getUnlockedItemArray(const LLU // Calling this method with an inventory category will either change // an existing item with the matching id, or it will add the category. -void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat) +void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 mask) { if(cat->getUUID().isNull()) { @@ -1028,7 +1008,6 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat) if(old_cat) { // We already have an old category, modify it's values - U32 mask = LLInventoryObserver::NONE; LLUUID old_parent_id = old_cat->getParentUUID(); LLUUID new_parent_id = cat->getParentUUID(); if(old_parent_id != new_parent_id) @@ -1182,8 +1161,199 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, notifyObservers(); } +void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLSD& update) +{ + LLTimer timer; + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) + { + dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update); + } + + AISUpdate ais_update(update); // parse update llsd into stuff to do. + ais_update.doUpdate(); // execute the updates in the appropriate order. + LL_INFOS() << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL; +} + +// Does not appear to be used currently. +void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version) +{ + U32 mask = LLInventoryObserver::NONE; + + LLPointer<LLViewerInventoryItem> item = gInventory.getItem(item_id); + LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << LL_ENDL; + if(item) + { + for (LLSD::map_const_iterator it = updates.beginMap(); + it != updates.endMap(); ++it) + { + if (it->first == "name") + { + LL_INFOS() << "Updating name from " << item->getName() << " to " << it->second.asString() << LL_ENDL; + item->rename(it->second.asString()); + mask |= LLInventoryObserver::LABEL; + } + else if (it->first == "desc") + { + LL_INFOS() << "Updating description from " << item->getActualDescription() + << " to " << it->second.asString() << LL_ENDL; + item->setDescription(it->second.asString()); + } + else + { + LL_ERRS() << "unhandled updates for field: " << it->first << LL_ENDL; + } + } + mask |= LLInventoryObserver::INTERNAL; + addChangedMask(mask, item->getUUID()); + if (update_parent_version) + { + // Descendent count is unchanged, but folder version incremented. + LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0); + accountForUpdate(up); + } + gInventory.notifyObservers(); // do we want to be able to make this optional? + } +} + +// Not used? +void LLInventoryModel::onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates) +{ + U32 mask = LLInventoryObserver::NONE; + + LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(cat_id); + LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << LL_ENDL; + if(cat) + { + for (LLSD::map_const_iterator it = updates.beginMap(); + it != updates.endMap(); ++it) + { + if (it->first == "name") + { + LL_INFOS() << "Updating name from " << cat->getName() << " to " << it->second.asString() << LL_ENDL; + cat->rename(it->second.asString()); + mask |= LLInventoryObserver::LABEL; + } + else + { + LL_ERRS() << "unhandled updates for field: " << it->first << LL_ENDL; + } + } + mask |= LLInventoryObserver::INTERNAL; + addChangedMask(mask, cat->getUUID()); + gInventory.notifyObservers(); // do we want to be able to make this optional? + } +} + +// Update model after descendents have been purged. +void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links) +{ + LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id); + if (cat.notNull()) + { + // do the cache accounting + S32 descendents = cat->getDescendentCount(); + if(descendents > 0) + { + LLInventoryModel::LLCategoryUpdate up(object_id, -descendents); + accountForUpdate(up); + } + + // we know that descendent count is 0, however since the + // accounting may actually not do an update, we should force + // it here. + cat->setDescendentCount(0); + + // unceremoniously remove anything we have locally stored. + LLInventoryModel::cat_array_t categories; + LLInventoryModel::item_array_t items; + collectDescendents(object_id, + categories, + items, + LLInventoryModel::INCLUDE_TRASH); + S32 count = items.size(); + + LLUUID uu_id; + for(S32 i = 0; i < count; ++i) + { + uu_id = items.at(i)->getUUID(); + + // This check prevents the deletion of a previously deleted item. + // This is necessary because deletion is not done in a hierarchical + // order. The current item may have been already deleted as a child + // of its deleted parent. + if (getItem(uu_id)) + { + deleteObject(uu_id, fix_broken_links); + } + } + + count = categories.size(); + // Slightly kludgy way to make sure categories are removed + // only after their child categories have gone away. + + // FIXME: Would probably make more sense to have this whole + // descendent-clearing thing be a post-order recursive + // function to get the leaf-up behavior automatically. + S32 deleted_count; + S32 total_deleted_count = 0; + do + { + deleted_count = 0; + for(S32 i = 0; i < count; ++i) + { + uu_id = categories.at(i)->getUUID(); + if (getCategory(uu_id)) + { + cat_array_t* cat_list = getUnlockedCatArray(uu_id); + if (!cat_list || (cat_list->size() == 0)) + { + deleteObject(uu_id, fix_broken_links); + deleted_count++; + } + } + } + total_deleted_count += deleted_count; + } + while (deleted_count > 0); + if (total_deleted_count != count) + { + LL_WARNS() << "Unexpected count of categories deleted, got " + << total_deleted_count << " expected " << count << LL_ENDL; + } + //gInventory.validate(); + } +} + +// Update model after an item is confirmed as removed from +// server. Works for categories or items. +void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool fix_broken_links, bool update_parent_version, bool do_notify_observers) +{ + LLPointer<LLInventoryObject> obj = getObject(object_id); + if(obj) + { + if (getCategory(object_id)) + { + // For category, need to delete/update all children first. + onDescendentsPurgedFromServer(object_id, fix_broken_links); + } + + + // From item/cat removeFromServer() + if (update_parent_version) + { + LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); + accountForUpdate(up); + } + + // From purgeObject() + LLPreview::hide(object_id); + deleteObject(object_id, fix_broken_links, do_notify_observers); + } +} + + // Delete a particular inventory object by ID. -void LLInventoryModel::deleteObject(const LLUUID& id) +void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, bool do_notify_observers) { LL_DEBUGS() << "LLInventoryModel::deleteObject()" << LL_ENDL; LLPointer<LLInventoryObject> obj = getObject(id); @@ -1214,157 +1384,64 @@ void LLInventoryModel::deleteObject(const LLUUID& id) item_list = getUnlockedItemArray(id); if(item_list) { + if (item_list->size()) + { + LL_WARNS() << "Deleting cat " << id << " while it still has child items" << LL_ENDL; + } delete item_list; mParentChildItemTree.erase(id); } cat_list = getUnlockedCatArray(id); if(cat_list) { + if (cat_list->size()) + { + LL_WARNS() << "Deleting cat " << id << " while it still has child cats" << LL_ENDL; + } delete cat_list; mParentChildCategoryTree.erase(id); } addChangedMask(LLInventoryObserver::REMOVE, id); - obj = NULL; // delete obj - updateLinkedObjectsFromPurge(id); - gInventory.notifyObservers(); -} -// Delete a particular inventory item by ID, and remove it from the server. -void LLInventoryModel::purgeObject(const LLUUID &id) -{ - LL_DEBUGS() << "LLInventoryModel::purgeObject() [ id: " << id << " ] " << LL_ENDL; - LLPointer<LLInventoryObject> obj = getObject(id); - if(obj) + bool is_link_type = obj->getIsLinkType(); + if (is_link_type) + { + removeBacklinkInfo(obj->getUUID(), obj->getLinkedUUID()); + } + + // Can't have links to links, so there's no need for this update + // if the item removed is a link. Can also skip if source of the + // update is getting broken link info separately. + obj = NULL; // delete obj + if (fix_broken_links && !is_link_type) + { + updateLinkedObjectsFromPurge(id); + } + if (do_notify_observers) { - obj->removeFromServer(); - LLPreview::hide(id); - deleteObject(id); + notifyObservers(); } } void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id) { - LLInventoryModel::item_array_t item_array = collectLinkedItems(baseobj_id); + LLInventoryModel::item_array_t item_array = collectLinksTo(baseobj_id); // REBUILD is expensive, so clear the current change list first else // everything else on the changelist will also get rebuilt. - gInventory.notifyObservers(); - for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); - iter != item_array.end(); - iter++) + if (item_array.size() > 0) { - const LLViewerInventoryItem *linked_item = (*iter); - const LLUUID &item_id = linked_item->getUUID(); - if (item_id == baseobj_id) continue; - addChangedMask(LLInventoryObserver::REBUILD, item_id); - } - gInventory.notifyObservers(); -} - -// This is a method which collects the descendents of the id -// provided. If the category is not found, no action is -// taken. This method goes through the long winded process of -// cancelling any calling cards, removing server representation of -// folders, items, etc in a fairly efficient manner. -void LLInventoryModel::purgeDescendentsOf(const LLUUID& id) -{ - LLPointer<LLViewerInventoryCategory> cat = getCategory(id); - if (cat.notNull()) - { - if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode()) - { - // Something on the clipboard is in "cut mode" and needs to be preserved - LL_INFOS() << "LLInventoryModel::purgeDescendentsOf " << cat->getName() - << " iterate and purge non hidden items" << LL_ENDL; - cat_array_t* categories; - item_array_t* items; - // Get the list of direct descendants in that category passed as argument - getDirectDescendentsOf(id, categories, items); - std::vector<LLUUID> list_uuids; - // Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently) - // Note: we need to do that shallow copy as purging things will invalidate the categories or items lists - for (cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) - { - list_uuids.push_back((*it)->getUUID()); - } - for (item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) - { - list_uuids.push_back((*it)->getUUID()); - } - // Iterate through the list and only purge the UUIDs that are not on the clipboard - for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) - { - if (!LLClipboard::instance().isOnClipboard(*it)) - { - purgeObject(*it); - } - } - } - else + gInventory.notifyObservers(); + for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) { - // Fast purge - // do the cache accounting - LL_INFOS() << "LLInventoryModel::purgeDescendentsOf " << cat->getName() - << LL_ENDL; - S32 descendents = cat->getDescendentCount(); - if(descendents > 0) - { - LLCategoryUpdate up(id, -descendents); - accountForUpdate(up); - } - - // we know that descendent count is 0, however since the - // accounting may actually not do an update, we should force - // it here. - cat->setDescendentCount(0); - - // send it upstream - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("PurgeInventoryDescendents"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("InventoryData"); - msg->addUUID("FolderID", id); - gAgent.sendReliableMessage(); - - // unceremoniously remove anything we have locally stored. - cat_array_t categories; - item_array_t items; - collectDescendents(id, - categories, - items, - INCLUDE_TRASH); - S32 count = items.size(); - - item_map_t::iterator item_map_end = mItemMap.end(); - cat_map_t::iterator cat_map_end = mCategoryMap.end(); - LLUUID uu_id; - - for(S32 i = 0; i < count; ++i) - { - uu_id = items.at(i)->getUUID(); - - // This check prevents the deletion of a previously deleted item. - // This is necessary because deletion is not done in a hierarchical - // order. The current item may have been already deleted as a child - // of its deleted parent. - if (mItemMap.find(uu_id) != item_map_end) - { - deleteObject(uu_id); - } - } - - count = categories.size(); - for(S32 i = 0; i < count; ++i) - { - uu_id = categories.at(i)->getUUID(); - if (mCategoryMap.find(uu_id) != cat_map_end) - { - deleteObject(uu_id); - } - } + const LLViewerInventoryItem *linked_item = (*iter); + const LLUUID &item_id = linked_item->getUUID(); + if (item_id == baseobj_id) continue; + addChangedMask(LLInventoryObserver::REBUILD, item_id); } + gInventory.notifyObservers(); } } @@ -1419,6 +1496,7 @@ void LLInventoryModel::notifyObservers() mModifyMask = LLInventoryObserver::NONE; mChangedItemIDs.clear(); + mAddedItemIDs.clear(); mIsNotifyObservers = FALSE; } @@ -1432,25 +1510,49 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) // (which is in the process of processing the list of items marked for change). // This means the change may fail to be processed. LL_WARNS() << "Adding changed mask within notify observers! Change will likely be lost." << LL_ENDL; + LLViewerInventoryItem *item = getItem(referent); + if (item) + { + LL_WARNS() << "Item " << item->getName() << LL_ENDL; + } + else + { + LLViewerInventoryCategory *cat = getCategory(referent); + if (cat) + { + LL_WARNS() << "Category " << cat->getName() << LL_ENDL; + } + } } mModifyMask |= mask; if (referent.notNull()) { mChangedItemIDs.insert(referent); - } + + if (mask & LLInventoryObserver::ADD) + { + mAddedItemIDs.insert(referent); + } - // Update all linked items. Starting with just LABEL because I'm - // not sure what else might need to be accounted for this. - if (mModifyMask & LLInventoryObserver::LABEL) - { - addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); + // Update all linked items. Starting with just LABEL because I'm + // not sure what else might need to be accounted for this. + if (mask & LLInventoryObserver::LABEL) + { + addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); + } } } // If we get back a normal response, handle it here -void LLInventoryModel::fetchInventoryResponder::result(const LLSD& content) -{ +void LLInventoryModel::fetchInventoryResponder::httpSuccess() +{ + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } start_new_inventory_observer(); /*LLUUID agent_id; @@ -1471,8 +1573,8 @@ void LLInventoryModel::fetchInventoryResponder::result(const LLSD& content) LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; titem->unpackMessage(content["items"][i]); - LL_DEBUGS() << "LLInventoryModel::messageUpdateCore() item id:" - << titem->getUUID() << LL_ENDL; + LL_DEBUGS() << "LLInventoryModel::fetchInventoryResponder item id: " + << titem->getUUID() << LL_ENDL; items.push_back(titem); // examine update for changes. LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); @@ -1509,9 +1611,9 @@ void LLInventoryModel::fetchInventoryResponder::result(const LLSD& content) } //If we get back an error (not found, etc...), handle it here -void LLInventoryModel::fetchInventoryResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLInventoryModel::fetchInventoryResponder::httpFailure() { - LL_WARNS() << "fetchInventory error [status:" << status << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; gInventory.notifyObservers(); } @@ -1603,6 +1705,47 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) } } +bool LLInventoryModel::hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const +{ + std::pair <backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range; + range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) + { + if (it->second == link_id) + { + return true; + } + } + return false; +} + +void LLInventoryModel::addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) +{ + if (!hasBacklinkInfo(link_id, target_id)) + { + mBacklinkMMap.insert(std::make_pair(target_id, link_id)); + } +} + +void LLInventoryModel::removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) +{ + std::pair <backlink_mmap_t::iterator, backlink_mmap_t::iterator> range; + range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::iterator it = range.first; it != range.second; ) + { + if (it->second == link_id) + { + backlink_mmap_t::iterator delete_it = it; // iterator will be invalidated by erase. + ++it; + mBacklinkMMap.erase(delete_it); + } + else + { + ++it; + } + } +} + void LLInventoryModel::addItem(LLViewerInventoryItem* item) { llassert(item); @@ -1624,7 +1767,13 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) { LL_INFOS() << "Adding broken link [ name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL; } - + if (item->getIsLinkType()) + { + // Add back-link from linked-to UUID. + const LLUUID& link_id = item->getUUID(); + const LLUUID& target_id = item->getLinkedUUID(); + addBacklinkInfo(link_id, target_id); + } mItemMap[item->getUUID()] = item; } } @@ -1643,6 +1792,7 @@ void LLInventoryModel::empty() mParentChildItemTree.end(), DeletePairedPointer()); mParentChildItemTree.clear(); + mBacklinkMMap.clear(); // forget all backlink information. mCategoryMap.clear(); // remove all references (should delete entries) mItemMap.clear(); // remove all references (should delete entries) mLastItem = NULL; @@ -1654,37 +1804,34 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const LLViewerInventoryCategory* cat = getCategory(update.mCategoryID); if(cat) { - bool accounted = false; S32 version = cat->getVersion(); if(version != LLViewerInventoryCategory::VERSION_UNKNOWN) { S32 descendents_server = cat->getDescendentCount(); - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - getDirectDescendentsOf(update.mCategoryID, cats, items); - S32 descendents_actual = 0; - if(cats && items) - { - descendents_actual = cats->size() + items->size(); - } + S32 descendents_actual = cat->getViewerDescendentCount(); if(descendents_server == descendents_actual) { - accounted = true; descendents_actual += update.mDescendentDelta; cat->setDescendentCount(descendents_actual); cat->setVersion(++version); - LL_DEBUGS() << "accounted: '" << cat->getName() << "' " - << version << " with " << descendents_actual - << " descendents." << LL_ENDL; + LL_DEBUGS("Inventory") << "accounted: '" << cat->getName() << "' " + << version << " with " << descendents_actual + << " descendents." << LL_ENDL; + } + else + { + // Error condition, this means that the category did not register that + // it got new descendents (perhaps because it is still being loaded) + // which means its descendent count will be wrong. + LL_WARNS() << "Accounting failed for '" << cat->getName() << "' version:" + << version << " due to mismatched descendent count: server == " + << descendents_server << ", viewer == " << descendents_actual << LL_ENDL; } } - if(!accounted) + else { - // Error condition, this means that the category did not register that - // it got new descendents (perhaps because it is still being loaded) - // which means its descendent count will be wrong. - LL_WARNS() << "Accounting failed for '" << cat->getName() << "' version:" - << version << LL_ENDL; + LL_WARNS() << "Accounting failed for '" << cat->getName() << "' version: unknown (" + << version << ")" << LL_ENDL; } } else @@ -1718,47 +1865,6 @@ void LLInventoryModel::accountForUpdate( } } - -/* -void LLInventoryModel::incrementCategoryVersion(const LLUUID& category_id) -{ - LLViewerInventoryCategory* cat = getCategory(category_id); - if(cat) - { - S32 version = cat->getVersion(); - if(LLViewerInventoryCategory::VERSION_UNKNOWN != version) - { - cat->setVersion(version + 1); - LL_INFOS() << "IncrementVersion: " << cat->getName() << " " - << cat->getVersion() << LL_ENDL; - } - else - { - LL_INFOS() << "Attempt to increment version when unknown: " - << category_id << LL_ENDL; - } - } - else - { - LL_INFOS() << "Attempt to increment category: " << category_id << LL_ENDL; - } -} -void LLInventoryModel::incrementCategorySetVersion( - const std::set<LLUUID>& categories) -{ - if(!categories.empty()) - { - std::set<LLUUID>::const_iterator it = categories.begin(); - std::set<LLUUID>::const_iterator end = categories.end(); - for(; it != end; ++it) - { - incrementCategoryVersion(*it); - } - } -} -*/ - - LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren( const LLUUID& cat_id) const { @@ -1799,14 +1905,7 @@ bool LLInventoryModel::isCategoryComplete(const LLUUID& cat_id) const if(cat && (cat->getVersion()!=LLViewerInventoryCategory::VERSION_UNKNOWN)) { S32 descendents_server = cat->getDescendentCount(); - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - getDirectDescendentsOf(cat_id, cats, items); - S32 descendents_actual = 0; - if(cats && items) - { - descendents_actual = cats->size() + items->size(); - } + S32 descendents_actual = cat->getViewerDescendentCount(); if(descendents_server == descendents_actual) { return true; @@ -2144,11 +2243,16 @@ void LLInventoryModel::buildParentChildMap() S32 count = cats.size(); S32 i; S32 lost = 0; + cat_array_t lost_cats; for(i = 0; i < count; ++i) { LLViewerInventoryCategory* cat = cats.at(i); catsp = getUnlockedCatArray(cat->getParentUUID()); - if(catsp) + if(catsp && + // Only the two root folders should be children of null. + // Others should go to lost & found. + (cat->getParentUUID().notNull() || + cat->getPreferredType() == LLFolderType::FT_ROOT_INVENTORY )) { catsp->push_back(cat); } @@ -2160,35 +2264,10 @@ void LLInventoryModel::buildParentChildMap() // implement it, we would need a set or map of uuid pairs // which would be (folder_id, new_parent_id) to be sent up // to the server. - LL_INFOS() << "Lost categroy: " << cat->getUUID() << " - " - << cat->getName() << LL_ENDL; + LL_INFOS() << "Lost category: " << cat->getUUID() << " - " + << cat->getName() << LL_ENDL; ++lost; - // plop it into the lost & found. - LLFolderType::EType pref = cat->getPreferredType(); - if(LLFolderType::FT_NONE == pref) - { - cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); - } - else if(LLFolderType::FT_ROOT_INVENTORY == pref) - { - // it's the root - cat->setParent(LLUUID::null); - } - else - { - // it's a protected folder. - cat->setParent(gInventory.getRootFolderID()); - } - cat->updateServer(TRUE); - catsp = getUnlockedCatArray(cat->getParentUUID()); - if(catsp) - { - catsp->push_back(cat); - } - else - { - LL_WARNS() << "Lost and found Not there!!" << LL_ENDL; - } + lost_cats.push_back(cat); } } if(lost) @@ -2196,6 +2275,42 @@ void LLInventoryModel::buildParentChildMap() LL_WARNS() << "Found " << lost << " lost categories." << LL_ENDL; } + // Do moves in a separate pass to make sure we've properly filed + // the FT_LOST_AND_FOUND category before we try to find its UUID. + for(i = 0; i<lost_cats.size(); ++i) + { + LLViewerInventoryCategory *cat = lost_cats.at(i); + + // plop it into the lost & found. + LLFolderType::EType pref = cat->getPreferredType(); + if(LLFolderType::FT_NONE == pref) + { + cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); + } + else if(LLFolderType::FT_ROOT_INVENTORY == pref) + { + // it's the root + cat->setParent(LLUUID::null); + } + else + { + // it's a protected folder. + cat->setParent(gInventory.getRootFolderID()); + } + // FIXME note that updateServer() fails with protected + // types, so this will not work as intended in that case. + cat->updateServer(TRUE); + catsp = getUnlockedCatArray(cat->getParentUUID()); + if(catsp) + { + catsp->push_back(cat); + } + else + { + LL_WARNS() << "Lost and found Not there!!" << LL_ENDL; + } + } + const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, FALSE) != LLUUID::null); sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); @@ -2228,7 +2343,7 @@ void LLInventoryModel::buildParentChildMap() else { LL_INFOS() << "Lost item: " << item->getUUID() << " - " - << item->getName() << LL_ENDL; + << item->getName() << LL_ENDL; ++lost; // plop it into the lost & found. // @@ -2319,11 +2434,25 @@ void LLInventoryModel::buildParentChildMap() // The inv tree is built. mIsAgentInvUsable = true; - LL_INFOS() << "Inventory initialized, notifying observers" << LL_ENDL; - addChangedMask(LLInventoryObserver::ALL, LLUUID::null); - notifyObservers(); + // notifyObservers() has been moved to + // llstartup/idle_startup() after this func completes. + // Allows some system categories to be created before + // observers start firing. } } + + if (!gInventory.validate()) + { + LL_WARNS() << "model failed validity check!" << LL_ENDL; + } +} + +void LLInventoryModel::createCommonSystemCategories() +{ + gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH,true); + gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true); + gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD,true); + gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS,true); } struct LLUUIDAndName @@ -2547,7 +2676,7 @@ void LLInventoryModel::registerCallbacks(LLMessageSystem* msg) void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, void**) { // do accounting and highlight new items if they arrive - if (gInventory.messageUpdateCore(msg, true)) + if (gInventory.messageUpdateCore(msg, true, LLInventoryObserver::UPDATE_CREATE)) { U32 callback_id; LLUUID item_id; @@ -2567,7 +2696,7 @@ void LLInventoryModel::processFetchInventoryReply(LLMessageSystem* msg, void**) } -bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account) +bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32 mask) { //make sure our added inventory observer is active start_new_inventory_observer(); @@ -2621,10 +2750,14 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account) } U32 changes = 0x0; + if (account) + { + mask |= LLInventoryObserver::CREATE; + } //as above, this loop never seems to loop more than once per call for (item_array_t::iterator it = items.begin(); it != items.end(); ++it) { - changes |= gInventory.updateItem(*it); + changes |= gInventory.updateItem(*it, mask); } gInventory.notifyObservers(); gViewerWindow->getWindow()->decBusyCount(); @@ -2862,7 +2995,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) LLUUID tid; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid); #ifndef LL_RELEASE_FOR_DOWNLOAD - LL_INFOS() << "Bulk inventory: " << tid << LL_ENDL; + LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << LL_ENDL; #endif update_map_t update; @@ -2874,9 +3007,9 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID()); tfolder->unpackMessage(msg, _PREHASH_FolderData, i); - LL_INFOS() << "unpacked folder '" << tfolder->getName() << "' (" - << tfolder->getUUID() << ") in " << tfolder->getParentUUID() - << LL_ENDL; + LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' (" + << tfolder->getUUID() << ") in " << tfolder->getParentUUID() + << LL_ENDL; if(tfolder->getUUID().notNull()) { folders.push_back(tfolder); @@ -2916,8 +3049,8 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; titem->unpackMessage(msg, _PREHASH_ItemData, i); - LL_INFOS() << "unpacked item '" << titem->getName() << "' in " - << titem->getParentUUID() << LL_ENDL; + LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in " + << titem->getParentUUID() << LL_ENDL; U32 callback_id; msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id); if(titem->getUUID().notNull() ) // && callback_id.notNull() ) @@ -2994,6 +3127,9 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) InventoryCallbackInfo cbinfo = (*inv_it); gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID); } + + //gInventory.validate(); + // Don't show the inventory. We used to call showAgentInventory here. //LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); //if(view) @@ -3052,7 +3188,8 @@ void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**) // If the item has already been added (e.g. from link prefetch), then it doesn't need to be re-added. if (gInventory.getItem(titem->getUUID())) { - LL_DEBUGS() << "Skipping prefetched item [ Name: " << titem->getName() << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << LL_ENDL; + LL_DEBUGS("Inventory") << "Skipping prefetched item [ Name: " << titem->getName() + << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << LL_ENDL; continue; } gInventory.updateItem(titem); @@ -3138,8 +3275,7 @@ bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const L if (option == 0) // YES { const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purgeDescendentsOf(folder_id); - notifyObservers(); + purge_descendents_of(folder_id, NULL); } return false; } @@ -3154,8 +3290,7 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT else { const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purgeDescendentsOf(folder_id); - notifyObservers(); + purge_descendents_of(folder_id, NULL); } } @@ -3442,6 +3577,305 @@ void LLInventoryModel::dumpInventory() const LL_INFOS() << "\n**********************\nEnd Inventory Dump" << LL_ENDL; } +// Do various integrity checks on model, logging issues found and +// returning an overall good/bad flag. +bool LLInventoryModel::validate() const +{ + bool valid = true; + + if (getRootFolderID().isNull()) + { + LL_WARNS() << "no root folder id" << LL_ENDL; + valid = false; + } + if (getLibraryRootFolderID().isNull()) + { + LL_WARNS() << "no root folder id" << LL_ENDL; + valid = false; + } + + if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) + { + // ParentChild should be one larger because of the special entry for null uuid. + LL_INFOS() << "unexpected sizes: cat map size " << mCategoryMap.size() + << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; + valid = false; + } + S32 cat_lock = 0; + S32 item_lock = 0; + S32 desc_unknown_count = 0; + S32 version_unknown_count = 0; + for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + { + const LLUUID& cat_id = cit->first; + const LLViewerInventoryCategory *cat = cit->second; + if (!cat) + { + LL_WARNS() << "invalid cat" << LL_ENDL; + valid = false; + continue; + } + if (cat_id != cat->getUUID()) + { + LL_WARNS() << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; + valid = false; + } + + if (cat->getParentUUID().isNull()) + { + if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) + { + LL_WARNS() << "cat " << cat_id << " has no parent, but is not root (" + << getRootFolderID() << ") or library root (" + << getLibraryRootFolderID() << ")" << LL_ENDL; + } + } + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(cat_id,cats,items); + if (!cats || !items) + { + LL_WARNS() << "invalid direct descendents for " << cat_id << LL_ENDL; + valid = false; + continue; + } + if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) + { + desc_unknown_count++; + } + else if (cats->size() + items->size() != cat->getDescendentCount()) + { + LL_WARNS() << "invalid desc count for " << cat_id << " name [" << cat->getName() + << "] parent " << cat->getParentUUID() + << " cached " << cat->getDescendentCount() + << " expected " << cats->size() << "+" << items->size() + << "=" << cats->size() +items->size() << LL_ENDL; + valid = false; + } + if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + version_unknown_count++; + } + if (mCategoryLock.count(cat_id)) + { + cat_lock++; + } + if (mItemLock.count(cat_id)) + { + item_lock++; + } + for (S32 i = 0; i<items->size(); i++) + { + LLViewerInventoryItem *item = items->at(i); + + if (!item) + { + LL_WARNS() << "null item at index " << i << " for cat " << cat_id << LL_ENDL; + valid = false; + continue; + } + + const LLUUID& item_id = item->getUUID(); + + if (item->getParentUUID() != cat_id) + { + LL_WARNS() << "wrong parent for " << item_id << " found " + << item->getParentUUID() << " expected " << cat_id + << LL_ENDL; + valid = false; + } + + + // Entries in items and mItemMap should correspond. + item_map_t::const_iterator it = mItemMap.find(item_id); + if (it == mItemMap.end()) + { + LL_WARNS() << "item " << item_id << " found as child of " + << cat_id << " but not in top level mItemMap" << LL_ENDL; + valid = false; + } + else + { + LLViewerInventoryItem *top_item = it->second; + if (top_item != item) + { + LL_WARNS() << "item mismatch, item_id " << item_id + << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; + } + } + + // Topmost ancestor should be root or library. + LLUUID topmost_ancestor_id; + bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); + if (!found) + { + LL_WARNS() << "unable to find topmost ancestor for " << item_id << LL_ENDL; + valid = false; + } + else + { + if (topmost_ancestor_id != getRootFolderID() && + topmost_ancestor_id != getLibraryRootFolderID()) + { + LL_WARNS() << "unrecognized top level ancestor for " << item_id + << " got " << topmost_ancestor_id + << " expected " << getRootFolderID() + << " or " << getLibraryRootFolderID() << LL_ENDL; + valid = false; + } + } + } + + // Does this category appear as a child of its supposed parent? + const LLUUID& parent_id = cat->getParentUUID(); + if (!parent_id.isNull()) + { + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(parent_id,cats,items); + if (!cats) + { + LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; + valid = false; + } + else + { + bool found = false; + for (S32 i = 0; i<cats->size(); i++) + { + LLViewerInventoryCategory *kid_cat = cats->at(i); + if (kid_cat == cat) + { + found = true; + break; + } + } + if (!found) + { + LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; + } + } + } + } + + for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + { + const LLUUID& item_id = iit->first; + LLViewerInventoryItem *item = iit->second; + if (item->getUUID() != item_id) + { + LL_WARNS() << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; + valid = false; + } + + const LLUUID& parent_id = item->getParentUUID(); + if (parent_id.isNull()) + { + LL_WARNS() << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; + } + else + { + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(parent_id,cats,items); + if (!items) + { + LL_WARNS() << "item " << item_id << " name [" << item->getName() + << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; + } + else + { + bool found = false; + for (S32 i=0; i<items->size(); ++i) + { + if (items->at(i) == item) + { + found = true; + break; + } + } + if (!found) + { + LL_WARNS() << "item " << item_id << " name [" << item->getName() + << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; + } + } + + } + // Link checking + if (item->getIsLinkType()) + { + const LLUUID& link_id = item->getUUID(); + const LLUUID& target_id = item->getLinkedUUID(); + LLViewerInventoryItem *target_item = getItem(target_id); + LLViewerInventoryCategory *target_cat = getCategory(target_id); + // Linked-to UUID should have back reference to this link. + if (!hasBacklinkInfo(link_id, target_id)) + { + LL_WARNS() << "link " << item->getUUID() << " type " << item->getActualType() + << " missing backlink info at target_id " << target_id + << LL_ENDL; + } + // Links should have referents. + if (item->getActualType() == LLAssetType::AT_LINK && !target_item) + { + LL_WARNS() << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) + { + LL_WARNS() << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + if (target_item && target_item->getIsLinkType()) + { + LL_WARNS() << "link " << item->getName() << " references a link item " + << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; + } + + // Links should not have backlinks. + std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id); + if (range.first != range.second) + { + LL_WARNS() << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; + } + } + else + { + // Check the backlinks of a non-link item. + const LLUUID& target_id = item->getUUID(); + std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) + { + const LLUUID& link_id = it->second; + LLViewerInventoryItem *link_item = getItem(link_id); + if (!link_item || !link_item->getIsLinkType()) + { + LL_WARNS() << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; + } + } + } + } + + if (cat_lock > 0 || item_lock > 0) + { + LL_INFOS() << "Found locks on some categories: sub-cat arrays " + << cat_lock << ", item arrays " << item_lock << LL_ENDL; + } + if (desc_unknown_count != 0) + { + LL_INFOS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL; + } + if (version_unknown_count != 0) + { + LL_INFOS() << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; + } + + LL_INFOS() << "Validate done, valid = " << (U32) valid << LL_ENDL; + + return valid; +} + ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 7dd7ac8e9a..2e957809be 100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -33,6 +33,7 @@ #include "llcurl.h" #include "lluuid.h" #include "llpermissionsflags.h" +#include "llviewerinventory.h" #include "llstring.h" #include "llmd5.h" #include <map> @@ -44,14 +45,9 @@ class LLInventoryObserver; class LLInventoryObject; class LLInventoryItem; class LLInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory; class LLMessageSystem; class LLInventoryCollectFunctor; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // LLInventoryModel // @@ -80,11 +76,12 @@ public: class fetchInventoryResponder : public LLCurl::Responder { + LOG_CLASS(fetchInventoryResponder); public: fetchInventoryResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); protected: + virtual void httpSuccess(); + virtual void httpFailure(); LLSD mRequestSD; }; @@ -137,6 +134,8 @@ public: // during authentication. Returns true if everything parsed. bool loadSkeleton(const LLSD& options, const LLUUID& owner_id); void buildParentChildMap(); // brute force method to rebuild the entire parent-child relations + void createCommonSystemCategories(); + // Call on logout to save a terse representation. void cache(const LLUUID& parent_folder_id, const LLUUID& agent_id); private: @@ -155,6 +154,15 @@ private: parent_cat_map_t mParentChildCategoryTree; parent_item_map_t mParentChildItemTree; + // Track links to items and categories. We do not store item or + // category pointers here, because broken links are also supported. + typedef std::multimap<LLUUID, LLUUID> backlink_mmap_t; + backlink_mmap_t mBacklinkMMap; // key = target_id: ID of item, values = link_ids: IDs of item or folder links referencing it. + // For internal use only + bool hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const; + void addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id); + void removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id); + //-------------------------------------------------------------------- // Login //-------------------------------------------------------------------- @@ -203,6 +211,9 @@ public: EXCLUDE_TRASH = FALSE, INCLUDE_TRASH = TRUE }; + // Simpler existence test if matches don't actually need to be collected. + bool hasMatchingDirectDescendent(const LLUUID& cat_id, + LLInventoryCollectFunctor& filter); void collectDescendents(const LLUUID& id, cat_array_t& categories, item_array_t& items, @@ -211,22 +222,27 @@ public: cat_array_t& categories, item_array_t& items, BOOL include_trash, - LLInventoryCollectFunctor& add, - BOOL follow_folder_links = FALSE); + LLInventoryCollectFunctor& add); // Collect all items in inventory that are linked to item_id. // Assumes item_id is itself not a linked item. - item_array_t collectLinkedItems(const LLUUID& item_id, - const LLUUID& start_folder_id = LLUUID::null); - + item_array_t collectLinksTo(const LLUUID& item_id); // Check if one object has a parent chain up to the category specified by UUID. BOOL isObjectDescendentOf(const LLUUID& obj_id, const LLUUID& cat_id) const; + // Follow parent chain to the top. + bool getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const; + //-------------------------------------------------------------------- // Find //-------------------------------------------------------------------- public: + const LLUUID findCategoryUUIDForTypeInRoot( + LLFolderType::EType preferred_type, + bool create_folder, + const LLUUID& root_id); + // Returns the uuid of the category that specifies 'type' as what it // defaults to containing. The category is not necessarily only for that type. // NOTE: If create_folder is true, this will create a new inventory category @@ -296,7 +312,7 @@ public: // NOTE: In usage, you will want to perform cache accounting // operations in LLInventoryModel::accountForUpdate() or // LLViewerInventoryItem::updateServer() before calling this method. - U32 updateItem(const LLViewerInventoryItem* item); + U32 updateItem(const LLViewerInventoryItem* item, U32 mask = 0); // Change an existing item with the matching id or add // the category. No notifcation will be sent to observers. This @@ -305,7 +321,7 @@ public: // NOTE: In usage, you will want to perform cache accounting // operations in accountForUpdate() or LLViewerInventoryCategory:: // updateServer() before calling this method. - void updateCategory(const LLViewerInventoryCategory* cat); + void updateCategory(const LLViewerInventoryCategory* cat, U32 mask = 0); // Move the specified object id to the specified category and // update the internal structures. No cache accounting, @@ -326,11 +342,31 @@ public: // Delete //-------------------------------------------------------------------- public: + + // Update model after an AISv3 update received for any operation. + void onAISUpdateReceived(const std::string& context, const LLSD& update); + + // Update model after an item is confirmed as removed from + // server. Works for categories or items. + void onObjectDeletedFromServer(const LLUUID& item_id, + bool fix_broken_links = true, + bool update_parent_version = true, + bool do_notify_observers = true); + + // Update model after all descendents removed from server. + void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true); + + // Update model after an existing item gets updated on server. + void onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version); + + // Update model after an existing category gets updated on server. + void onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates); + // Delete a particular inventory object by ID. Will purge one // object from the internal data structures, maintaining a // consistent internal state. No cache accounting, observer // notification, or server update is performed. - void deleteObject(const LLUUID& id); + void deleteObject(const LLUUID& id, bool fix_broken_links = true, bool do_notify_observers = true); /// move Item item_id to Trash void removeItem(const LLUUID& item_id); /// move Category category_id to Trash @@ -338,17 +374,6 @@ public: /// removeItem() or removeCategory(), whichever is appropriate void removeObject(const LLUUID& object_id); - // Delete a particular inventory object by ID, and delete it from - // the server. Also updates linked items. - void purgeObject(const LLUUID& id); - - // Collects and purges the descendants of the id - // provided. If the category is not found, no action is - // taken. This method goes through the long winded process of - // removing server representation of folders and items while doing - // cache accounting in a fairly efficient manner. This method does - // not notify observers (though maybe it should...) - void purgeDescendentsOf(const LLUUID& id); protected: void updateLinkedObjectsFromPurge(const LLUUID& baseobj_id); @@ -383,8 +408,7 @@ public: LLUUID createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, const std::string& name, - void (*callback)(const LLSD&, void*) = NULL, - void* user_data = NULL ); + boost::optional<inventory_func_type> callback = boost::optional<inventory_func_type>()); protected: // Internal methods that add inventory and make sure that all of // the internal data structures are consistent. These methods @@ -461,7 +485,9 @@ public: // been changed 'under the hood', but outside the control of the // inventory. The next notify will include that notification. void addChangedMask(U32 mask, const LLUUID& referent); + const changed_items_t& getChangedIDs() const { return mChangedItemIDs; } + const changed_items_t& getAddedIDs() const { return mAddedItemIDs; } protected: // Updates all linked items pointing to this id. void addChangedMaskForLinks(const LLUUID& object_id, U32 mask); @@ -472,6 +498,8 @@ private: // Variables used to track what has changed since the last notify. U32 mModifyMask; changed_items_t mChangedItemIDs; + changed_items_t mAddedItemIDs; + //-------------------------------------------------------------------- // Observers @@ -533,7 +561,7 @@ public: static void processMoveInventoryItem(LLMessageSystem* msg, void**); static void processFetchInventoryReply(LLMessageSystem* msg, void**); protected: - bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting); + bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting, U32 mask = 0x0); //-------------------------------------------------------------------- // Locks @@ -555,6 +583,7 @@ private: //-------------------------------------------------------------------- public: void dumpInventory() const; + bool validate() const; /** Miscellaneous ** ** diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index a8fda4fcf8..2de37b0790 100755 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -1,6 +1,6 @@ /** - * @file llinventorymodel.cpp - * @brief Implementation of the inventory model used to track agent inventory. + * @file llinventorymodelbackgroundfetch.cpp + * @brief Implementation of background fetching of inventory. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code @@ -172,8 +172,11 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched() mRecursiveLibraryFetchStarted) { mAllFoldersFetched = TRUE; + //LL_INFOS() << "All folders fetched, validating" << LL_ENDL; + //gInventory.validate(); } mFolderFetchActive = false; + mBackgroundFetchActive = false; } void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *) @@ -363,35 +366,40 @@ void LLInventoryModelBackgroundFetch::incrFetchCount(S16 fetching) class LLInventoryModelFetchItemResponder : public LLInventoryModel::fetchInventoryResponder { + LOG_CLASS(LLInventoryModelFetchItemResponder); public: - LLInventoryModelFetchItemResponder(const LLSD& request_sd) : LLInventoryModel::fetchInventoryResponder(request_sd) {}; - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + LLInventoryModelFetchItemResponder(const LLSD& request_sd) : + LLInventoryModel::fetchInventoryResponder(request_sd) + { + LLInventoryModelBackgroundFetch::instance().incrFetchCount(1); + } +private: + /* virtual */ void httpCompleted() + { + LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); + LLInventoryModel::fetchInventoryResponder::httpCompleted(); + } }; -void LLInventoryModelFetchItemResponder::result( const LLSD& content ) -{ - LLInventoryModel::fetchInventoryResponder::result(content); - LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); -} - -void LLInventoryModelFetchItemResponder::errorWithContent( U32 status, const std::string& reason, const LLSD& content ) -{ - LLInventoryModel::fetchInventoryResponder::errorWithContent(status, reason, content); - LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); -} - - class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder { + LOG_CLASS(LLInventoryModelFetchDescendentsResponder); public: LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd, uuid_vec_t recursive_cats) : mRequestSD(request_sd), mRecursiveCatUUIDs(recursive_cats) - {}; + { + LLInventoryModelBackgroundFetch::instance().incrFetchCount(1); + } //LLInventoryModelFetchDescendentsResponder() {}; - void result(const LLSD& content); - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +private: + /* virtual */ void httpCompleted() + { + LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); + LLHTTPClient::Responder::httpCompleted(); + } + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); protected: BOOL getIsRecursive(const LLUUID& cat_id) const; private: @@ -400,8 +408,14 @@ private: }; // If we get back a normal response, handle it here. -void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) +void LLInventoryModelFetchDescendentsResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); if (content.has("folders")) { @@ -508,16 +522,15 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray(); folder_it != content["bad_folders"].endArray(); ++folder_it) - { + { + // *TODO: Stop copying data LLSD folder_sd = *folder_it; // These folders failed on the dataserver. We probably don't want to retry them. - LL_INFOS() << "Folder " << folder_sd["folder_id"].asString() - << "Error: " << folder_sd["error"].asString() << LL_ENDL; + LL_WARNS() << "Folder " << folder_sd["folder_id"].asString() + << "Error: " << folder_sd["error"].asString() << LL_ENDL; } } - - fetcher->incrFetchCount(-1); if (fetcher->isBulkFetchProcessingComplete()) { @@ -529,21 +542,21 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) } // If we get back an error (not found, etc...), handle it here. -void LLInventoryModelFetchDescendentsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLInventoryModelFetchDescendentsResponder::httpFailure() { + LL_WARNS() << dumpResponse() << LL_ENDL; LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); - LL_INFOS() << "LLInventoryModelFetchDescendentsResponder::error [status:" - << status << "]: " << content << LL_ENDL; + LL_INFOS() << dumpResponse() << LL_ENDL; fetcher->incrFetchCount(-1); - if (status==499) // timed out + if (getStatus()==HTTP_INTERNAL_ERROR) // timed out or curl failure { for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); folder_it != mRequestSD["folders"].endArray(); ++folder_it) - { + { LLSD folder_sd = *folder_it; LLUUID folder_id = folder_sd["folder_id"]; const BOOL recursive = getIsRecursive(folder_id); @@ -586,7 +599,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch() (mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches)) { return; // just bail if we are disconnected - } + } U32 item_count=0; U32 folder_count=0; @@ -686,63 +699,46 @@ void LLInventoryModelBackgroundFetch::bulkFetch() { if (folder_count) { - std::string url = region->getCapability("FetchInventoryDescendents2"); + std::string url = region->getCapability("FetchInventoryDescendents2"); if ( !url.empty() ) { - mFetchCount++; - if (folder_request_body["folders"].size()) - { - LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); - LLHTTPClient::post(url, folder_request_body, fetcher, 300.0); - } - if (folder_request_body_lib["folders"].size()) - { - std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); + if (folder_request_body["folders"].size()) + { + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); + LLHTTPClient::post(url, folder_request_body, fetcher, 300.0); + } + if (folder_request_body_lib["folders"].size()) + { + std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); - LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); - LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0); + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); + LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0); + } } } - } if (item_count) { std::string url; if (item_request_body.size()) { - mFetchCount++; url = region->getCapability("FetchInventory2"); if (!url.empty()) { LLSD body; - body["agent_id"] = gAgent.getID(); body["items"] = item_request_body; LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); } - //else - //{ - // LLMessageSystem* msg = gMessageSystem; - // msg->newMessage("FetchInventory"); - // msg->nextBlock("AgentData"); - // msg->addUUID("AgentID", gAgent.getID()); - // msg->addUUID("SessionID", gAgent.getSessionID()); - // msg->nextBlock("InventoryData"); - // msg->addUUID("OwnerID", mPermissions.getOwner()); - // msg->addUUID("ItemID", mUUID); - // gAgent.sendReliableMessage(); - //} } if (item_request_body_lib.size()) { - mFetchCount++; url = region->getCapability("FetchLib2"); if (!url.empty()) { LLSD body; - body["agent_id"] = gAgent.getID(); body["items"] = item_request_body_lib; LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 2cbf9bb8b6..2dd8dce42f 100755 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -465,41 +465,13 @@ void LLInventoryFetchComboObserver::startFetch() mFetchDescendents->startFetch(); } -void LLInventoryExistenceObserver::watchItem(const LLUUID& id) -{ - if (id.notNull()) - { - mMIA.push_back(id); - } -} - -void LLInventoryExistenceObserver::changed(U32 mask) -{ - // scan through the incomplete items and move or erase them as - // appropriate. - if (!mMIA.empty()) - { - for (uuid_vec_t::iterator it = mMIA.begin(); it < mMIA.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if (!item) - { - ++it; - continue; - } - mExist.push_back(*it); - it = mMIA.erase(it); - } - if (mMIA.empty()) - { - done(); - } - } -} - +// See comment preceding LLInventoryAddedObserver::changed() for some +// concerns that also apply to this observer. void LLInventoryAddItemByAssetObserver::changed(U32 mask) { - if(!(mask & LLInventoryObserver::ADD)) + if(!(mask & LLInventoryObserver::ADD) || + !(mask & LLInventoryObserver::CREATE) || + !(mask & LLInventoryObserver::UPDATE_CREATE)) { return; } @@ -510,20 +482,12 @@ void LLInventoryAddItemByAssetObserver::changed(U32 mask) return; } - LLMessageSystem* msg = gMessageSystem; - if (!(msg->getMessageName() && (0 == strcmp(msg->getMessageName(), "UpdateCreateInventoryItem")))) + const uuid_set_t& added = gInventory.getAddedIDs(); + for (uuid_set_t::iterator it = added.begin(); it != added.end(); ++it) { - // this is not our message - return; // to prevent a crash. EXT-7921; - } - - LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem; - S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - for(S32 i = 0; i < num_blocks; ++i) - { - item->unpackMessage(msg, _PREHASH_InventoryData, i); + LLInventoryItem *item = gInventory.getItem(*it); const LLUUID& asset_uuid = item->getAssetUUID(); - if (item->getUUID().notNull() && asset_uuid.notNull()) + if (item && item->getUUID().notNull() && asset_uuid.notNull()) { if (isAssetWatched(asset_uuid)) { @@ -532,11 +496,11 @@ void LLInventoryAddItemByAssetObserver::changed(U32 mask) } } } - + if (mAddedItems.size() == mWatchedAssets.size()) { - done(); LL_DEBUGS("Inventory_Move") << "All watched items are added & processed." << LL_ENDL; + done(); mAddedItems.clear(); // Unable to clean watched items here due to somebody can require to check them in current frame. @@ -566,41 +530,28 @@ bool LLInventoryAddItemByAssetObserver::isAssetWatched( const LLUUID& asset_id ) return std::find(mWatchedAssets.begin(), mWatchedAssets.end(), asset_id) != mWatchedAssets.end(); } +// This observer used to explicitly check for whether it was being +// called as a result of an UpdateCreateInventoryItem message. It has +// now been decoupled enough that it's not actually checking the +// message system, but now we have the special UPDATE_CREATE flag +// being used for the same purpose. Fixing this, as we would need to +// do to get rid of the message, is somewhat subtle because there's no +// particular obvious criterion for when creating a new item should +// trigger this observer and when it shouldn't. For example, creating +// a new notecard with new->notecard causes a preview window to pop up +// via the derived class LLOpenTaskOffer, but creating a new notecard +// by copy and paste does not, solely because one goes through +// UpdateCreateInventoryItem and the other doesn't. void LLInventoryAddedObserver::changed(U32 mask) { - if (!(mask & LLInventoryObserver::ADD)) + if (!(mask & LLInventoryObserver::ADD) || + !(mask & LLInventoryObserver::CREATE) || + !(mask & LLInventoryObserver::UPDATE_CREATE)) { return; } - // *HACK: If this was in response to a packet off - // the network, figure out which item was updated. - LLMessageSystem* msg = gMessageSystem; - - std::string msg_name = msg->getMessageName(); - if (msg_name.empty()) - { - return; - } - - // We only want newly created inventory items. JC - if ( msg_name != "UpdateCreateInventoryItem") - { - return; - } - - LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; - S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - for (S32 i = 0; i < num_blocks; ++i) - { - titem->unpackMessage(msg, _PREHASH_InventoryData, i); - if (!(titem->getUUID().isNull())) - { - //we don't do anything with null keys - mAdded.push_back(titem->getUUID()); - } - } - if (!mAdded.empty()) + if (!gInventory.getAddedIDs().empty()) { done(); } @@ -613,9 +564,9 @@ void LLInventoryCategoryAddedObserver::changed(U32 mask) return; } - const LLInventoryModel::changed_items_t& changed_ids = gInventory.getChangedIDs(); + const LLInventoryModel::changed_items_t& added_ids = gInventory.getAddedIDs(); - for (LLInventoryModel::changed_items_t::const_iterator cit = changed_ids.begin(); cit != changed_ids.end(); ++cit) + for (LLInventoryModel::changed_items_t::const_iterator cit = added_ids.begin(); cit != added_ids.end(); ++cit) { LLViewerInventoryCategory* cat = gInventory.getCategory(*cit); @@ -633,58 +584,6 @@ void LLInventoryCategoryAddedObserver::changed(U32 mask) } } - -LLInventoryTransactionObserver::LLInventoryTransactionObserver(const LLTransactionID& transaction_id) : - mTransactionID(transaction_id) -{ -} - -void LLInventoryTransactionObserver::changed(U32 mask) -{ - if (mask & LLInventoryObserver::ADD) - { - // This could be it - see if we are processing a bulk update - LLMessageSystem* msg = gMessageSystem; - if (msg->getMessageName() - && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory"))) - { - // we have a match for the message - now check the - // transaction id. - LLUUID id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id); - if (id == mTransactionID) - { - // woo hoo, we found it - uuid_vec_t folders; - uuid_vec_t items; - S32 count; - count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); - S32 i; - for (i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i); - if (id.notNull()) - { - folders.push_back(id); - } - } - count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); - for (i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i); - if (id.notNull()) - { - items.push_back(id); - } - } - - // call the derived class the implements this method. - done(folders, items); - } - } - } -} - void LLInventoryCategoriesObserver::changed(U32 mask) { if (!mCategoryMap.size()) @@ -702,7 +601,7 @@ void LLInventoryCategoriesObserver::changed(U32 mask) LLViewerInventoryCategory* category = gInventory.getCategory(cat_id); if (!category) { - llwarns << "Category : Category id = " << cat_id << " disappeared" << llendl; + LL_WARNS() << "Category : Category id = " << cat_id << " disappeared" << LL_ENDL; cat_data.mCallback(); // Keep track of those deleted categories so we can remove them deleted_categories_ids.push_back(cat_id); @@ -833,3 +732,23 @@ LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData( { mItemNameHash.finalize(); } + +void LLScrollOnRenameObserver::changed(U32 mask) +{ + if (mask & LLInventoryObserver::LABEL) + { + const uuid_set_t& changed_item_ids = gInventory.getChangedIDs(); + for (uuid_set_t::const_iterator it = changed_item_ids.begin(); it != changed_item_ids.end(); ++it) + { + const LLUUID& id = *it; + if (id == mUUID) + { + mView->scrollToShowSelection(); + + gInventory.removeObserver(this); + delete this; + return; + } + } + } +} diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index aa1eae84d7..8cf6a6bdab 100755 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -58,6 +58,9 @@ public: GESTURE = 64, REBUILD = 128, // Item UI changed (e.g. item type different) SORT = 256, // Folder needs to be resorted. + CREATE = 512, // With ADD, item has just been created. + // unfortunately a particular message is still associated with some unique semantics. + UPDATE_CREATE = 1024, // With ADD, item added via UpdateCreateInventoryItem ALL = 0xffffffff }; LLInventoryObserver(); @@ -152,25 +155,6 @@ protected: }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryExistenceObserver -// -// Used as a base class for doing something when all the -// observed item ids exist in the inventory somewhere. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryExistenceObserver : public LLInventoryObserver -{ -public: - LLInventoryExistenceObserver() {} - /*virtual*/ void changed(U32 mask); - - void watchItem(const LLUUID& id); -protected: - virtual void done() = 0; - uuid_vec_t mExist; - uuid_vec_t mMIA; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryMovedObserver // // This class is used as a base class for doing something when all the @@ -209,13 +193,11 @@ private: class LLInventoryAddedObserver : public LLInventoryObserver { public: - LLInventoryAddedObserver() : mAdded() {} + LLInventoryAddedObserver() {} /*virtual*/ void changed(U32 mask); protected: virtual void done() = 0; - - uuid_vec_t mAdded; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -241,25 +223,6 @@ protected: }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryTransactionObserver -// -// Base class for doing something when an inventory transaction completes. -// NOTE: This class is not quite complete. Avoid using unless you fix up its -// functionality gaps. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryTransactionObserver : public LLInventoryObserver -{ -public: - LLInventoryTransactionObserver(const LLTransactionID& transaction_id); - /*virtual*/ void changed(U32 mask); - -protected: - virtual void done(const uuid_vec_t& folders, const uuid_vec_t& items) = 0; - - LLTransactionID mTransactionID; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryCompletionObserver // // Base class for doing something when when all observed items are locally @@ -326,4 +289,22 @@ protected: category_map_t mCategoryMap; }; +class LLFolderView; + +// Force a FolderView to scroll after an item in the corresponding view has been renamed. +class LLScrollOnRenameObserver: public LLInventoryObserver +{ +public: + LLFolderView *mView; + LLUUID mUUID; + + LLScrollOnRenameObserver(const LLUUID& uuid, LLFolderView *view): + mUUID(uuid), + mView(view) + { + } + /* virtual */ void changed(U32 mask); +}; + + #endif // LL_LLINVENTORYOBSERVERS_H diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 2e592f731a..e74e58015a 100755 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -145,7 +145,8 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) : mShowItemLinkOverlays(p.show_item_link_overlays), mShowEmptyMessage(p.show_empty_message), mViewsInitialized(false), - mInvFVBridgeBuilder(NULL) + mInvFVBridgeBuilder(NULL), + mInventoryViewModel(p.name) { mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER; diff --git a/indra/newview/lllistcontextmenu.cpp b/indra/newview/lllistcontextmenu.cpp index a624c9fb87..6bda8b1d0d 100755 --- a/indra/newview/lllistcontextmenu.cpp +++ b/indra/newview/lllistcontextmenu.cpp @@ -110,6 +110,7 @@ void LLListContextMenu::handleMultiple(functor_t functor, const uuid_vec_t& ids) // static LLContextMenu* LLListContextMenu::createFromFile(const std::string& filename) { + llassert(LLMenuGL::sMenuContainer != NULL); return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( filename, LLContextMenu::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); } diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 1948475530..8e4950f5c2 100755 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -541,7 +541,7 @@ void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableTyp { U32 index = gAgentWearables.getWearableIndex(wearable); gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index); - gAgentAvatarp->wearableUpdated(type, FALSE); + gAgentAvatarp->wearableUpdated(type); /* telling the manager to rebake once update cycle is fully done */ LLLocalBitmapMgr::setNeedsRebake(); diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index af194aaa1d..8d21fda8f9 100755 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -107,8 +107,8 @@ public: private: /*virtual*/ void done() { - uuid_vec_t::const_iterator it = mAdded.begin(), end = mAdded.end(); - for(; it != end; ++it) + const uuid_set_t& added = gInventory.getAddedIDs(); + for (uuid_set_t::const_iterator it = added.begin(); it != added.end(); ++it) { LLInventoryItem* item = gInventory.getItem(*it); if (!item || item->getType() != LLAssetType::AT_LANDMARK) @@ -124,8 +124,6 @@ private: mInput->onLandmarkLoaded(lm); } } - - mAdded.clear(); } LLLocationInputCtrl* mInput; @@ -142,7 +140,11 @@ public: private: /*virtual*/ void changed(U32 mask) { - if (mask & (~(LLInventoryObserver::LABEL|LLInventoryObserver::INTERNAL|LLInventoryObserver::ADD))) + if (mask & (~(LLInventoryObserver::LABEL| + LLInventoryObserver::INTERNAL| + LLInventoryObserver::ADD| + LLInventoryObserver::CREATE| + LLInventoryObserver::UPDATE_CREATE))) { mInput->updateAddLandmarkButton(); } diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 92974b9cef..06e517a861 100755 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -206,7 +206,11 @@ private: }; LLLogChat::save_history_signal_t * LLLogChat::sSaveHistorySignal = NULL; -LLLoadHistoryThread::load_end_signal_t * LLLoadHistoryThread::mLoadEndSignal = NULL; + +std::map<LLUUID,LLLoadHistoryThread *> LLLogChat::sLoadHistoryThreads; +std::map<LLUUID,LLDeleteHistoryThread *> LLLogChat::sDeleteHistoryThreads; +LLMutex* LLLogChat::sHistoryThreadsMutex = NULL; + //static std::string LLLogChat::makeLogFileName(std::string filename) @@ -337,83 +341,179 @@ void LLLogChat::saveHistory(const std::string& filename, void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params) { if (file_name.empty()) - { - LL_WARNS("LLLogChat::loadChatHistory") << "Session name is Empty!" << LL_ENDL; - return ; - } + { + LL_WARNS("LLLogChat::loadChatHistory") << "Session name is Empty!" << LL_ENDL; + return ; + } - bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false; + bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false; - LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ - if (!fptr) - { - fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ - if (!fptr) - { - return; //No previous conversation with this name. - } - } + LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ + if (!fptr) + { + fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ + if (!fptr) + { + return; //No previous conversation with this name. + } + } - char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/ - char *bptr; - S32 len; - bool firstline = TRUE; - - if (load_all_history || fseek(fptr, (LOG_RECALL_SIZE - 1) * -1 , SEEK_END)) - { //We need to load the whole historyFile or it's smaller than recall size, so get it all. - firstline = FALSE; - if (fseek(fptr, 0, SEEK_SET)) - { - fclose(fptr); - return; - } - } - while (fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr)) - { - len = strlen(buffer) - 1; /*Flawfinder: ignore*/ - for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0'; - - if (firstline) - { - firstline = FALSE; - continue; - } - - std::string line(buffer); - - //updated 1.23 plain text log format requires a space added before subsequent lines in a multilined message - if (' ' == line[0]) - { - line.erase(0, MULTI_LINE_PREFIX.length()); - append_to_last_message(messages, '\n' + line); - } - else if (0 == len && ('\n' == line[0] || '\r' == line[0])) - { - //to support old format's multilined messages with new lines used to divide paragraphs - append_to_last_message(messages, line); - } - else - { - LLSD item; - if (!LLChatLogParser::parse(line, item, load_params)) - { - item[LL_IM_TEXT] = line; - } - messages.push_back(item); - } - } - fclose(fptr); + char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/ + char *bptr; + S32 len; + bool firstline = TRUE; + + if (load_all_history || fseek(fptr, (LOG_RECALL_SIZE - 1) * -1 , SEEK_END)) + { //We need to load the whole historyFile or it's smaller than recall size, so get it all. + firstline = FALSE; + if (fseek(fptr, 0, SEEK_SET)) + { + fclose(fptr); + return; + } + } + while (fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr)) + { + len = strlen(buffer) - 1; /*Flawfinder: ignore*/ + for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0'; + + if (firstline) + { + firstline = FALSE; + continue; + } + + std::string line(buffer); + + //updated 1.23 plain text log format requires a space added before subsequent lines in a multilined message + if (' ' == line[0]) + { + line.erase(0, MULTI_LINE_PREFIX.length()); + append_to_last_message(messages, '\n' + line); + } + else if (0 == len && ('\n' == line[0] || '\r' == line[0])) + { + //to support old format's multilined messages with new lines used to divide paragraphs + append_to_last_message(messages, line); + } + else + { + LLSD item; + if (!LLChatLogParser::parse(line, item, load_params)) + { + item[LL_IM_TEXT] = line; + } + messages.push_back(item); + } + } + fclose(fptr); +} + +// static +bool LLLogChat::historyThreadsFinished(LLUUID session_id) +{ + LLMutexLock lock(historyThreadsMutex()); + bool finished = true; + std::map<LLUUID,LLLoadHistoryThread *>::iterator it = sLoadHistoryThreads.find(session_id); + if (it != sLoadHistoryThreads.end()) + { + finished = it->second->isFinished(); + } + if (!finished) + { + return false; + } + std::map<LLUUID,LLDeleteHistoryThread *>::iterator dit = sDeleteHistoryThreads.find(session_id); + if (dit != sDeleteHistoryThreads.end()) + { + finished = finished && dit->second->isFinished(); + } + return finished; +} + +// static +LLLoadHistoryThread* LLLogChat::getLoadHistoryThread(LLUUID session_id) +{ + LLMutexLock lock(historyThreadsMutex()); + std::map<LLUUID,LLLoadHistoryThread *>::iterator it = sLoadHistoryThreads.find(session_id); + if (it != sLoadHistoryThreads.end()) + { + return it->second; + } + return NULL; +} +// static +LLDeleteHistoryThread* LLLogChat::getDeleteHistoryThread(LLUUID session_id) +{ + LLMutexLock lock(historyThreadsMutex()); + std::map<LLUUID,LLDeleteHistoryThread *>::iterator it = sDeleteHistoryThreads.find(session_id); + if (it != sDeleteHistoryThreads.end()) + { + return it->second; + } + return NULL; +} +// static +bool LLLogChat::addLoadHistoryThread(LLUUID& session_id, LLLoadHistoryThread* lthread) +{ + LLMutexLock lock(historyThreadsMutex()); + std::map<LLUUID,LLLoadHistoryThread *>::const_iterator it = sLoadHistoryThreads.find(session_id); + if (it != sLoadHistoryThreads.end()) + { + return false; + } + sLoadHistoryThreads[session_id] = lthread; + return true; +} + +// static +bool LLLogChat::addDeleteHistoryThread(LLUUID& session_id, LLDeleteHistoryThread* dthread) +{ + LLMutexLock lock(historyThreadsMutex()); + std::map<LLUUID,LLDeleteHistoryThread *>::const_iterator it = sDeleteHistoryThreads.find(session_id); + if (it != sDeleteHistoryThreads.end()) + { + return false; + } + sDeleteHistoryThreads[session_id] = dthread; + return true; } -void LLLogChat::startChatHistoryThread(const std::string& file_name, const LLSD& load_params) +// static +void LLLogChat::cleanupHistoryThreads() { + LLMutexLock lock(historyThreadsMutex()); + std::vector<LLUUID> uuids; + std::map<LLUUID,LLLoadHistoryThread *>::iterator lit = sLoadHistoryThreads.begin(); + for (; lit != sLoadHistoryThreads.end(); lit++) + { + if (lit->second->isFinished() && sDeleteHistoryThreads[lit->first]->isFinished()) + { + delete lit->second; + delete sDeleteHistoryThreads[lit->first]; + uuids.push_back(lit->first); + } + } + std::vector<LLUUID>::iterator uuid_it = uuids.begin(); + for ( ;uuid_it != uuids.end(); uuid_it++) + { + sLoadHistoryThreads.erase(*uuid_it); + sDeleteHistoryThreads.erase(*uuid_it); + } +} - LLLoadHistoryThread* mThread = new LLLoadHistoryThread(); - mThread->start(); - mThread->setHistoryParams(file_name, load_params); +//static +LLMutex* LLLogChat::historyThreadsMutex() +{ + if (sHistoryThreadsMutex == NULL) + { + sHistoryThreadsMutex = new LLMutex(NULL); + } + return sHistoryThreadsMutex; } + // static std::string LLLogChat::oldLogFileName(std::string filename) { @@ -475,7 +575,7 @@ void LLLogChat::findTranscriptFiles(std::string pattern, std::vector<std::string //Add Nearby chat history to the list of transcriptions list_of_transcriptions.push_back(gDirUtilp->add(dirname, filename)); LLFile::close(filep); - return; + continue; } char buffer[LOG_RECALL_SIZE]; @@ -845,31 +945,89 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params return true; //parsed name and message text, maybe have a timestamp too } -LLLoadHistoryThread::LLLoadHistoryThread() : LLThread("load chat history") +LLDeleteHistoryThread::LLDeleteHistoryThread(std::list<LLSD>* messages, LLLoadHistoryThread* loadThread) + : LLActionThread("delete chat history"), + mMessages(messages), + mLoadThread(loadThread) { - mNewLoad = false; +} +LLDeleteHistoryThread::~LLDeleteHistoryThread() +{ +} +void LLDeleteHistoryThread::run() +{ + if (mLoadThread != NULL) + { + mLoadThread->waitFinished(); + } + if (NULL != mMessages) + { + delete mMessages; + } + mMessages = NULL; + setFinished(); } -void LLLoadHistoryThread::run() +LLActionThread::LLActionThread(const std::string& name) + : LLThread(name), + mMutex(NULL), + mRunCondition(NULL), + mFinished(false) { - while (!LLApp::isQuitting()) +} + +LLActionThread::~LLActionThread() +{ +} + +void LLActionThread::waitFinished() +{ + mMutex.lock(); + if (!mFinished) { - if(mNewLoad) - { - loadHistory(mFileName,mMessages,mLoadParams); - break; - } + mMutex.unlock(); + mRunCondition.wait(); + } + else + { + mMutex.unlock(); } } -void LLLoadHistoryThread::setHistoryParams(const std::string& file_name, const LLSD& load_params) +void LLActionThread::setFinished() { - mFileName = file_name; - mLoadParams = load_params; - mNewLoad = true; + mMutex.lock(); + mFinished = true; + mMutex.unlock(); + mRunCondition.signal(); } -void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params) +LLLoadHistoryThread::LLLoadHistoryThread(const std::string& file_name, std::list<LLSD>* messages, const LLSD& load_params) + : LLActionThread("load chat history"), + mMessages(messages), + mFileName(file_name), + mLoadParams(load_params), + mNewLoad(true), + mLoadEndSignal(NULL) +{ +} + +LLLoadHistoryThread::~LLLoadHistoryThread() +{ +} + +void LLLoadHistoryThread::run() +{ + if(mNewLoad) + { + loadHistory(mFileName, mMessages, mLoadParams); + int count = mMessages->size(); + llinfos << "mMessages->size(): " << count << llendl; + setFinished(); + } +} + +void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list<LLSD>* messages, const LLSD& load_params) { if (file_name.empty()) { @@ -878,8 +1036,8 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list<LL } bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false; - LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ + if (!fptr) { fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ @@ -892,6 +1050,7 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list<LL } char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/ + char *bptr; S32 len; bool firstline = TRUE; @@ -908,29 +1067,31 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list<LL } } - while (fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr)) + + while (fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr)) { len = strlen(buffer) - 1; /*Flawfinder: ignore*/ + for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0'; + if (firstline) { firstline = FALSE; continue; } - std::string line(buffer); //updated 1.23 plaint text log format requires a space added before subsequent lines in a multilined message if (' ' == line[0]) { line.erase(0, MULTI_LINE_PREFIX.length()); - append_to_last_message(messages, '\n' + line); + append_to_last_message(*messages, '\n' + line); } else if (0 == len && ('\n' == line[0] || '\r' == line[0])) { //to support old format's multilined messages with new lines used to divide paragraphs - append_to_last_message(messages, line); + append_to_last_message(*messages, line); } else { @@ -939,15 +1100,15 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list<LL { item[LL_IM_TEXT] = line; } - messages.push_back(item); + messages->push_back(item); } } + fclose(fptr); mNewLoad = false; (*mLoadEndSignal)(messages, file_name); } - -//static + boost::signals2::connection LLLoadHistoryThread::setLoadEndSignal(const load_end_signal_t::slot_type& cb) { if (NULL == mLoadEndSignal) @@ -957,3 +1118,13 @@ boost::signals2::connection LLLoadHistoryThread::setLoadEndSignal(const load_end return mLoadEndSignal->connect(cb); } + +void LLLoadHistoryThread::removeLoadEndSignal(const load_end_signal_t::slot_type& cb) +{ + if (NULL != mLoadEndSignal) + { + mLoadEndSignal->disconnect_all_slots(); + delete mLoadEndSignal; + } + mLoadEndSignal = NULL; +} diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index 86610f99b3..ca597599dd 100755 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -29,23 +29,54 @@ #include "llthread.h" class LLChat; -class LLLoadHistoryThread : public LLThread + +class LLActionThread : public LLThread { +public: + LLActionThread(const std::string& name); + ~LLActionThread(); + + void waitFinished(); + bool isFinished() { return mFinished; } +protected: + void setFinished(); private: - std::string mFileName; - std::list<LLSD> mMessages; + bool mFinished; + LLMutex mMutex; + LLCondition mRunCondition; +}; + +class LLLoadHistoryThread : public LLActionThread +{ +private: + const std::string& mFileName; + std::list<LLSD>* mMessages; LLSD mLoadParams; bool mNewLoad; public: - LLLoadHistoryThread(); - - void setHistoryParams(const std::string& file_name, const LLSD& load_params); - virtual void loadHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params); + LLLoadHistoryThread(const std::string& file_name, std::list<LLSD>* messages, const LLSD& load_params); + ~LLLoadHistoryThread(); + //void setHistoryParams(const std::string& file_name, const LLSD& load_params); + virtual void loadHistory(const std::string& file_name, std::list<LLSD>* messages, const LLSD& load_params); virtual void run(); - typedef boost::signals2::signal<void (std::list<LLSD>& messages,const std::string& file_name)> load_end_signal_t; - static load_end_signal_t * mLoadEndSignal; - static boost::signals2::connection setLoadEndSignal(const load_end_signal_t::slot_type& cb); + typedef boost::signals2::signal<void (std::list<LLSD>* messages,const std::string& file_name)> load_end_signal_t; + load_end_signal_t * mLoadEndSignal; + boost::signals2::connection setLoadEndSignal(const load_end_signal_t::slot_type& cb); + void removeLoadEndSignal(const load_end_signal_t::slot_type& cb); +}; + +class LLDeleteHistoryThread : public LLActionThread +{ +private: + std::list<LLSD>* mMessages; + LLLoadHistoryThread* mLoadThread; +public: + LLDeleteHistoryThread(std::list<LLSD>* messages, LLLoadHistoryThread* loadThread); + ~LLDeleteHistoryThread(); + + virtual void run(); + static void deleteHistory(); }; class LLLogChat @@ -74,7 +105,6 @@ public: static void getListOfTranscriptBackupFiles(std::vector<std::string>& list_of_transcriptions); static void loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params = LLSD()); - static void startChatHistoryThread(const std::string& file_name, const LLSD& load_params); typedef boost::signals2::signal<void ()> save_history_signal_t; static boost::signals2::connection setSaveHistorySignal(const save_history_signal_t::slot_type& cb); @@ -91,9 +121,21 @@ public: static bool isTranscriptExist(const LLUUID& avatar_id, bool is_group=false); static bool isNearbyTranscriptExist(); + static bool historyThreadsFinished(LLUUID session_id); + static LLLoadHistoryThread* getLoadHistoryThread(LLUUID session_id); + static LLDeleteHistoryThread* getDeleteHistoryThread(LLUUID session_id); + static bool addLoadHistoryThread(LLUUID& session_id, LLLoadHistoryThread* lthread); + static bool addDeleteHistoryThread(LLUUID& session_id, LLDeleteHistoryThread* dthread); + static void cleanupHistoryThreads(); + private: static std::string cleanFileName(std::string filename); static save_history_signal_t * sSaveHistorySignal; + + static std::map<LLUUID,LLLoadHistoryThread *> sLoadHistoryThreads; + static std::map<LLUUID,LLDeleteHistoryThread *> sDeleteHistoryThreads; + static LLMutex* sHistoryThreadsMutex; + static LLMutex* historyThreadsMutex(); }; /** diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index a63f6f424c..8c531e476d 100755 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -843,121 +843,85 @@ void LLManipScale::drag( S32 x, S32 y ) // Scale around the void LLManipScale::dragCorner( S32 x, S32 y ) { - LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); - // Suppress scale if mouse hasn't moved. if (x == mLastMouseX && y == mLastMouseY) { - // sendUpdates(TRUE,TRUE,TRUE); return; } - mLastMouseX = x; mLastMouseY = y; - LLVector3d drag_start_point_global = mDragStartPointGlobal; - LLVector3d drag_start_center_global = mDragStartCenterGlobal; - LLVector3 drag_start_point_agent = gAgent.getPosAgentFromGlobal(drag_start_point_global); - LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(drag_start_center_global); + LLVector3 drag_start_point_agent = gAgent.getPosAgentFromGlobal(mDragStartPointGlobal); + LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(mDragStartCenterGlobal); LLVector3d drag_start_dir_d; - drag_start_dir_d.setVec(drag_start_point_global - drag_start_center_global); - LLVector3 drag_start_dir_f; - drag_start_dir_f.setVec(drag_start_dir_d); + drag_start_dir_d.setVec(mDragStartPointGlobal - mDragStartCenterGlobal); F32 s = 0; F32 t = 0; - nearestPointOnLineFromMouse(x, y, - drag_start_center_agent, - drag_start_point_agent, - s, t ); - - F32 drag_start_dist = dist_vec(drag_start_point_agent, drag_start_center_agent); + drag_start_center_agent, + drag_start_point_agent, + s, t ); if( s <= 0 ) // we only care about intersections in front of the camera { return; } + mDragPointGlobal = lerp(mDragStartCenterGlobal, mDragStartPointGlobal, t); - LLVector3d drag_point_global = drag_start_center_global + t * drag_start_dir_d; - - F32 scale_factor = t; - - BOOL uniform = LLManipScale::getUniform(); - - if( !uniform ) - { - scale_factor = 0.5f + (scale_factor * 0.5f); - } + LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); + F32 scale_factor = 1.f; + F32 max_scale = partToMaxScale(mManipPart, bbox); + F32 min_scale = partToMinScale(mManipPart, bbox); + BOOL uniform = LLManipScale::getUniform(); // check for snapping - LLVector3 drag_center_agent = gAgent.getPosAgentFromGlobal(drag_point_global); LLVector3 mouse_on_plane1; - getMousePointOnPlaneAgent(mouse_on_plane1, x, y, drag_center_agent, mScalePlaneNormal1); - LLVector3 mouse_on_plane2; - getMousePointOnPlaneAgent(mouse_on_plane2, x, y, drag_center_agent, mScalePlaneNormal2); - LLVector3 mouse_dir_1 = mouse_on_plane1 - mScaleCenter; - LLVector3 mouse_dir_2 = mouse_on_plane2 - mScaleCenter; - LLVector3 mouse_to_scale_line_1 = mouse_dir_1 - projected_vec(mouse_dir_1, mScaleDir); - LLVector3 mouse_to_scale_line_2 = mouse_dir_2 - projected_vec(mouse_dir_2, mScaleDir); - LLVector3 mouse_to_scale_line_dir_1 = mouse_to_scale_line_1; - mouse_to_scale_line_dir_1.normVec(); - if (mouse_to_scale_line_dir_1 * mSnapGuideDir1 < 0.f) - { - // need to keep sign of mouse offset wrt to snap guide direction - mouse_to_scale_line_dir_1 *= -1.f; - } - LLVector3 mouse_to_scale_line_dir_2 = mouse_to_scale_line_2; - mouse_to_scale_line_dir_2.normVec(); - if (mouse_to_scale_line_dir_2 * mSnapGuideDir2 < 0.f) - { - // need to keep sign of mouse offset wrt to snap guide direction - mouse_to_scale_line_dir_2 *= -1.f; - } + getMousePointOnPlaneAgent(mouse_on_plane1, x, y, mScaleCenter, mScalePlaneNormal1); + mouse_on_plane1 -= mScaleCenter; - F32 snap_dir_dot_mouse_offset1 = mSnapGuideDir1 * mouse_to_scale_line_dir_1; - F32 snap_dir_dot_mouse_offset2 = mSnapGuideDir2 * mouse_to_scale_line_dir_2; + LLVector3 mouse_on_plane2; + getMousePointOnPlaneAgent(mouse_on_plane2, x, y, mScaleCenter, mScalePlaneNormal2); + mouse_on_plane2 -= mScaleCenter; - F32 dist_from_scale_line_1 = mouse_to_scale_line_1 * mouse_to_scale_line_dir_1; - F32 dist_from_scale_line_2 = mouse_to_scale_line_2 * mouse_to_scale_line_dir_2; + LLVector3 projected_drag_pos1 = inverse_projected_vec(mScaleDir, orthogonal_component(mouse_on_plane1, mSnapGuideDir1)); + LLVector3 projected_drag_pos2 = inverse_projected_vec(mScaleDir, orthogonal_component(mouse_on_plane2, mSnapGuideDir2)); - F32 max_scale = partToMaxScale(mManipPart, bbox); - F32 min_scale = partToMinScale(mManipPart, bbox); + LLVector3 mouse_offset_from_scale_line_1 = orthogonal_component(mouse_on_plane1, mScaleDir); + LLVector3 mouse_offset_from_scale_line_2 = orthogonal_component(mouse_on_plane2, mScaleDir); BOOL snap_enabled = gSavedSettings.getBOOL("SnapEnabled"); - if (snap_enabled && dist_from_scale_line_1 > mSnapRegimeOffset * snap_dir_dot_mouse_offset1) + if (snap_enabled && (mouse_on_plane1 - projected_drag_pos1) * mSnapGuideDir1 > mSnapRegimeOffset) { - mInSnapRegime = TRUE; - LLVector3 projected_drag_pos = mouse_on_plane1 - (dist_from_scale_line_1 / snap_dir_dot_mouse_offset1) * mSnapGuideDir1; - F32 drag_dist = (projected_drag_pos - mScaleCenter) * mScaleDir; + F32 drag_dist = projected_drag_pos1.length(); - F32 cur_subdivisions = llclamp(getSubdivisionLevel(projected_drag_pos, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); + F32 cur_subdivisions = llclamp(getSubdivisionLevel(projected_drag_pos1, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions); F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit1 / cur_subdivisions); mScaleSnapValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)), min_scale, max_scale); - scale_factor = mScaleSnapValue / drag_start_dist; - if( !uniform ) + mInSnapRegime = TRUE; + scale_factor = mScaleSnapValue / dist_vec(drag_start_point_agent, drag_start_center_agent); + if (!uniform) { scale_factor *= 0.5f; } } - else if (snap_enabled && dist_from_scale_line_2 > mSnapRegimeOffset * snap_dir_dot_mouse_offset2) + else if (snap_enabled && (mouse_on_plane2 - projected_drag_pos2) * mSnapGuideDir2 > mSnapRegimeOffset ) { - mInSnapRegime = TRUE; - LLVector3 projected_drag_pos = mouse_on_plane2 - (dist_from_scale_line_2 / snap_dir_dot_mouse_offset2) * mSnapGuideDir2; - F32 drag_dist = (projected_drag_pos - mScaleCenter) * mScaleDir; + F32 drag_dist = projected_drag_pos2.length(); - F32 cur_subdivisions = llclamp(getSubdivisionLevel(projected_drag_pos, mScaleDir, mScaleSnapUnit2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); + F32 cur_subdivisions = llclamp(getSubdivisionLevel(projected_drag_pos2, mScaleDir, mScaleSnapUnit2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); F32 snap_dist = mScaleSnapUnit2 / (2.f * cur_subdivisions); F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit2 / cur_subdivisions); mScaleSnapValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)), min_scale, max_scale); - scale_factor = mScaleSnapValue / drag_start_dist; - if( !uniform ) + mInSnapRegime = TRUE; + scale_factor = mScaleSnapValue / dist_vec(drag_start_point_agent, drag_start_center_agent); + if (!uniform) { scale_factor *= 0.5f; } @@ -965,8 +929,14 @@ void LLManipScale::dragCorner( S32 x, S32 y ) else { mInSnapRegime = FALSE; + scale_factor = t; + if (!uniform) + { + scale_factor = 0.5f + (scale_factor * 0.5f); + } } + F32 max_scale_factor = get_default_max_prim_scale() / MIN_PRIM_SCALE; F32 min_scale_factor = MIN_PRIM_SCALE / get_default_max_prim_scale(); @@ -1069,9 +1039,6 @@ void LLManipScale::dragCorner( S32 x, S32 y ) } } - - - mDragPointGlobal = drag_point_global; } diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 7907e700c4..4a7a4e268d 100755 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -100,7 +100,7 @@ namespace LLMarketplaceImport bool hasSessionCookie(); bool inProgress(); bool resultPending(); - U32 getResultStatus(); + S32 getResultStatus(); const LLSD& getResults(); bool establishMarketplaceSessionCookie(); @@ -114,7 +114,7 @@ namespace LLMarketplaceImport static bool sImportInProgress = false; static bool sImportPostPending = false; static bool sImportGetPending = false; - static U32 sImportResultStatus = 0; + static S32 sImportResultStatus = 0; static LLSD sImportResults = LLSD::emptyMap(); static LLTimer slmGetTimer; @@ -124,23 +124,26 @@ namespace LLMarketplaceImport class LLImportPostResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLImportPostResponder); public: LLImportPostResponder() : LLCurl::Responder() {} - - void completed(U32 status, const std::string& reason, const LLSD& content) + + protected: + /* virtual */ void httpCompleted() { slmPostTimer.stop(); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - LL_INFOS() << " SLM POST status: " << status << LL_ENDL; - LL_INFOS() << " SLM POST reason: " << reason << LL_ENDL; - LL_INFOS() << " SLM POST content: " << content.asString() << LL_ENDL; - LL_INFOS() << " SLM POST timer: " << slmPostTimer.getElapsedTimeF32() << LL_ENDL; + LL_INFOS() << " SLM [timer:" << slmPostTimer.getElapsedTimeF32() << "] " + << dumpResponse() << LL_ENDL; } - // MAINT-2301 : we determined we can safely ignore that error in that context - if (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT) + S32 status = getStatus(); + if ((status == MarketplaceErrorCodes::IMPORT_REDIRECT) || + (status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) || + // MAINT-2301 : we determined we can safely ignore that error in that context + (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT)) { if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { @@ -161,39 +164,37 @@ namespace LLMarketplaceImport sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_DONE); sImportPostPending = false; sImportResultStatus = status; - sImportId = content; + sImportId = getContent(); } }; class LLImportGetResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLImportGetResponder); public: LLImportGetResponder() : LLCurl::Responder() {} - void completedHeader(U32 status, const std::string& reason, const LLSD& content) + protected: + /* virtual */ void httpCompleted() { - const std::string& set_cookie_string = content["set-cookie"].asString(); + const std::string& set_cookie_string = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); if (!set_cookie_string.empty()) { sMarketplaceCookie = set_cookie_string; } - } - - void completed(U32 status, const std::string& reason, const LLSD& content) - { + slmGetTimer.stop(); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - LL_INFOS() << " SLM GET status: " << status << LL_ENDL; - LL_INFOS() << " SLM GET reason: " << reason << LL_ENDL; - LL_INFOS() << " SLM GET content: " << content.asString() << LL_ENDL; - LL_INFOS() << " SLM GET timer: " << slmGetTimer.getElapsedTimeF32() << LL_ENDL; + LL_INFOS() << " SLM [timer:" << slmGetTimer.getElapsedTimeF32() << "] " + << dumpResponse() << LL_ENDL; } // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initally empty + S32 status = getStatus(); if ((status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) && (status != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) && (status != MarketplaceErrorCodes::IMPORT_NOT_FOUND)) @@ -212,7 +213,7 @@ namespace LLMarketplaceImport sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING); sImportGetPending = false; sImportResultStatus = status; - sImportResults = content; + sImportResults = getContent(); } }; @@ -233,7 +234,7 @@ namespace LLMarketplaceImport return (sImportPostPending || sImportGetPending); } - U32 getResultStatus() + S32 getResultStatus() { return sImportResultStatus; } @@ -297,10 +298,11 @@ namespace LLMarketplaceImport // Make the headers for the post LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - headers["Cookie"] = sMarketplaceCookie; - headers["Content-Type"] = "application/llsd+xml"; - headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent(); + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; + headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie; + // *TODO: Why are we setting Content-Type for a GET request? + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; + headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent(); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { @@ -334,11 +336,11 @@ namespace LLMarketplaceImport // Make the headers for the post LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - headers["Connection"] = "Keep-Alive"; - headers["Cookie"] = sMarketplaceCookie; - headers["Content-Type"] = "application/xml"; - headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent(); + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; + headers[HTTP_OUT_HEADER_CONNECTION] = "Keep-Alive"; + headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie; + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML; + headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent(); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index df6a42db4d..a1f6a01aa0 100644..100755 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -71,8 +71,8 @@ public: LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback); virtual ~LLMaterialsResponder(); - virtual void result(const LLSD& pContent); - virtual void error(U32 pStatus, const std::string& pReason); + virtual void httpSuccess(); + virtual void httpFailure(); private: std::string mMethod; @@ -92,14 +92,19 @@ LLMaterialsResponder::~LLMaterialsResponder() { } -void LLMaterialsResponder::result(const LLSD& pContent) +void LLMaterialsResponder::httpSuccess() { + const LLSD& pContent = getContent(); + LL_DEBUGS("Materials") << LL_ENDL; mCallback(true, pContent); } -void LLMaterialsResponder::error(U32 pStatus, const std::string& pReason) +void LLMaterialsResponder::httpFailure() { + U32 pStatus = (U32) getStatus(); + const std::string& pReason = getReason(); + LL_WARNS("Materials") << "\n--------------------------------------------------------------------------\n" << mMethod << " Error[" << pStatus << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 323445afa6..0178512cb5 100755 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -52,6 +52,7 @@ #include "llsdutil.h" #include "lllayoutstack.h" #include "lliconctrl.h" +#include "llhttpconstants.h" #include "lltextbox.h" #include "llbutton.h" #include "llcheckboxctrl.h" @@ -390,8 +391,12 @@ BOOL LLMediaCtrl::postBuild () LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); + // stinson 05/05/2014 : use this as the parent of the context menu if the static menu + // container has yet to be created + LLPanel* menuParent = (LLMenuGL::sMenuContainer != NULL) ? dynamic_cast<LLPanel*>(LLMenuGL::sMenuContainer) : dynamic_cast<LLPanel*>(this); + llassert(menuParent != NULL); mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( - "menu_media_ctrl.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); + "menu_media_ctrl.xml", menuParent, LLViewerMenuHolderGL::child_registry_t::instance()); setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChanged, this, _2)); return TRUE; @@ -576,7 +581,7 @@ void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::str { mCurrentNavUrl = expanded_filename; mMediaSource->setSize(mTextureWidth, mTextureHeight); - mMediaSource->navigateTo(expanded_filename, "text/html", false); + mMediaSource->navigateTo(expanded_filename, HTTP_CONTENT_TEXT_HTML, false); } } @@ -948,7 +953,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_ERROR_PAGE" << LL_ENDL; if ( mErrorPageURL.length() > 0 ) { - navigateTo(mErrorPageURL, "text/html"); + navigateTo(mErrorPageURL, HTTP_CONTENT_TEXT_HTML); }; }; break; @@ -1117,3 +1122,8 @@ void LLMediaCtrl::setTrustedContent(bool trusted) mMediaSource->setTrustedBrowser(trusted); } } + +void LLMediaCtrl::updateContextMenuParent(LLView* pNewParent) +{ + mContextMenu->updateParent(pNewParent); +} diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 5978a7a344..b07eb356ae 100755 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -168,6 +168,8 @@ public: LLUUID getTextureID() {return mMediaTextureID;} + void updateContextMenuParent(LLView* pNewParent); + protected: void convertInputCoords(S32& x, S32& y); diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index e3b46d5d2f..691be13610 100755 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -35,7 +35,7 @@ #include <boost/lexical_cast.hpp> -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h" #include "llsdutil.h" #include "llmediaentry.h" #include "lltextureentry.h" @@ -564,7 +564,7 @@ LLMediaDataClient::Responder::Responder(const request_ptr_t &request) } /*virtual*/ -void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLMediaDataClient::Responder::httpFailure() { mRequest->stopTracking(); @@ -574,9 +574,17 @@ void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::strin return; } - if (status == HTTP_SERVICE_UNAVAILABLE) + if (getStatus() == HTTP_SERVICE_UNAVAILABLE) { - F32 retry_timeout = mRequest->getRetryTimerDelay(); + F32 retry_timeout; +#if 0 + // *TODO: Honor server Retry-After header. + if (!hasResponseHeader(HTTP_IN_HEADER_RETRY_AFTER) + || !getSecondsUntilRetryAfter(getResponseHeader(HTTP_IN_HEADER_RETRY_AFTER), retry_timeout)) +#endif + { + retry_timeout = mRequest->getRetryTimerDelay(); + } mRequest->incRetryCount(); @@ -594,15 +602,16 @@ void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::strin << mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL; } } + // *TODO: Redirect on 3xx status codes. else { - LL_WARNS("LLMediaDataClient") << *mRequest << " http error [status:" - << status << "]:" << content << ")" << LL_ENDL; + LL_WARNS("LLMediaDataClient") << *mRequest << " http failure " + << dumpResponse() << LL_ENDL; } } /*virtual*/ -void LLMediaDataClient::Responder::result(const LLSD& content) +void LLMediaDataClient::Responder::httpSuccess() { mRequest->stopTracking(); @@ -612,7 +621,7 @@ void LLMediaDataClient::Responder::result(const LLSD& content) return; } - LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " result : " << ll_print_sd(content) << LL_ENDL; + LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " " << dumpResponse() << LL_ENDL; } ////////////////////////////////////////////////////////////////////////////////////// @@ -876,7 +885,7 @@ LLMediaDataClient::Responder *LLObjectMediaDataClient::RequestUpdate::createResp /*virtual*/ -void LLObjectMediaDataClient::Responder::result(const LLSD& content) +void LLObjectMediaDataClient::Responder::httpSuccess() { getRequest()->stopTracking(); @@ -886,10 +895,16 @@ void LLObjectMediaDataClient::Responder::result(const LLSD& content) return; } + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + // This responder is only used for GET requests, not UPDATE. + LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL; - LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " GET returned: " << ll_print_sd(content) << LL_ENDL; - // Look for an error if (content.has("error")) { @@ -1003,7 +1018,7 @@ LLMediaDataClient::Responder *LLObjectMediaNavigateClient::RequestNavigate::crea } /*virtual*/ -void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLObjectMediaNavigateClient::Responder::httpFailure() { getRequest()->stopTracking(); @@ -1015,14 +1030,14 @@ void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const // Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base // class - if (status == HTTP_SERVICE_UNAVAILABLE) + if (getStatus() == HTTP_SERVICE_UNAVAILABLE) { - LLMediaDataClient::Responder::errorWithContent(status, reason, content); + LLMediaDataClient::Responder::httpFailure(); } else { // bounce the face back - LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << status << LL_ENDL; + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: " << dumpResponse() << LL_ENDL; const LLSD &payload = getRequest()->getPayload(); // bounce the face back getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); @@ -1030,7 +1045,7 @@ void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const } /*virtual*/ -void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) +void LLObjectMediaNavigateClient::Responder::httpSuccess() { getRequest()->stopTracking(); @@ -1040,8 +1055,9 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) return; } - LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_print_sd(content) << LL_ENDL; + LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << dumpResponse() << LL_ENDL; + const LLSD& content = getContent(); if (content.has("error")) { const LLSD &error = content["error"]; @@ -1065,6 +1081,6 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) else { // No action required. - LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " result : " << ll_print_sd(content) << LL_ENDL; + LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL; } } diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 89e20a28d0..231b883c32 100755 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -74,8 +74,9 @@ public: // Abstracts the Cap URL, the request, and the responder class LLMediaDataClient : public LLRefCount { -public: +protected: LOG_CLASS(LLMediaDataClient); +public: const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s) const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs @@ -192,14 +193,16 @@ protected: // Responder class Responder : public LLHTTPClient::Responder { + LOG_CLASS(Responder); public: Responder(const request_ptr_t &request); + request_ptr_t &getRequest() { return mRequest; } + + protected: //If we get back an error (not found, etc...), handle it here - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + virtual void httpFailure(); //If we get back a normal response, handle it here. Default just logs it. - virtual void result(const LLSD& content); - - request_ptr_t &getRequest() { return mRequest; } + virtual void httpSuccess(); private: request_ptr_t mRequest; @@ -287,8 +290,9 @@ private: // MediaDataClient specific for the ObjectMedia cap class LLObjectMediaDataClient : public LLMediaDataClient { -public: +protected: LOG_CLASS(LLObjectMediaDataClient); +public: LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, U32 max_retries = MAX_RETRIES, @@ -341,10 +345,12 @@ protected: class Responder : public LLMediaDataClient::Responder { + LOG_CLASS(Responder); public: Responder(const request_ptr_t &request) : LLMediaDataClient::Responder(request) {} - virtual void result(const LLSD &content); + protected: + virtual void httpSuccess(); }; private: // The Get/Update data client needs a second queue to avoid object updates starving load-ins. @@ -362,8 +368,9 @@ private: // MediaDataClient specific for the ObjectMediaNavigate cap class LLObjectMediaNavigateClient : public LLMediaDataClient { -public: +protected: LOG_CLASS(LLObjectMediaNavigateClient); +public: // NOTE: from llmediaservice.h static const int ERROR_PERMISSION_DENIED_CODE = 8002; @@ -397,11 +404,13 @@ protected: class Responder : public LLMediaDataClient::Responder { + LOG_CLASS(Responder); public: Responder(const request_ptr_t &request) : LLMediaDataClient::Responder(request) {} - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - virtual void result(const LLSD &content); + protected: + virtual void httpFailure(); + virtual void httpSuccess(); private: void mediaNavigateBounceBack(); }; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 08d2d03b9b..80a427c0b8 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -27,8 +27,10 @@ #include "llviewerprecompiledheaders.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "llhttpconstants.h" #include "llapr.h" -#include "llhttpstatuscodes.h" #include "llmeshrepository.h" #include "llagent.h" @@ -515,6 +517,7 @@ S32 LLMeshRepoThread::sRequestWaterLevel = 0; class LLMeshHandlerBase : public LLCore::HttpHandler { public: + LOG_CLASS(LLMeshHandlerBase); LLMeshHandlerBase() : LLCore::HttpHandler(), mMeshParams(), @@ -547,6 +550,7 @@ public: class LLMeshHeaderHandler : public LLMeshHandlerBase { public: + LOG_CLASS(LLMeshHeaderHandler); LLMeshHeaderHandler(const LLVolumeParams & mesh_params) : LLMeshHandlerBase() { @@ -603,6 +607,7 @@ public: class LLMeshSkinInfoHandler : public LLMeshHandlerBase { public: + LOG_CLASS(LLMeshSkinInfoHandler); LLMeshSkinInfoHandler(const LLUUID& id, U32 offset, U32 size) : LLMeshHandlerBase(), mMeshID(id), @@ -632,6 +637,7 @@ public: class LLMeshDecompositionHandler : public LLMeshHandlerBase { public: + LOG_CLASS(LLMeshDecompositionHandler); LLMeshDecompositionHandler(const LLUUID& id, U32 offset, U32 size) : LLMeshHandlerBase(), mMeshID(id), @@ -661,6 +667,7 @@ public: class LLMeshPhysicsShapeHandler : public LLMeshHandlerBase { public: + LOG_CLASS(LLMeshPhysicsShapeHandler); LLMeshPhysicsShapeHandler(const LLUUID& id, U32 offset, U32 size) : LLMeshHandlerBase(), mMeshID(id), @@ -736,7 +743,6 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content, } } - LLMeshRepoThread::LLMeshRepoThread() : LLThread("mesh repo"), mHttpRequest(NULL), diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index b2a3a9f645..ba85aa7c9e 100755 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -65,7 +65,8 @@ LLNameListCtrl::LLNameListCtrl(const LLNameListCtrl::Params& p) mNameColumn(p.name_column.column_name), mAllowCallingCardDrop(p.allow_calling_card_drop), mShortNames(p.short_names), - mAvatarNameCacheConnection() + mAvatarNameCacheConnection(), + mPendingLookupsRemaining(0) {} // public @@ -335,6 +336,17 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( mAvatarNameCacheConnection.disconnect(); } mAvatarNameCacheConnection = LLAvatarNameCache::get(id,boost::bind(&LLNameListCtrl::onAvatarNameCache,this, _1, _2, item->getHandle())); + + if(mPendingLookupsRemaining <= 0) + { + // BAKER TODO: + // We might get into a state where mPendingLookupsRemaining might + // go negative. So just reset it right now and figure out if it's + // possible later :) + mPendingLookupsRemaining = 0; + mNameListCompleteSignal(false); + } + mPendingLookupsRemaining++; } break; } @@ -386,6 +398,8 @@ void LLNameListCtrl::removeNameItem(const LLUUID& agent_id) { selectNthItem(idx); // not sure whether this is needed, taken from previous implementation deleteSingleItem(idx); + + mPendingLookupsRemaining--; } } @@ -412,6 +426,23 @@ void LLNameListCtrl::onAvatarNameCache(const LLUUID& agent_id, } } + ////////////////////////////////////////////////////////////////////////// + // BAKER - FIX NameListCtrl + //if (mPendingLookupsRemaining <= 0) + { + // We might get into a state where mPendingLookupsRemaining might + // go negative. So just reset it right now and figure out if it's + // possible later :) + //mPendingLookupsRemaining = 0; + + mNameListCompleteSignal(true); + } + //else + { + // mPendingLookupsRemaining--; + } + ////////////////////////////////////////////////////////////////////////// + dirtyColumns(); } diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h index 92e82b672d..a3e17eb6df 100755 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -67,6 +67,7 @@ class LLNameListCtrl : public LLScrollListCtrl, public LLInstanceTracker<LLNameListCtrl> { public: + typedef boost::signals2::signal<void(bool)> namelist_complete_signal_t; typedef enum e_name_type { @@ -152,7 +153,7 @@ public: /*virtual*/ void updateColumns(bool force_update); - /*virtual*/ void mouseOverHighlightNthItem( S32 index ); + /*virtual*/ void mouseOverHighlightNthItem( S32 index ); private: void showInspector(const LLUUID& avatar_id, bool is_group); void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, LLHandle<LLNameListItem> item); @@ -163,6 +164,16 @@ private: BOOL mAllowCallingCardDrop; bool mShortNames; // display name only, no SLID boost::signals2::connection mAvatarNameCacheConnection; + + S32 mPendingLookupsRemaining; + namelist_complete_signal_t mNameListCompleteSignal; + +public: + boost::signals2::connection setOnNameListCompleteCallback(boost::function<void(bool)> onNameListCompleteCallback) + { + return mNameListCompleteSignal.connect(onNameListCompleteCallback); + } + }; diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 62966e3a4e..3cd39d7c7e 100755 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -96,15 +96,11 @@ class LLClassifiedClickMessageResponder : public LLHTTPClient::Responder { LOG_CLASS(LLClassifiedClickMessageResponder); -public: +protected: // If we get back an error (not found, etc...), handle it here - virtual void errorWithContent( - U32 status, - const std::string& reason, - const LLSD& content) + virtual void httpFailure() { - LL_WARNS() << "Sending click message failed (" << status << "): [" << reason << "]" << LL_ENDL; - LL_WARNS() << "Content: [" << content << "]" << LL_ENDL; + LL_WARNS() << "Sending click message failed " << dumpResponse() << LL_ENDL; } }; diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index daa7df682b..ac00c5d986 100755 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -944,11 +944,11 @@ void LLPanelEditWearable::onCommitSexChange() LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, index); if (wearable) { - wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE); + wearable->setVisualParamWeight(param->getID(), is_new_sex_male); } - param->setWeight( is_new_sex_male, FALSE ); + param->setWeight( is_new_sex_male); - gAgentAvatarp->updateSexDependentLayerSets( FALSE ); + gAgentAvatarp->updateSexDependentLayerSets(); gAgentAvatarp->updateVisualParams(); @@ -983,7 +983,7 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl) U32 index = gAgentWearables.getWearableIndex(getWearable()); gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index); LLVisualParamHint::requestHintUpdates(); - gAgentAvatarp->wearableUpdated(type, FALSE); + gAgentAvatarp->wearableUpdated(type); } } else @@ -1007,9 +1007,9 @@ void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* ctrl) const LLColor4& new_color = LLColor4(ctrl->getValue()); if( old_color != new_color ) { - getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE); + getWearable()->setClothesColor(entry->mTextureIndex, new_color); LLVisualParamHint::requestHintUpdates(); - gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + gAgentAvatarp->wearableUpdated(getWearable()->getType()); } } else @@ -1080,10 +1080,10 @@ void LLPanelEditWearable::saveChanges(bool force_save_as) if (force_save_as) { - // the name of the wearable has changed, re-save wearable with new name - LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID()); + // the name of the wearable has changed, re-save wearable with new name + LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID(),gAgentAvatarp->mEndCustomizeCallback); gAgentWearables.saveWearableAs(mWearablePtr->getType(), index, new_name, description, FALSE); - mNameEditor->setText(mWearableItem->getName()); + mNameEditor->setText(mWearableItem->getName()); } else { @@ -1093,17 +1093,19 @@ void LLPanelEditWearable::saveChanges(bool force_save_as) if (link_item) { // Create new link - link_inventory_item( gAgent.getID(), - link_item->getLinkedUUID(), - LLAppearanceMgr::instance().getCOF(), - link_item->getName(), - description, - LLAssetType::AT_LINK, - NULL); + LL_DEBUGS("Avatar") << "link refresh, creating new link to " << link_item->getLinkedUUID() + << " removing old link at " << link_item->getUUID() + << " wearable item id " << mWearablePtr->getItemID() << LL_ENDL; + + LLInventoryObject::const_object_list_t obj_array; + obj_array.push_back(LLConstPointer<LLInventoryObject>(link_item)); + link_inventory_array(LLAppearanceMgr::instance().getCOF(), + obj_array, + gAgentAvatarp->mEndCustomizeCallback); // Remove old link - gInventory.purgeObject(link_item->getUUID()); + remove_inventory_item(link_item->getUUID(), gAgentAvatarp->mEndCustomizeCallback); } - gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name); + gAgentWearables.saveWearable(mWearablePtr->getType(), index, new_name); } @@ -1121,7 +1123,7 @@ void LLPanelEditWearable::revertChanges() mNameEditor->setText(mWearableItem->getName()); updatePanelPickerControls(mWearablePtr->getType()); updateTypeSpecificControls(mWearablePtr->getType()); - gAgentAvatarp->wearableUpdated(mWearablePtr->getType(), FALSE); + gAgentAvatarp->wearableUpdated(mWearablePtr->getType()); } void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BOOL disable_camera_switch) @@ -1583,7 +1585,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE ); U32 index = gAgentWearables.getWearableIndex(getWearable()); gAgentAvatarp->setLocalTexture(te, image, FALSE, index); - gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + gAgentAvatarp->wearableUpdated(getWearable()->getType()); } else { @@ -1600,7 +1602,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL U32 index = gAgentWearables.getWearableIndex(getWearable()); gAgentAvatarp->setLocalTexture(te, image, FALSE, index); - gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + gAgentAvatarp->wearableUpdated(getWearable()->getType()); } updatePanelPickerControls(getWearable()->getType()); diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index bf332d1ca7..f4aab6bd4e 100755 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -49,6 +49,7 @@ #include "llpanelgroupnotices.h" #include "llpanelgroupgeneral.h" +#include "llpanelgrouproles.h" #include "llaccordionctrltab.h" #include "llaccordionctrl.h" @@ -275,6 +276,7 @@ void LLPanelGroup::onBtnApply(void* user_data) { LLPanelGroup* self = static_cast<LLPanelGroup*>(user_data); self->apply(); + self->refreshData(); } void LLPanelGroup::onBtnGroupCallClicked(void* user_data) @@ -497,6 +499,22 @@ bool LLPanelGroup::apply(LLPanelGroupTab* tab) { //we skip refreshing group after ew manually apply changes since its very annoying //for those who are editing group + + LLPanelGroupRoles * roles_tab = dynamic_cast<LLPanelGroupRoles*>(tab); + if (roles_tab) + { + LLGroupMgr* gmgrp = LLGroupMgr::getInstance(); + LLGroupMgrGroupData* gdatap = gmgrp->getGroupData(roles_tab->getGroupID()); + + // allow refresh only for one specific case: + // there is only one member in group and it is not owner + // it's a wrong situation and need refresh panels from server + if (gdatap && gdatap->isSingleMemberNotOwner()) + { + return true; + } + } + mSkipRefresh = TRUE; return true; } diff --git a/indra/newview/llpanelgroupbulk.cpp b/indra/newview/llpanelgroupbulk.cpp new file mode 100644 index 0000000000..1eafc5bd64 --- /dev/null +++ b/indra/newview/llpanelgroupbulk.cpp @@ -0,0 +1,421 @@ +/** +* @file llpanelgroupbulk.cpp +* @brief Implementation of llpanelgroupbulk +* @author Baker@lindenlab.com +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, 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 "llpanelgroupbulk.h" +#include "llpanelgroupbulkimpl.h" + +#include "llagent.h" +#include "llavatarnamecache.h" +#include "llfloateravatarpicker.h" +#include "llbutton.h" +#include "llcallingcard.h" +#include "llcombobox.h" +#include "llgroupactions.h" +#include "llgroupmgr.h" +#include "llnamelistctrl.h" +#include "llnotificationsutil.h" +#include "llscrolllistitem.h" +#include "llspinctrl.h" +#include "lltextbox.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "lluictrlfactory.h" +#include "llviewerwindow.h" + + +////////////////////////////////////////////////////////////////////////// +// Implementation of llpanelgroupbulkimpl.h functions +////////////////////////////////////////////////////////////////////////// +LLPanelGroupBulkImpl::LLPanelGroupBulkImpl(const LLUUID& group_id) : + mGroupID(group_id), + mBulkAgentList(NULL), + mOKButton(NULL), + mRemoveButton(NULL), + mGroupName(NULL), + mLoadingText(), + mTooManySelected(), + mCloseCallback(NULL), + mCloseCallbackUserData(NULL), + mAvatarNameCacheConnection(), + mRoleNames(NULL), + mOwnerWarning(), + mAlreadyInGroup(), + mConfirmedOwnerInvite(false), + mListFullNotificationSent(false) +{} + +LLPanelGroupBulkImpl::~LLPanelGroupBulkImpl() +{ + if(mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } +} + +void LLPanelGroupBulkImpl::callbackClickAdd(void* userdata) +{ + LLPanelGroupBulk* panelp = (LLPanelGroupBulk*)userdata; + + if(panelp) + { + //Right now this is hard coded with some knowledge that it is part + //of a floater since the avatar picker needs to be added as a dependent + //floater to the parent floater. + //Soon the avatar picker will be embedded into this panel + //instead of being it's own separate floater. But that is next week. + //This will do for now. -jwolk May 10, 2006 + LLView* button = panelp->findChild<LLButton>("add_button"); + LLFloater* root_floater = gFloaterView->getParentFloater(panelp); + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show( + boost::bind(callbackAddUsers, _1, panelp->mImplementation), TRUE, FALSE, FALSE, root_floater->getName(), button); + if(picker) + { + root_floater->addDependentFloater(picker); + } + } +} + +void LLPanelGroupBulkImpl::callbackClickRemove(void* userdata) +{ + LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)userdata; + if (selfp) + selfp->handleRemove(); +} + +void LLPanelGroupBulkImpl::callbackClickCancel(void* userdata) +{ + LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)userdata; + if(selfp) + (*(selfp->mCloseCallback))(selfp->mCloseCallbackUserData); +} + +void LLPanelGroupBulkImpl::callbackSelect(LLUICtrl* ctrl, void* userdata) +{ + LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)userdata; + if (selfp) + selfp->handleSelection(); +} + +void LLPanelGroupBulkImpl::callbackAddUsers(const uuid_vec_t& agent_ids, void* user_data) +{ + std::vector<std::string> names; + for (S32 i = 0; i < (S32)agent_ids.size(); i++) + { + LLAvatarName av_name; + if (LLAvatarNameCache::get(agent_ids[i], &av_name)) + { + onAvatarNameCache(agent_ids[i], av_name, user_data); + } + else + { + LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*) user_data; + if (selfp) + { + if (selfp->mAvatarNameCacheConnection.connected()) + { + selfp->mAvatarNameCacheConnection.disconnect(); + } + // *TODO : Add a callback per avatar name being fetched. + selfp->mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_ids[i],boost::bind(onAvatarNameCache, _1, _2, user_data)); + } + } + } +} + +void LLPanelGroupBulkImpl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, void* user_data) +{ + LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*) user_data; + + if (selfp) + { + if (selfp->mAvatarNameCacheConnection.connected()) + { + selfp->mAvatarNameCacheConnection.disconnect(); + } + std::vector<std::string> names; + uuid_vec_t agent_ids; + agent_ids.push_back(agent_id); + names.push_back(av_name.getCompleteName()); + + selfp->addUsers(names, agent_ids); + } +} + +void LLPanelGroupBulkImpl::handleRemove() +{ + std::vector<LLScrollListItem*> selection = mBulkAgentList->getAllSelected(); + if (selection.empty()) + return; + + std::vector<LLScrollListItem*>::iterator iter; + for(iter = selection.begin(); iter != selection.end(); ++iter) + { + mInviteeIDs.erase((*iter)->getUUID()); + } + + mBulkAgentList->deleteSelectedItems(); + mRemoveButton->setEnabled(FALSE); + + if( mOKButton && mOKButton->getEnabled() && + mBulkAgentList->isEmpty()) + { + mOKButton->setEnabled(FALSE); + } +} + +void LLPanelGroupBulkImpl::handleSelection() +{ + std::vector<LLScrollListItem*> selection = mBulkAgentList->getAllSelected(); + if (selection.empty()) + mRemoveButton->setEnabled(FALSE); + else + mRemoveButton->setEnabled(TRUE); +} + +void LLPanelGroupBulkImpl::addUsers(const std::vector<std::string>& names, const uuid_vec_t& agent_ids) +{ + std::string name; + LLUUID id; + + if(mListFullNotificationSent) + { + return; + } + + if( !mListFullNotificationSent && + (names.size() + mInviteeIDs.size() > MAX_GROUP_INVITES)) + { + mListFullNotificationSent = true; + + // Fail! Show a warning and don't add any names. + LLSD msg; + msg["MESSAGE"] = mTooManySelected; + LLNotificationsUtil::add("GenericAlert", msg); + return; + } + + for (S32 i = 0; i < (S32)names.size(); ++i) + { + name = names[i]; + id = agent_ids[i]; + + if(mInviteeIDs.find(id) != mInviteeIDs.end()) + { + continue; + } + + //add the name to the names list + LLSD row; + row["id"] = id; + row["columns"][0]["value"] = name; + + mBulkAgentList->addElement(row); + mInviteeIDs.insert(id); + + // We've successfully added someone to the list. + if(mOKButton && !mOKButton->getEnabled()) + mOKButton->setEnabled(TRUE); + } +} + +void LLPanelGroupBulkImpl::setGroupName(std::string name) +{ + if(mGroupName) + mGroupName->setText(name); +} + + +LLPanelGroupBulk::LLPanelGroupBulk(const LLUUID& group_id) : + LLPanel(), + mImplementation(new LLPanelGroupBulkImpl(group_id)), + mPendingGroupPropertiesUpdate(false), + mPendingRoleDataUpdate(false), + mPendingMemberDataUpdate(false) +{} + +LLPanelGroupBulk::~LLPanelGroupBulk() +{ + delete mImplementation; +} + +void LLPanelGroupBulk::clear() +{ + mImplementation->mInviteeIDs.clear(); + + if(mImplementation->mBulkAgentList) + mImplementation->mBulkAgentList->deleteAllItems(); + + if(mImplementation->mOKButton) + mImplementation->mOKButton->setEnabled(FALSE); +} + +void LLPanelGroupBulk::update() +{ + updateGroupName(); + updateGroupData(); +} + +void LLPanelGroupBulk::draw() +{ + LLPanel::draw(); + update(); +} + +void LLPanelGroupBulk::updateGroupName() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID); + + if( gdatap && + gdatap->isGroupPropertiesDataComplete()) + { + // Only do work if the current group name differs + if(mImplementation->mGroupName->getText().compare(gdatap->mName) != 0) + mImplementation->setGroupName(gdatap->mName); + } + else + { + mImplementation->setGroupName(mImplementation->mLoadingText); + } +} + +void LLPanelGroupBulk::updateGroupData() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID); + if(gdatap && gdatap->isGroupPropertiesDataComplete()) + { + mPendingGroupPropertiesUpdate = false; + } + else + { + if(!mPendingGroupPropertiesUpdate) + { + mPendingGroupPropertiesUpdate = true; + LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID); + } + } + + if(gdatap && gdatap->isRoleDataComplete()) + { + mPendingRoleDataUpdate = false; + } + else + { + if(!mPendingRoleDataUpdate) + { + mPendingRoleDataUpdate = true; + LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID); + } + } + + if(gdatap && gdatap->isMemberDataComplete()) + { + mPendingMemberDataUpdate = false; + } + else + { + if(!mPendingMemberDataUpdate) + { + mPendingMemberDataUpdate = true; + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID); + } + } +} + +void LLPanelGroupBulk::addUserCallback(const LLUUID& id, const LLAvatarName& av_name) +{ + std::vector<std::string> names; + uuid_vec_t agent_ids; + agent_ids.push_back(id); + names.push_back(av_name.getAccountName()); + + mImplementation->addUsers(names, agent_ids); +} + +void LLPanelGroupBulk::setCloseCallback(void (*close_callback)(void*), void* data) +{ + mImplementation->mCloseCallback = close_callback; + mImplementation->mCloseCallbackUserData = data; +} + +void LLPanelGroupBulk::addUsers(uuid_vec_t& agent_ids) +{ + std::vector<std::string> names; + for (S32 i = 0; i < (S32)agent_ids.size(); i++) + { + std::string fullname; + LLUUID agent_id = agent_ids[i]; + LLViewerObject* dest = gObjectList.findObject(agent_id); + if(dest && dest->isAvatar()) + { + LLNameValue* nvfirst = dest->getNVPair("FirstName"); + LLNameValue* nvlast = dest->getNVPair("LastName"); + if(nvfirst && nvlast) + { + fullname = LLCacheName::buildFullName( + nvfirst->getString(), nvlast->getString()); + + } + if (!fullname.empty()) + { + names.push_back(fullname); + } + else + { + llwarns << "llPanelGroupBulk: Selected avatar has no name: " << dest->getID() << llendl; + names.push_back("(Unknown)"); + } + } + else + { + //looks like user try to invite offline friend + //for offline avatar_id gObjectList.findObject() will return null + //so we need to do this additional search in avatar tracker, see EXT-4732 + if (LLAvatarTracker::instance().isBuddy(agent_id)) + { + LLAvatarName av_name; + if (!LLAvatarNameCache::get(agent_id, &av_name)) + { + // actually it should happen, just in case + LLAvatarNameCache::get(LLUUID(agent_id), boost::bind(&LLPanelGroupBulk::addUserCallback, this, _1, _2)); + // for this special case! + //when there is no cached name we should remove resident from agent_ids list to avoid breaking of sequence + // removed id will be added in callback + agent_ids.erase(agent_ids.begin() + i); + } + else + { + names.push_back(av_name.getAccountName()); + } + } + } + } + mImplementation->mListFullNotificationSent = false; + mImplementation->addUsers(names, agent_ids); +} + diff --git a/indra/newview/llpanelgroupbulk.h b/indra/newview/llpanelgroupbulk.h new file mode 100644 index 0000000000..25ae71ab86 --- /dev/null +++ b/indra/newview/llpanelgroupbulk.h @@ -0,0 +1,74 @@ +/** +* @file llpanelgroupbulk.h +* @brief Header file for llpanelgroupbulk +* @author Baker@lindenlab.com +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, 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_LLPANELGROUPBULK_H +#define LL_LLPANELGROUPBULK_H + +#include "llpanel.h" +#include "lluuid.h" + +class LLAvatarName; +class LLGroupMgrGroupData; +class LLPanelGroupBulkImpl; + +// Base panel class for bulk group invite / ban floaters +class LLPanelGroupBulk : public LLPanel +{ +public: + LLPanelGroupBulk(const LLUUID& group_id); + /*virtual*/ ~LLPanelGroupBulk(); + +public: + static void callbackClickSubmit(void* userdata) {} + virtual void submit() = 0; + +public: + virtual void clear(); + virtual void update(); + virtual void draw(); + +protected: + virtual void updateGroupName(); + virtual void updateGroupData(); + +public: + // this callback is being used to add a user whose fullname isn't been loaded before invoking of addUsers(). + virtual void addUserCallback(const LLUUID& id, const LLAvatarName& av_name); + virtual void setCloseCallback(void (*close_callback)(void*), void* data); + + virtual void addUsers(uuid_vec_t& agent_ids); + +public: + LLPanelGroupBulkImpl* mImplementation; + +protected: + bool mPendingGroupPropertiesUpdate; + bool mPendingRoleDataUpdate; + bool mPendingMemberDataUpdate; +}; + +#endif // LL_LLPANELGROUPBULK_H + diff --git a/indra/newview/llpanelgroupbulkban.cpp b/indra/newview/llpanelgroupbulkban.cpp new file mode 100644 index 0000000000..a31396737d --- /dev/null +++ b/indra/newview/llpanelgroupbulkban.cpp @@ -0,0 +1,170 @@ +/** +* @file llpanelgroupbulkban.cpp +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, 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 "llpanelgroupbulkban.h" +#include "llpanelgroupbulk.h" +#include "llpanelgroupbulkimpl.h" + +#include "llagent.h" +#include "llavatarnamecache.h" +#include "llfloateravatarpicker.h" +#include "llbutton.h" +#include "llcallingcard.h" +#include "llcombobox.h" +#include "llgroupactions.h" +#include "llgroupmgr.h" +#include "llnamelistctrl.h" +#include "llnotificationsutil.h" +#include "llscrolllistitem.h" +#include "llslurl.h" +#include "llspinctrl.h" +#include "lltextbox.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "lluictrlfactory.h" +#include "llviewerwindow.h" + +#include <boost/foreach.hpp> + +LLPanelGroupBulkBan::LLPanelGroupBulkBan(const LLUUID& group_id) : LLPanelGroupBulk(group_id) +{ + // Pass on construction of this panel to the control factory. + buildFromFile( "panel_group_bulk_ban.xml"); +} + +BOOL LLPanelGroupBulkBan::postBuild() +{ + BOOL recurse = TRUE; + + mImplementation->mLoadingText = getString("loading"); + mImplementation->mGroupName = getChild<LLTextBox>("group_name_text", recurse); + mImplementation->mBulkAgentList = getChild<LLNameListCtrl>("banned_agent_list", recurse); + if ( mImplementation->mBulkAgentList ) + { + mImplementation->mBulkAgentList->setCommitOnSelectionChange(TRUE); + mImplementation->mBulkAgentList->setCommitCallback(LLPanelGroupBulkImpl::callbackSelect, mImplementation); + } + + LLButton* button = getChild<LLButton>("add_button", recurse); + if ( button ) + { + // default to opening avatarpicker automatically + // (*impl::callbackClickAdd)((void*)this); + button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickAdd, this); + } + + mImplementation->mRemoveButton = + getChild<LLButton>("remove_button", recurse); + if ( mImplementation->mRemoveButton ) + { + mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation); + mImplementation->mRemoveButton->setEnabled(FALSE); + } + + mImplementation->mOKButton = + getChild<LLButton>("ban_button", recurse); + if ( mImplementation->mOKButton ) + { + mImplementation->mOKButton->setClickedCallback(LLPanelGroupBulkBan::callbackClickSubmit, this); + mImplementation->mOKButton->setEnabled(FALSE); + } + + button = getChild<LLButton>("cancel_button", recurse); + if ( button ) + { + button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation); + } + + mImplementation->mTooManySelected = getString("ban_selection_too_large"); + + update(); + return TRUE; +} + +// TODO: Refactor the shitty callback functions with void* -- just use boost::bind to call submit() instead. +void LLPanelGroupBulkBan::callbackClickSubmit(void* userdata) +{ + LLPanelGroupBulkBan* selfp = (LLPanelGroupBulkBan*)userdata; + + if(selfp) + selfp->submit(); +} + + +void LLPanelGroupBulkBan::submit() +{ + std::vector<LLUUID> banned_agent_list; + std::vector<LLScrollListItem*> agents = mImplementation->mBulkAgentList->getAllData(); + std::vector<LLScrollListItem*>::iterator iter = agents.begin(); + for(;iter != agents.end(); ++iter) + { + LLScrollListItem* agent = *iter; + banned_agent_list.push_back(agent->getUUID()); + } + + const S32 MAX_GROUP_BANS = 100; // Max invites per request. 100 to match server cap. + if (banned_agent_list.size() > MAX_GROUP_BANS) + { + // Fail! + LLSD msg; + msg["MESSAGE"] = mImplementation->mTooManySelected; + LLNotificationsUtil::add("GenericAlert", msg); + (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData); + return; + } + + LLGroupMgrGroupData * group_datap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID); + if (group_datap) + { + BOOST_FOREACH(const LLGroupMgrGroupData::ban_list_t::value_type& group_ban_pair, group_datap->mBanList) + { + const LLUUID& group_ban_agent_id = group_ban_pair.first; + if (std::find(banned_agent_list.begin(), banned_agent_list.end(), group_ban_agent_id) != banned_agent_list.end()) + { + // Fail! + LLAvatarName av_name; + LLAvatarNameCache::get(group_ban_agent_id, &av_name); + + LLStringUtil::format_map_t string_args; + string_args["[RESIDENT]"] = av_name.getDisplayName(); + + LLSD msg; + msg["MESSAGE"] = getString("already_banned", string_args); + LLNotificationsUtil::add("GenericAlert", msg); + (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData); + return; + } + } + } + + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mImplementation->mGroupID, LLGroupMgr::BAN_CREATE | LLGroupMgr::BAN_UPDATE, banned_agent_list); + LLGroupMgr::getInstance()->sendGroupMemberEjects(mImplementation->mGroupID, banned_agent_list); + + //then close + (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData); +} + diff --git a/indra/newview/llpanelgroupbulkban.h b/indra/newview/llpanelgroupbulkban.h new file mode 100644 index 0000000000..0684f365a0 --- /dev/null +++ b/indra/newview/llpanelgroupbulkban.h @@ -0,0 +1,47 @@ +/** +* @file llpanelgroupbulkban.h +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, 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_LLPANELGROUPBULKBAN_H +#define LL_LLPANELGROUPBULKBAN_H + +#include "llpanel.h" +#include "lluuid.h" +#include "llpanelgroupbulk.h" + +class LLAvatarName; + +class LLPanelGroupBulkBan : public LLPanelGroupBulk +{ +public: + LLPanelGroupBulkBan(const LLUUID& group_id); + ~LLPanelGroupBulkBan() {} + + virtual BOOL postBuild(); + + static void callbackClickSubmit(void* userdata); + virtual void submit(); +}; + +#endif // LL_LLPANELGROUPBULKBAN_H diff --git a/indra/newview/llpanelgroupbulkimpl.h b/indra/newview/llpanelgroupbulkimpl.h new file mode 100644 index 0000000000..0bc834d67e --- /dev/null +++ b/indra/newview/llpanelgroupbulkimpl.h @@ -0,0 +1,96 @@ +/** +* @file llpanelgroupbulkimpl.h +* @brief Class definition for implementation class of LLPanelGroupBulk +* @author Baker@lindenlab.com +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, 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_LLPANELGROUPBULKIMPL_H +#define LL_LLPANELGROUPBULKIMPL_H + +#include "llpanel.h" +#include "lluuid.h" + +class LLAvatarName; +class LLNameListCtrl; +class LLTextBox; +class LLComboBox; + +////////////////////////////////////////////////////////////////////////// +// Implementation found in llpanelgroupbulk.cpp +////////////////////////////////////////////////////////////////////////// +class LLPanelGroupBulkImpl +{ +public: + LLPanelGroupBulkImpl(const LLUUID& group_id); + ~LLPanelGroupBulkImpl(); + + static void callbackClickAdd(void* userdata); + static void callbackClickRemove(void* userdata); + + static void callbackClickCancel(void* userdata); + + static void callbackSelect(LLUICtrl* ctrl, void* userdata); + static void callbackAddUsers(const uuid_vec_t& agent_ids, void* user_data); + + static void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, void* user_data); + + void handleRemove(); + void handleSelection(); + + void addUsers(const std::vector<std::string>& names, const uuid_vec_t& agent_ids); + void setGroupName(std::string name); + + +public: + static const S32 MAX_GROUP_INVITES = 100; // Max invites per request. 100 to match server cap. + + + LLUUID mGroupID; + + LLNameListCtrl* mBulkAgentList; + LLButton* mOKButton; + LLButton* mRemoveButton; + LLTextBox* mGroupName; + + std::string mLoadingText; + std::string mTooManySelected; + + std::set<LLUUID> mInviteeIDs; + + void (*mCloseCallback)(void* data); + void* mCloseCallbackUserData; + boost::signals2::connection mAvatarNameCacheConnection; + + // The following are for the LLPanelGroupInvite subclass only. + // These aren't needed for LLPanelGroupBulkBan, but if we have to add another + // group bulk floater for some reason, we'll have these objects too. +public: + LLComboBox* mRoleNames; + std::string mOwnerWarning; + std::string mAlreadyInGroup; + bool mConfirmedOwnerInvite; + bool mListFullNotificationSent; +}; + +#endif // LL_LLPANELGROUPBULKIMPL_H + diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp index dd13e8abf4..236ad861a5 100755 --- a/indra/newview/llpanelgroupinvite.cpp +++ b/indra/newview/llpanelgroupinvite.cpp @@ -260,7 +260,7 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap) //else if they have the limited add to roles power //we add every role the user is in //else we just add to everyone - bool is_owner = member_data->isInRole(gdatap->mOwnerRole); + bool is_owner = member_data->isOwner(); bool can_assign_any = gAgent.hasPowerInGroup(mGroupID, GP_ROLE_ASSIGN_MEMBER); bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID, @@ -492,7 +492,7 @@ void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids) } else { - LL_WARNS() << "llPanelGroupInvite: Selected avatar has no name: " << dest->getID() << LL_ENDL; + llwarns << "llPanelGroupInvite: Selected avatar has no name: " << dest->getID() << llendl; names.push_back("(Unknown)"); } } @@ -579,7 +579,7 @@ void LLPanelGroupInvite::updateLists() { waiting = true; } - if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete()) + if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && gdatap->isRoleMemberDataComplete()) { if ( mImplementation->mRoleNames ) { @@ -607,6 +607,7 @@ void LLPanelGroupInvite::updateLists() { LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID); LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID); + LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mImplementation->mGroupID); LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID); } mPendingUpdate = TRUE; @@ -654,7 +655,7 @@ BOOL LLPanelGroupInvite::postBuild() } mImplementation->mOKButton = - getChild<LLButton>("ok_button", recurse); + getChild<LLButton>("invite_button", recurse); if ( mImplementation->mOKButton ) { mImplementation->mOKButton->setClickedCallback(impl::callbackClickOK, mImplementation); diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 61fa4ea959..2fcaa5666e 100755 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llpanelgrouproles.cpp * @brief Panel for roles information about a particular group. * @@ -32,6 +32,7 @@ #include "llavatarnamecache.h" #include "llbutton.h" #include "llfiltereditor.h" +#include "llfloatergroupbulkban.h" #include "llfloatergroupinvite.h" #include "llavataractions.h" #include "lliconctrl.h" @@ -109,8 +110,10 @@ bool agentCanAddToRole(const LLUUID& group_id, return false; } -// static +// LLPanelGroupRoles ///////////////////////////////////////////////////// + +// static LLPanelGroupRoles::LLPanelGroupRoles() : LLPanelGroupTab(), mCurrentTab(NULL), @@ -297,7 +300,6 @@ bool LLPanelGroupRoles::onModalClose(const LLSD& notification, const LLSD& respo return false; } - bool LLPanelGroupRoles::apply(std::string& mesg) { // Pass this along to the currently visible sub tab. @@ -334,7 +336,6 @@ void LLPanelGroupRoles::update(LLGroupChange gc) { if (mGroupID.isNull()) return; - LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel(); if (panelp) { @@ -351,39 +352,33 @@ void LLPanelGroupRoles::activate() { // Start requesting member and role data if needed. LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); - //if (!gdatap || mFirstUse) + if (!gdatap || !gdatap->isMemberDataComplete() ) { - // Check member data. - - if (!gdatap || !gdatap->isMemberDataComplete() ) - { - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); - } - - // Check role data. - if (!gdatap || !gdatap->isRoleDataComplete() ) - { - // Mildly hackish - clear all pending changes - cancel(); + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); + } - LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID); - } + if (!gdatap || !gdatap->isRoleDataComplete() ) + { + // Mildly hackish - clear all pending changes + cancel(); - // Check role-member mapping data. - if (!gdatap || !gdatap->isRoleMemberDataComplete() ) - { - LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); - } + LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID); + } - // Need this to get base group member powers - if (!gdatap || !gdatap->isGroupPropertiesDataComplete() ) - { - LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID); - } + // Check role-member mapping data. + if (!gdatap || !gdatap->isRoleMemberDataComplete() ) + { + LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); + } - mFirstUse = FALSE; + // Need this to get base group member powers + if (!gdatap || !gdatap->isGroupPropertiesDataComplete() ) + { + LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID); } + mFirstUse = FALSE; + LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel(); if (panelp) panelp->activate(); } @@ -412,15 +407,38 @@ BOOL LLPanelGroupRoles::hasModal() return panelp->hasModal(); } +void LLPanelGroupRoles::setGroupID(const LLUUID& id) +{ + LLPanelGroupTab::setGroupID(id); + + LLPanelGroupMembersSubTab* group_members_tab = findChild<LLPanelGroupMembersSubTab>("members_sub_tab"); + LLPanelGroupRolesSubTab* group_roles_tab = findChild<LLPanelGroupRolesSubTab>("roles_sub_tab"); + LLPanelGroupActionsSubTab* group_actions_tab = findChild<LLPanelGroupActionsSubTab>("actions_sub_tab"); + LLPanelGroupBanListSubTab* group_ban_tab = findChild<LLPanelGroupBanListSubTab>("banlist_sub_tab"); + + if(group_members_tab) group_members_tab->setGroupID(id); + if(group_roles_tab) group_roles_tab->setGroupID(id); + if(group_actions_tab) group_actions_tab->setGroupID(id); + if(group_ban_tab) group_ban_tab->setGroupID(id); + + LLButton* button = getChild<LLButton>("member_invite"); + if ( button ) + button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE)); + + if(mSubTabContainer) + mSubTabContainer->selectTab(1); + group_roles_tab->mFirstOpen = TRUE; + activate(); +} + -//////////////////////////// -// LLPanelGroupSubTab -//////////////////////////// +// LLPanelGroupSubTab //////////////////////////////////////////////////// LLPanelGroupSubTab::LLPanelGroupSubTab() : LLPanelGroupTab(), mHeader(NULL), mFooter(NULL), mActivated(false), + mHasGroupBanPower(false), mSearchEditor(NULL) { } @@ -542,9 +560,10 @@ void LLPanelGroupSubTab::buildActionsList(LLScrollListCtrl* ctrl, return; } + mHasGroupBanPower = false; + std::vector<LLRoleActionSet*>::iterator ras_it = LLGroupMgr::getInstance()->mRoleActionSets.begin(); std::vector<LLRoleActionSet*>::iterator ras_end = LLGroupMgr::getInstance()->mRoleActionSets.end(); - for ( ; ras_it != ras_end; ++ras_it) { buildActionCategory(ctrl, @@ -674,6 +693,31 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, row["columns"][column_index]["value"] = (*ra_it)->mDescription; row["columns"][column_index]["font"] = "SANSSERIF_SMALL"; + if(mHasGroupBanPower) + { + // The ban ability is being set. Prevent these abilities from being manipulated + if((*ra_it)->mPowerBit == GP_MEMBER_EJECT) + { + row["enabled"] = false; + } + else if((*ra_it)->mPowerBit == GP_ROLE_REMOVE_MEMBER) + { + row["enabled"] = false; + } + } + else + { + // The ban ability is not set. Allow these abilities to be manipulated + if((*ra_it)->mPowerBit == GP_MEMBER_EJECT) + { + row["enabled"] = true; + } + else if((*ra_it)->mPowerBit == GP_ROLE_REMOVE_MEMBER) + { + row["enabled"] = true; + } + } + LLScrollListItem* item = ctrl->addElement(row, ADD_BOTTOM, (*ra_it)); if (-1 != check_box_index) @@ -709,6 +753,15 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, check->setTentative(TRUE); } } + + // Regardless of whether or not this ability is allowed by all or some, we want to prevent + // the group managers from accidentally disabling either of the two additional abilities + // tied with GP_GROUP_BAN_ACCESS. + if( (allowed_by_all & GP_GROUP_BAN_ACCESS) == GP_GROUP_BAN_ACCESS || + (allowed_by_some & GP_GROUP_BAN_ACCESS) == GP_GROUP_BAN_ACCESS) + { + mHasGroupBanPower = true; + } } } @@ -728,11 +781,8 @@ void LLPanelGroupSubTab::setFooterEnabled(BOOL enable) } } -//////////////////////////// -// LLPanelGroupMembersSubTab -//////////////////////////// - +// LLPanelGroupMembersSubTab ///////////////////////////////////////////// static LLPanelInjector<LLPanelGroupMembersSubTab> t_panel_group_members_subtab("panel_group_members_subtab"); LLPanelGroupMembersSubTab::LLPanelGroupMembersSubTab() @@ -810,6 +860,13 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root) mEjectBtn->setEnabled(FALSE); } + mBanBtn = parent->getChild<LLButton>("member_ban", recurse); + if(mBanBtn) + { + mBanBtn->setClickedCallback(onBanMember, this); + mBanBtn->setEnabled(FALSE); + } + return TRUE; } @@ -823,34 +880,6 @@ void LLPanelGroupMembersSubTab::setGroupID(const LLUUID& id) LLPanelGroupSubTab::setGroupID(id); } -void LLPanelGroupRolesSubTab::setGroupID(const LLUUID& id) -{ - if(mRolesList) mRolesList->deleteAllItems(); - if(mAssignedMembersList) mAssignedMembersList->deleteAllItems(); - if(mAllowedActionsList) mAllowedActionsList->deleteAllItems(); - - if(mRoleName) mRoleName->clear(); - if(mRoleDescription) mRoleDescription->clear(); - if(mRoleTitle) mRoleTitle->clear(); - - mHasRoleChange = FALSE; - - setFooterEnabled(FALSE); - - LLPanelGroupSubTab::setGroupID(id); -} -void LLPanelGroupActionsSubTab::setGroupID(const LLUUID& id) -{ - if(mActionList) mActionList->deleteAllItems(); - if(mActionRoles) mActionRoles->deleteAllItems(); - if(mActionMembers) mActionMembers->deleteAllItems(); - - if(mActionDescription) mActionDescription->clear(); - - LLPanelGroupSubTab::setGroupID(id); -} - - // static void LLPanelGroupMembersSubTab::onMemberSelect(LLUICtrl* ctrl, void* user_data) { @@ -879,7 +908,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() // Build a vector of all selected members, and gather allowed actions. uuid_vec_t selected_members; - U64 allowed_by_all = 0xffffffffffffLL; + U64 allowed_by_all = GP_ALL_POWERS; //0xFFFFffffFFFFffffLL; U64 allowed_by_some = 0; std::vector<LLScrollListItem*>::iterator itor; @@ -916,8 +945,8 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() LLGroupMgrGroupData::role_list_t::iterator iter = gdatap->mRoles.begin(); LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end(); - BOOL can_eject_members = gAgent.hasPowerInGroup(mGroupID, - GP_MEMBER_EJECT); + BOOL can_ban_members = gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS); + BOOL can_eject_members = gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_EJECT); BOOL member_is_owner = FALSE; for( ; iter != end; ++iter) @@ -964,6 +993,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() { // Can't remove other owners. cb_enable = FALSE; + can_ban_members = FALSE; break; } } @@ -983,14 +1013,14 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() } // If anyone selected is in any role besides 'Everyone' then they can't be ejected. - if (role_id.notNull() && (count > 0)) - { + if (role_id.notNull() && (count > 0)) + { can_eject_members = FALSE; - if (role_id == gdatap->mOwnerRole) - { - member_is_owner = TRUE; - } - } + if (role_id == gdatap->mOwnerRole) + { + member_is_owner = TRUE; + } + } LLRoleData rd; if (gdatap->getRoleData(role_id,rd)) @@ -1047,7 +1077,10 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() mAssignedRolesList->setEnabled(TRUE); if (gAgent.isGodlike()) + { can_eject_members = TRUE; + // can_ban_members = TRUE; + } if (!can_eject_members && !member_is_owner) { @@ -1060,10 +1093,41 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() if ( member_data && member_data->isInRole(gdatap->mOwnerRole) ) { can_eject_members = TRUE; + //can_ban_members = TRUE; } } + + } + + // ... or we can eject them because we have all the requisite powers... + if( gAgent.hasPowerInGroup(mGroupID, GP_ROLE_REMOVE_MEMBER) && + !member_is_owner) + { + if( gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_EJECT)) + { + can_eject_members = TRUE; + } + + if( gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS)) + { + can_ban_members = TRUE; + } + } + + + uuid_vec_t::const_iterator member_iter = selected_members.begin(); + uuid_vec_t::const_iterator member_end = selected_members.end(); + for ( ; member_iter != member_end; ++member_iter) + { + // Don't count the agent. + if ((*member_iter) == gAgent.getID()) + { + can_eject_members = FALSE; + can_ban_members = FALSE; + } } + mBanBtn->setEnabled(can_ban_members); mEjectBtn->setEnabled(can_eject_members); } @@ -1101,61 +1165,26 @@ void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata) } void LLPanelGroupMembersSubTab::handleEjectMembers() -{ +{ + //send down an eject message + uuid_vec_t selected_members; + std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected(); if (selection.empty()) return; - - S32 selection_count = selection.size(); - if (selection_count == 1) - { - LLSD args; - LLUUID selected_avatar = mMembersList->getValue().asUUID(); - std::string fullname = LLSLURL("agent", selected_avatar, "inspect").getSLURLString(); - args["AVATAR_NAME"] = fullname; - LLSD payload; - LLNotificationsUtil::add("EjectGroupMemberWarning", - args, - payload, - boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2)); - } - else - { - LLSD args; - args["COUNT"] = llformat("%d", selection_count); - LLSD payload; - LLNotificationsUtil::add("EjectGroupMembersWarning", - args, - payload, - boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2)); - } -} -bool LLPanelGroupMembersSubTab::handleEjectCallback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) // Eject button + std::vector<LLScrollListItem*>::iterator itor; + for (itor = selection.begin() ; + itor != selection.end(); ++itor) { - //send down an eject message - uuid_vec_t selected_members; - - std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected(); - if (selection.empty()) return false; - - std::vector<LLScrollListItem*>::iterator itor; - for (itor = selection.begin() ; - itor != selection.end(); ++itor) - { - LLUUID member_id = (*itor)->getUUID(); - selected_members.push_back( member_id ); - } - - mMembersList->deleteSelectedItems(); - - sendEjectNotifications(mGroupID, selected_members); - - LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members); + LLUUID member_id = (*itor)->getUUID(); + selected_members.push_back( member_id ); } - return false; + + mMembersList->deleteSelectedItems(); + + sendEjectNotifications(mGroupID, selected_members); + + LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members); } void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members) @@ -1183,12 +1212,11 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, //add that the user is requesting to change the roles for selected //members - U64 powers_all_have = 0xffffffffffffLL; + U64 powers_all_have = GP_ALL_POWERS; U64 powers_some_have = 0; BOOL is_owner_role = ( gdatap->mOwnerRole == role_id ); LLUUID member_id; - std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected(); if (selection.empty()) @@ -1199,7 +1227,6 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, for (std::vector<LLScrollListItem*>::iterator itor = selection.begin() ; itor != selection.end(); ++itor) { - member_id = (*itor)->getUUID(); //see if we requested a change for this member before @@ -1265,7 +1292,6 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, FALSE); } - // static void LLPanelGroupMembersSubTab::onRoleCheck(LLUICtrl* ctrl, void* user_data) { @@ -1690,13 +1716,12 @@ void LLPanelGroupMembersSubTab::updateMembers() return; } - //cleanup list only for first iretation + //cleanup list only for first iteration if(mMemberProgress == gdatap->mMembers.begin()) { mMembersList->deleteAllItems(); } - LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end(); LLTimer update_time; @@ -1749,12 +1774,44 @@ void LLPanelGroupMembersSubTab::updateMembers() handleMemberSelect(); } +void LLPanelGroupMembersSubTab::onBanMember(void* user_data) +{ + LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data); + self->handleBanMember(); +} + +void LLPanelGroupMembersSubTab::handleBanMember() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if(!gdatap) + { + LL_WARNS("Groups") << "Unable to get group data for group " << mGroupID << LL_ENDL; + return; + } + + std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected(); + if(selection.empty()) + { + return; + } + + uuid_vec_t ban_ids; + std::vector<LLScrollListItem*>::iterator itor; + for(itor = selection.begin(); itor != selection.end(); ++itor) + { + LLUUID ban_id = (*itor)->getUUID(); + ban_ids.push_back(ban_id); + + LLGroupBanData ban_data; + gdatap->createBanEntry(ban_id, ban_data); + } + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mGroupID, LLGroupMgr::BAN_CREATE, ban_ids); + handleEjectMembers(); +} -//////////////////////////// -// LLPanelGroupRolesSubTab -//////////////////////////// +// LLPanelGroupRolesSubTab /////////////////////////////////////////////// static LLPanelInjector<LLPanelGroupRolesSubTab> t_panel_group_roles_subtab("panel_group_roles_subtab"); LLPanelGroupRolesSubTab::LLPanelGroupRolesSubTab() @@ -1768,7 +1825,7 @@ LLPanelGroupRolesSubTab::LLPanelGroupRolesSubTab() mMemberVisibleCheck(NULL), mDeleteRoleButton(NULL), mCreateRoleButton(NULL), - + mFirstOpen(TRUE), mHasRoleChange(FALSE) { } @@ -1870,6 +1927,7 @@ void LLPanelGroupRolesSubTab::deactivate() LL_DEBUGS() << "LLPanelGroupRolesSubTab::deactivate()" << LL_ENDL; LLPanelGroupSubTab::deactivate(); + mFirstOpen = FALSE; } bool LLPanelGroupRolesSubTab::needsApply(std::string& mesg) @@ -1877,6 +1935,12 @@ bool LLPanelGroupRolesSubTab::needsApply(std::string& mesg) LL_DEBUGS() << "LLPanelGroupRolesSubTab::needsApply()" << LL_ENDL; LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if(!gdatap) + { + llwarns << "Unable to get group data for group " << mGroupID << llendl; + return false; + } + return (mHasRoleChange // Text changed in current role || (gdatap && gdatap->pendingRoleChanges())); // Pending role changes in the group @@ -1887,7 +1951,7 @@ bool LLPanelGroupRolesSubTab::apply(std::string& mesg) LL_DEBUGS() << "LLPanelGroupRolesSubTab::apply()" << LL_ENDL; saveRoleChanges(true); - + mFirstOpen = FALSE; LLGroupMgr::getInstance()->sendGroupRoleChanges(mGroupID); notifyObservers(); @@ -2024,14 +2088,17 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc) } } - if (!gdatap || !gdatap->isMemberDataComplete()) + if(!mFirstOpen) { - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); - } - - if (!gdatap || !gdatap->isRoleMemberDataComplete()) - { - LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); + if (!gdatap || !gdatap->isMemberDataComplete()) + { + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); + } + + if (!gdatap || !gdatap->isRoleMemberDataComplete()) + { + LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); + } } if ((GC_ROLE_MEMBER_DATA == gc || GC_MEMBER_DATA == gc) @@ -2047,6 +2114,9 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc) void LLPanelGroupRolesSubTab::onRoleSelect(LLUICtrl* ctrl, void* user_data) { LLPanelGroupRolesSubTab* self = static_cast<LLPanelGroupRolesSubTab*>(user_data); + if (!self) + return; + self->handleRoleSelect(); } @@ -2226,40 +2296,115 @@ void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force) LLRoleAction* rap = (LLRoleAction*)action_item->getUserdata(); U64 power = rap->mPowerBit; - if (check->get()) + bool isEnablingAbility = check->get(); + LLRoleData rd; + LLSD args; + + if (isEnablingAbility && + !force && + ((GP_ROLE_ASSIGN_MEMBER == power) || (GP_ROLE_CHANGE_ACTIONS == power) )) { - if (!force && ( (GP_ROLE_ASSIGN_MEMBER == power) - || (GP_ROLE_CHANGE_ACTIONS == power) )) - { - // Uncheck the item, for now. It will be - // checked if they click 'Yes', below. - check->set(FALSE); + // Uncheck the item, for now. It will be + // checked if they click 'Yes', below. + check->set(FALSE); - LLRoleData rd; - LLSD args; + LLRoleData rd; + LLSD args; - if ( gdatap->getRoleData(role_id, rd) ) + if ( gdatap->getRoleData(role_id, rd) ) + { + args["ACTION_NAME"] = rap->mDescription; + args["ROLE_NAME"] = rd.mRoleName; + mHasModal = TRUE; + std::string warning = "AssignDangerousActionWarning"; + if (GP_ROLE_CHANGE_ACTIONS == power) { - args["ACTION_NAME"] = rap->mDescription; - args["ROLE_NAME"] = rd.mRoleName; - mHasModal = TRUE; - std::string warning = "AssignDangerousActionWarning"; - if (GP_ROLE_CHANGE_ACTIONS == power) - { - warning = "AssignDangerousAbilityWarning"; - } - LLNotificationsUtil::add(warning, args, LLSD(), boost::bind(&LLPanelGroupRolesSubTab::addActionCB, this, _1, _2, check)); + warning = "AssignDangerousAbilityWarning"; } - else - { + LLNotificationsUtil::add(warning, args, LLSD(), boost::bind(&LLPanelGroupRolesSubTab::addActionCB, this, _1, _2, check)); + } + else + { LL_WARNS() << "Unable to look up role information for role id: " << role_id << LL_ENDL; + } + } + + if(GP_GROUP_BAN_ACCESS == power) + { + std::string warning = isEnablingAbility ? "AssignBanAbilityWarning" : "RemoveBanAbilityWarning"; + + ////////////////////////////////////////////////////////////////////////// + // Get role data for both GP_ROLE_REMOVE_MEMBER and GP_MEMBER_EJECT + // Add description and role name to LLSD + // Pop up dialog saying "Yo, you also granted these other abilities when you did this!" + if ( gdatap->getRoleData(role_id, rd) ) + { + args["ACTION_NAME"] = rap->mDescription; + args["ROLE_NAME"] = rd.mRoleName; + mHasModal = TRUE; + + std::vector<LLScrollListItem*> all_data = mAllowedActionsList->getAllData(); + std::vector<LLScrollListItem*>::iterator ad_it = all_data.begin(); + std::vector<LLScrollListItem*>::iterator ad_end = all_data.end(); + LLRoleAction* adp; + for( ; ad_it != ad_end; ++ad_it) + { + adp = (LLRoleAction*)(*ad_it)->getUserdata(); + if(adp->mPowerBit == GP_MEMBER_EJECT) + { + args["ACTION_NAME_2"] = adp->mDescription; + } + else if(adp->mPowerBit == GP_ROLE_REMOVE_MEMBER) + { + args["ACTION_NAME_3"] = adp->mDescription; + } } + + LLNotificationsUtil::add(warning, args); + } + else + { + llwarns << "Unable to look up role information for role id: " + << role_id << llendl; + } + + ////////////////////////////////////////////////////////////////////////// + + LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.find(role_id); + U64 current_role_powers = GP_NO_POWERS; + if (rit != gdatap->mRoles.end()) + { + current_role_powers = ((*rit).second->getRoleData().mRolePowers); + } + + if(isEnablingAbility) + { + power |= (GP_ROLE_REMOVE_MEMBER | GP_MEMBER_EJECT); + current_role_powers |= power; } else { - gdatap->addRolePower(role_id,power); + current_role_powers &= ~GP_GROUP_BAN_ACCESS; } + + mAllowedActionsList->deleteAllItems(); + buildActionsList( mAllowedActionsList, + current_role_powers, + current_role_powers, + boost::bind(&LLPanelGroupRolesSubTab::handleActionCheck, this, _1, false), + TRUE, + FALSE, + FALSE); + + } + + ////////////////////////////////////////////////////////////////////////// + // Adding non-specific ability to role + ////////////////////////////////////////////////////////////////////////// + if(isEnablingAbility) + { + gdatap->addRolePower(role_id, power); } else { @@ -2268,6 +2413,7 @@ void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force) mHasRoleChange = TRUE; notifyObservers(); + } bool LLPanelGroupRolesSubTab::addActionCB(const LLSD& notification, const LLSD& response, LLCheckBoxCtrl* check) @@ -2287,7 +2433,6 @@ bool LLPanelGroupRolesSubTab::addActionCB(const LLSD& notification, const LLSD& return false; } - // static void LLPanelGroupRolesSubTab::onPropertiesKey(LLLineEditor* ctrl, void* user_data) { @@ -2465,12 +2610,27 @@ void LLPanelGroupRolesSubTab::saveRoleChanges(bool select_saved_role) mHasRoleChange = FALSE; } } -//////////////////////////// -// LLPanelGroupActionsSubTab -//////////////////////////// -static LLPanelInjector<LLPanelGroupActionsSubTab> t_panel_group_actions_subtab("panel_group_actions_subtab"); +void LLPanelGroupRolesSubTab::setGroupID(const LLUUID& id) +{ + if(mRolesList) mRolesList->deleteAllItems(); + if(mAssignedMembersList) mAssignedMembersList->deleteAllItems(); + if(mAllowedActionsList) mAllowedActionsList->deleteAllItems(); + if(mRoleName) mRoleName->clear(); + if(mRoleDescription) mRoleDescription->clear(); + if(mRoleTitle) mRoleTitle->clear(); + + mHasRoleChange = FALSE; + + setFooterEnabled(FALSE); + + LLPanelGroupSubTab::setGroupID(id); +} + + +// LLPanelGroupActionsSubTab ///////////////////////////////////////////// +static LLPanelInjector<LLPanelGroupActionsSubTab> t_panel_group_actions_subtab("panel_group_actions_subtab"); LLPanelGroupActionsSubTab::LLPanelGroupActionsSubTab() : LLPanelGroupSubTab() @@ -2644,26 +2804,272 @@ void LLPanelGroupActionsSubTab::handleActionSelect() } } -void LLPanelGroupRoles::setGroupID(const LLUUID& id) +void LLPanelGroupActionsSubTab::setGroupID(const LLUUID& id) { - LLPanelGroupTab::setGroupID(id); + if(mActionList) mActionList->deleteAllItems(); + if(mActionRoles) mActionRoles->deleteAllItems(); + if(mActionMembers) mActionMembers->deleteAllItems(); + + if(mActionDescription) mActionDescription->clear(); + + LLPanelGroupSubTab::setGroupID(id); +} + + +// LLPanelGroupBanListSubTab ///////////////////////////////////////////// +static LLPanelInjector<LLPanelGroupBanListSubTab> t_panel_group_ban_subtab("panel_group_banlist_subtab"); + +LLPanelGroupBanListSubTab::LLPanelGroupBanListSubTab() + : LLPanelGroupSubTab(), + mBanList(NULL), + mCreateBanButton(NULL), + mDeleteBanButton(NULL) +{} + +BOOL LLPanelGroupBanListSubTab::postBuildSubTab(LLView* root) +{ + LLPanelGroupSubTab::postBuildSubTab(root); + + // Upcast parent so we can ask it for sibling controls. + LLPanelGroupRoles* parent = (LLPanelGroupRoles*)root; + + // Look recursively from the parent to find all our widgets. + bool recurse = true; - LLPanelGroupMembersSubTab* group_members_tab = findChild<LLPanelGroupMembersSubTab>("members_sub_tab"); - LLPanelGroupRolesSubTab* group_roles_tab = findChild<LLPanelGroupRolesSubTab>("roles_sub_tab"); - LLPanelGroupActionsSubTab* group_actions_tab = findChild<LLPanelGroupActionsSubTab>("actions_sub_tab"); + mHeader = parent->getChild<LLPanel>("banlist_header", recurse); + mFooter = parent->getChild<LLPanel>("banlist_footer", recurse); + + mBanList = parent->getChild<LLNameListCtrl>("ban_list", recurse); + + mCreateBanButton = parent->getChild<LLButton>("ban_create", recurse); + mDeleteBanButton = parent->getChild<LLButton>("ban_delete", recurse); + mRefreshBanListButton = parent->getChild<LLButton>("ban_refresh", recurse); - if(group_members_tab) group_members_tab->setGroupID(id); - if(group_roles_tab) group_roles_tab->setGroupID(id); - if(group_actions_tab) group_actions_tab->setGroupID(id); + if(!mBanList || !mCreateBanButton || !mDeleteBanButton || !mRefreshBanListButton) + return FALSE; - LLButton* button = getChild<LLButton>("member_invite"); - if ( button ) - button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE)); + mBanList->setCommitOnSelectionChange(TRUE); + mBanList->setCommitCallback(onBanEntrySelect, this); - if(mSubTabContainer) - mSubTabContainer->selectTab(1); + mCreateBanButton->setClickedCallback(onCreateBanEntry, this); + mCreateBanButton->setEnabled(FALSE); - activate(); + mDeleteBanButton->setClickedCallback(onDeleteBanEntry, this); + mDeleteBanButton->setEnabled(FALSE); + + mRefreshBanListButton->setClickedCallback(onRefreshBanList, this); + mRefreshBanListButton->setEnabled(FALSE); + + mBanList->setOnNameListCompleteCallback(boost::bind(&LLPanelGroupBanListSubTab::onBanListCompleted, this, _1)); + + populateBanList(); + + setFooterEnabled(FALSE); + return TRUE; } +void LLPanelGroupBanListSubTab::activate() +{ + LLPanelGroupSubTab::activate(); + + mBanList->deselectAllItems(); + mDeleteBanButton->setEnabled(FALSE); + + if (gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS)) + { + mCreateBanButton->setEnabled(TRUE); + } + + // BAKER: Should I really request everytime activate() is called? + // Perhaps I should only do it on a force refresh, or if an action on the list happens... + // Because it's not going to live-update the list anyway... You'd have to refresh if you + // wanted to see someone else's additions anyway... + // + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID); + + setFooterEnabled(FALSE); + update(GC_ALL); +} + +void LLPanelGroupBanListSubTab::update(LLGroupChange gc) +{ + populateBanList(); +} + +void LLPanelGroupBanListSubTab::draw() +{ + LLPanelGroupSubTab::draw(); + + // BAKER: Might be good to put it here instead of update, maybe.. See how often draw gets hit. + //if( + // populateBanList(); +} + +void LLPanelGroupBanListSubTab::onBanEntrySelect(LLUICtrl* ctrl, void* user_data) +{ + LLPanelGroupBanListSubTab* self = static_cast<LLPanelGroupBanListSubTab*>(user_data); + if (!self) + return; + + self->handleBanEntrySelect(); +} + +void LLPanelGroupBanListSubTab::handleBanEntrySelect() +{ + if (gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS)) + { + mDeleteBanButton->setEnabled(TRUE); + } +} + +void LLPanelGroupBanListSubTab::onCreateBanEntry(void* user_data) +{ + LLPanelGroupBanListSubTab* self = static_cast<LLPanelGroupBanListSubTab*>(user_data); + if (!self) + return; + + self->handleCreateBanEntry(); +} + +void LLPanelGroupBanListSubTab::handleCreateBanEntry() +{ + LLFloaterGroupBulkBan::showForGroup(mGroupID); + //populateBanList(); +} + +void LLPanelGroupBanListSubTab::onDeleteBanEntry(void* user_data) +{ + LLPanelGroupBanListSubTab* self = static_cast<LLPanelGroupBanListSubTab*>(user_data); + if (!self) + return; + + self->handleDeleteBanEntry(); +} + +void LLPanelGroupBanListSubTab::handleDeleteBanEntry() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if(!gdatap) + { + LL_WARNS("Groups") << "Unable to get group data for group " << mGroupID << LL_ENDL; + return; + } + + std::vector<LLScrollListItem*> selection = mBanList->getAllSelected(); + if(selection.empty()) + { + return; + } + + bool can_ban_members = false; + if (gAgent.isGodlike() || + gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS)) + { + can_ban_members = true; + } + + // Owners can ban anyone in the group. + LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find(gAgent.getID()); + if (mi != gdatap->mMembers.end()) + { + LLGroupMemberData* member_data = (*mi).second; + if ( member_data && member_data->isInRole(gdatap->mOwnerRole) ) + { + can_ban_members = true; + } + } + + if(!can_ban_members) + return; + + std::vector<LLUUID> ban_ids; + std::vector<LLScrollListItem*>::iterator itor; + for(itor = selection.begin(); itor != selection.end(); ++itor) + { + LLUUID ban_id = (*itor)->getUUID(); + ban_ids.push_back(ban_id); + + gdatap->removeBanEntry(ban_id); + mBanList->removeNameItem(ban_id); + + // Removing an item removes the selection, we shouldn't be able to click + // the button anymore until we reselect another entry. + mDeleteBanButton->setEnabled(FALSE); + } + + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mGroupID, LLGroupMgr::BAN_DELETE, ban_ids); +} + +void LLPanelGroupBanListSubTab::onRefreshBanList(void* user_data) +{ + LLPanelGroupBanListSubTab* self = static_cast<LLPanelGroupBanListSubTab*>(user_data); + if (!self) + return; + + self->handleRefreshBanList(); +} + +void LLPanelGroupBanListSubTab::handleRefreshBanList() +{ + mRefreshBanListButton->setEnabled(FALSE); + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID); +} +void LLPanelGroupBanListSubTab::onBanListCompleted(bool isComplete) +{ + if(isComplete) + { + mRefreshBanListButton->setEnabled(TRUE); + populateBanList(); + } +} + +void LLPanelGroupBanListSubTab::populateBanList() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if(!gdatap) + { + LL_WARNS("Groups") << "Unable to get group data for group " << mGroupID << LL_ENDL; + return; + } + + mBanList->deleteAllItems(); + std::map<LLUUID,LLGroupBanData>::const_iterator entry = gdatap->mBanList.begin(); + for(; entry != gdatap->mBanList.end(); entry++) + { + LLNameListCtrl::NameItem ban_entry; + ban_entry.value = entry->first; + LLGroupBanData bd = entry->second; + + ban_entry.columns.add().column("name").font.name("SANSSERIF_SMALL").style("NORMAL"); + + // Baker TODO: MAINT- + // Check out utc_to_pacific_time() + + std::string ban_date_str = bd.mBanDate.toHTTPDateString("%Y/%m/%d"); +// time_t utc_time; +// utc_time = time_corrected(); +// LLSD substitution; +// substitution["datetime"] = (S32) utc_time; +// LLStringUtil::format (ban_date_str, substitution); + + //LL_INFOS("BAKER") << "[BAKER] BAN_DATE: " << bd.mBanDate.toHTTPDateString("%Y/%m/%d") << LL_ENDL; + //LL_INFOS("BAKER") << "[BAKER] BAN_DATE_MODIFIED: " << ban_date_str << LL_ENDL; + + //ban_entry.columns.add().column("ban_date").value(ban_date_str.font.name("SANSSERIF_SMALL").style("NORMAL"); + ban_entry.columns.add().column("ban_date").value(bd.mBanDate.toHTTPDateString("%Y/%m/%d")).font.name("SANSSERIF_SMALL").style("NORMAL"); + + mBanList->addNameItemRow(ban_entry); + } + + mRefreshBanListButton->setEnabled(TRUE); +} + +void LLPanelGroupBanListSubTab::setGroupID(const LLUUID& id) +{ + if(mBanList) + mBanList->deleteAllItems(); + + setFooterEnabled(FALSE); + LLPanelGroupSubTab::setGroupID(id); +} diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 0cf272f3ee..052f1d2071 100755 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -39,11 +39,9 @@ class LLScrollListCtrl; class LLScrollListItem; class LLTextEditor; -// Forward declare for friend usage. -//virtual BOOL LLPanelGroupSubTab::postBuildSubTab(LLView*); - typedef std::map<std::string,std::string> icon_map_t; + class LLPanelGroupRoles : public LLPanelGroupTab { public: @@ -92,6 +90,7 @@ protected: std::string mWantApplyMesg; }; + class LLPanelGroupSubTab : public LLPanelGroupTab { public: @@ -143,10 +142,14 @@ protected: icon_map_t mActionIcons; bool mActivated; - + + bool mHasGroupBanPower; // Used to communicate between action sets due to the dependency between + // GP_GROUP_BAN_ACCESS and GP_EJECT_MEMBER and GP_ROLE_REMOVE_MEMBER + void setOthersVisible(BOOL b); }; + class LLPanelGroupMembersSubTab : public LLPanelGroupSubTab { public: @@ -173,6 +176,10 @@ public: void handleRoleCheck(const LLUUID& role_id, LLRoleMemberChangeType type); + static void onBanMember(void* user_data); + void handleBanMember(); + + void applyMemberChanges(); bool addOwnerCB(const LLSD& notification, const LLSD& response); @@ -206,6 +213,7 @@ protected: LLScrollListCtrl* mAssignedRolesList; LLScrollListCtrl* mAllowedActionsList; LLButton* mEjectBtn; + LLButton* mBanBtn; BOOL mChanged; BOOL mPendingMemberUpdate; @@ -218,6 +226,7 @@ protected: boost::signals2::connection mAvatarNameCacheConnection; }; + class LLPanelGroupRolesSubTab : public LLPanelGroupSubTab { public: @@ -240,7 +249,7 @@ public: static void onActionCheck(LLUICtrl*, void*); bool addActionCB(const LLSD& notification, const LLSD& response, LLCheckBoxCtrl* check); - + static void onPropertiesKey(LLLineEditor*, void*); void onDescriptionKeyStroke(LLTextEditor* caller); @@ -259,6 +268,9 @@ public: void saveRoleChanges(bool select_saved_role); virtual void setGroupID(const LLUUID& id); + + BOOL mFirstOpen; + protected: void handleActionCheck(LLUICtrl* ctrl, bool force); LLSD createRoleItem(const LLUUID& role_id, std::string name, std::string title, S32 members); @@ -280,6 +292,7 @@ protected: std::string mRemoveEveryoneTxt; }; + class LLPanelGroupActionsSubTab : public LLPanelGroupSubTab { public: @@ -307,4 +320,44 @@ protected: }; +class LLPanelGroupBanListSubTab : public LLPanelGroupSubTab +{ +public: + LLPanelGroupBanListSubTab(); + virtual ~LLPanelGroupBanListSubTab() {} + + virtual BOOL postBuildSubTab(LLView* root); + + virtual void activate(); + virtual void update(LLGroupChange gc); + virtual void draw(); + + static void onBanEntrySelect(LLUICtrl* ctrl, void* user_data); + void handleBanEntrySelect(); + + static void onCreateBanEntry(void* user_data); + void handleCreateBanEntry(); + + static void onDeleteBanEntry(void* user_data); + void handleDeleteBanEntry(); + + static void onRefreshBanList(void* user_data); + void handleRefreshBanList(); + + void onBanListCompleted(bool isComplete); + +protected: + void populateBanList(); + +public: + virtual void setGroupID(const LLUUID& id); + +protected: + LLNameListCtrl* mBanList; + LLButton* mCreateBanButton; + LLButton* mDeleteBanButton; + LLButton* mRefreshBanListButton; + +}; + #endif // LL_LLPANELGROUPROLES_H diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index b941ee1f1b..67cbc91332 100755 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -527,7 +527,7 @@ void LLLandmarksPanel::setParcelID(const LLUUID& parcel_id) } // virtual -void LLLandmarksPanel::setErrorStatus(U32 status, const std::string& reason) +void LLLandmarksPanel::setErrorStatus(S32 status, const std::string& reason) { LL_WARNS() << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<LL_ENDL; } @@ -716,6 +716,11 @@ void LLLandmarksPanel::updateListCommands() mListCommands->getChildView(TRASH_BUTTON_NAME)->setEnabled(trash_enabled); } +void LLLandmarksPanel::updateMenuVisibility(LLUICtrl* menu) +{ + onMenuVisibilityChange(menu, LLSD().with("visibility", true)); +} + void LLLandmarksPanel::onActionsButtonClick() { LLToggleableMenu* menu = mGearFolderMenu; diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 8fae0f0b67..c11cbe05ae 100755 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -80,6 +80,8 @@ public: LLPlacesInventoryPanel* getLibraryInventoryPanel() { return mLibraryInventoryPanel; } + void updateMenuVisibility(LLUICtrl* menu); + protected: /** * @return true - if current selected panel is not null and selected item is a landmark @@ -106,7 +108,7 @@ protected: //LLRemoteParcelInfoObserver interface /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); /*virtual*/ void setParcelID(const LLUUID& parcel_id); - /*virtual*/ void setErrorStatus(U32 status, const std::string& reason); + /*virtual*/ void setErrorStatus(S32 status, const std::string& reason); private: void initFavoritesInventoryPanel(); diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index e2b4d098e9..088eaa8e0d 100755 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -421,7 +421,7 @@ void LLPanelLogin::showLoginWidgets() sInstance->reshapeBrowser(); // *TODO: Append all the usual login parameters, like first_login=Y etc. std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage(); - web_browser->navigateTo( splash_screen_url, "text/html" ); + web_browser->navigateTo( splash_screen_url, HTTP_CONTENT_TEXT_HTML ); LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo"); username_combo->setFocus(TRUE); } @@ -785,7 +785,7 @@ void LLPanelLogin::loadLoginPage() if (web_browser->getCurrentNavUrl() != login_uri.asString()) { LL_DEBUGS("AppInit") << "loading: " << login_uri << LL_ENDL; - web_browser->navigateTo( login_uri.asString(), "text/html" ); + web_browser->navigateTo( login_uri.asString(), HTTP_CONTENT_TEXT_HTML ); } } diff --git a/indra/newview/llpanelmarketplaceinboxinventory.cpp b/indra/newview/llpanelmarketplaceinboxinventory.cpp index 2f65bedc2b..f7c2f629ec 100755 --- a/indra/newview/llpanelmarketplaceinboxinventory.cpp +++ b/indra/newview/llpanelmarketplaceinboxinventory.cpp @@ -129,11 +129,11 @@ void LLInboxFolderViewFolder::addItem(LLFolderViewItem* item) // virtual void LLInboxFolderViewFolder::draw() { - if (!badgeHasParent()) + if (!hasBadgeHolderParent()) { - addBadgeToParentPanel(); + addBadgeToParentHolder(); } - + setBadgeVisibility(mFresh); LLFolderViewFolder::draw(); @@ -214,9 +214,9 @@ BOOL LLInboxFolderViewItem::handleDoubleClick(S32 x, S32 y, MASK mask) // virtual void LLInboxFolderViewItem::draw() { - if (!badgeHasParent()) + if (!hasBadgeHolderParent()) { - addBadgeToParentPanel(); + addBadgeToParentHolder(); } setBadgeVisibility(mFresh); diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index 74c810ea79..1cdd1b664e 100755 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -876,7 +876,10 @@ void LLPanelNearByMedia::onClickParcelAudioPlay() // playing and updated as they cross to other parcels etc. mParcelAudioAutoStart = true; if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; return; + } if (LLAudioEngine::AUDIO_PAUSED == gAudiop->isInternetStreamPlaying()) { @@ -896,7 +899,10 @@ void LLPanelNearByMedia::onClickParcelAudioStop() // they explicitly start it again. mParcelAudioAutoStart = false; if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; return; + } LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade(); } @@ -904,7 +910,10 @@ void LLPanelNearByMedia::onClickParcelAudioStop() void LLPanelNearByMedia::onClickParcelAudioPause() { if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; return; + } // 'true' means pause gAudiop->pauseInternetStream(true); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 77bfcec4e0..665b9ab294 100755 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1491,7 +1491,8 @@ LLPanelObjectInventory::LLPanelObjectInventory(const LLPanelObjectInventory::Par mFolders(NULL), mHaveInventory(FALSE), mIsInventoryEmpty(TRUE), - mInventoryNeedsUpdate(FALSE) + mInventoryNeedsUpdate(FALSE), + mInventoryViewModel(p.name) { // Setup context menu callbacks mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelObjectInventory::doToSelected, this, _2)); @@ -2010,3 +2011,46 @@ void LLPanelObjectInventory::clearItemIDs() mItemMap.clear(); } +BOOL LLPanelObjectInventory::handleKeyHere( KEY key, MASK mask ) +{ + BOOL handled = FALSE; + switch (key) + { + case KEY_DELETE: + case KEY_BACKSPACE: + // Delete selected items if delete or backspace key hit on the inventory panel + // Note: on Mac laptop keyboards, backspace and delete are one and the same + if (isSelectionRemovable() && mask == MASK_NONE) + { + LLInventoryAction::doToSelected(&gInventory, mFolders, "delete"); + handled = TRUE; + } + break; + } + return handled; +} + +BOOL LLPanelObjectInventory::isSelectionRemovable() +{ + if (!mFolders || !mFolders->getRoot()) + { + return FALSE; + } + std::set<LLFolderViewItem*> selection_set = mFolders->getRoot()->getSelectionList(); + if (selection_set.empty()) + { + return FALSE; + } + for (std::set<LLFolderViewItem*>::iterator iter = selection_set.begin(); + iter != selection_set.end(); + ++iter) + { + LLFolderViewItem *item = *iter; + const LLFolderViewModelItemInventory *listener = dynamic_cast<const LLFolderViewModelItemInventory*>(item->getViewModelItem()); + if (!listener || !listener->isItemRemovable() || listener->isItemInTrash()) + { + return FALSE; + } + } + return TRUE; +} diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h index f497c695b3..9559f7e886 100755 --- a/indra/newview/llpanelobjectinventory.h +++ b/indra/newview/llpanelobjectinventory.h @@ -94,6 +94,9 @@ protected: void removeItemID(const LLUUID& id); void clearItemIDs(); + BOOL handleKeyHere( KEY key, MASK mask ); + BOOL isSelectionRemovable(); + private: std::map<LLUUID, LLFolderViewItem*> mItemMap; diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index e48aa88937..496168229d 100755 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -159,6 +159,7 @@ public: registrar.add("Wearable.Create", boost::bind(onCreate, _2)); + llassert(LLMenuGL::sMenuContainer != NULL); LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>( "menu_cof_gear.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); llassert(menu); @@ -228,6 +229,7 @@ public: enable_registrar.add("AddWearable.Gear.Check", boost::bind(onCheck, flat_list_handle, inventory_panel_handle, _2)); enable_registrar.add("AddWearable.Gear.Visible", boost::bind(onVisible, inventory_panel_handle, _2)); + llassert(LLMenuGL::sMenuContainer != NULL); LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>( "menu_add_wearable_gear.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); @@ -1184,12 +1186,12 @@ BOOL LLPanelOutfitEdit::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, * second argument is used to delay the appearance update until all dragged items * are added to optimize user experience. */ - LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), false); + LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID()); } else { // if asset id is not available for the item we must wear it immediately (attachments only) - LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), true); + LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), new LLUpdateAppearanceAndEditWearableOnDestroy(item->getUUID())); } } diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index 3c72607678..1e1f59055f 100755 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -76,7 +76,8 @@ BOOL LLPanelOutfitsInventory::postBuild() // Fetch your outfits folder so that the links are in memory. // ( This is only necessary if we want to show a warning if a user deletes an item that has a // a link in an outfit, see "ConfirmItemDeleteHasLinks". ) - const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTFIT, false); + + const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); if (outfits_cat.notNull()) { LLInventoryModelBackgroundFetch::instance().start(outfits_cat); @@ -183,7 +184,7 @@ bool LLPanelOutfitsInventory::onSaveCommit(const LLSD& notification, const LLSD& LLStringUtil::trim(outfit_name); if( !outfit_name.empty() ) { - LLUUID outfit_folder = LLAppearanceMgr::getInstance()->makeNewOutfitLinks(outfit_name); + LLAppearanceMgr::getInstance()->makeNewOutfitLinks(outfit_name); LLSidepanelAppearance* panel_appearance = getAppearanceSP(); if (panel_appearance) diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h index 3c1f14759c..7a8bd66fcf 100755 --- a/indra/newview/llpanelpick.h +++ b/indra/newview/llpanelpick.h @@ -86,7 +86,7 @@ public: //This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); /*virtual*/ void setParcelID(const LLUUID& parcel_id) { mParcelId = parcel_id; } - /*virtual*/ void setErrorStatus(U32 status, const std::string& reason) {}; + /*virtual*/ void setErrorStatus(S32 status, const std::string& reason) {}; protected: diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index 4ae0c0eb12..4e7c5f6ed2 100755 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -169,15 +169,15 @@ void LLPanelPlaceInfo::displayParcelInfo(const LLUUID& region_id, } // virtual -void LLPanelPlaceInfo::setErrorStatus(U32 status, const std::string& reason) +void LLPanelPlaceInfo::setErrorStatus(S32 status, const std::string& reason) { // We only really handle 404 and 499 errors std::string error_text; - if(status == 404) + if(status == HTTP_NOT_FOUND) { error_text = getString("server_error_text"); } - else if(status == 499) + else if(status == HTTP_INTERNAL_ERROR) { error_text = getString("server_forbidden_text"); } diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index 64f0b6b550..30327378ef 100755 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -86,7 +86,7 @@ public: void displayParcelInfo(const LLUUID& region_id, const LLVector3d& pos_global); - /*virtual*/ void setErrorStatus(U32 status, const std::string& reason); + /*virtual*/ void setErrorStatus(S32 status, const std::string& reason); /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp index e501486ecb..d3a7f9bb75 100755 --- a/indra/newview/llpanelplaceprofile.cpp +++ b/indra/newview/llpanelplaceprofile.cpp @@ -483,8 +483,9 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel, gCacheName->getGroup(parcel->getGroupID(), boost::bind(&LLPanelPlaceInfo::onNameCache, mRegionGroupText, _2)); - gCacheName->getGroup(parcel->getGroupID(), - boost::bind(&LLPanelPlaceInfo::onNameCache, mParcelOwner, _2)); + std::string owner = + LLSLURL("group", parcel->getGroupID(), "inspect").getSLURLString(); + mParcelOwner->setText(owner); } else { diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index c05b379fd8..2be96b9b78 100755 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -168,8 +168,7 @@ public: protected: /*virtual*/ void done() { - mPlaces->showAddedLandmarkInfo(mAdded); - mAdded.clear(); + mPlaces->showAddedLandmarkInfo(gInventory.getAddedIDs()); } private: @@ -217,7 +216,7 @@ public: LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id); } } - /*virtual*/ void setErrorStatus(U32 status, const std::string& reason) + /*virtual*/ void setErrorStatus(S32 status, const std::string& reason) { LL_ERRS() << "Can't complete remote parcel request. Http Status: " << status << ". Reason : " << reason << LL_ENDL; @@ -1100,9 +1099,9 @@ void LLPanelPlaces::changedGlobalPos(const LLVector3d &global_pos) updateVerbs(); } -void LLPanelPlaces::showAddedLandmarkInfo(const uuid_vec_t& items) +void LLPanelPlaces::showAddedLandmarkInfo(const uuid_set_t& items) { - for (uuid_vec_t::const_iterator item_iter = items.begin(); + for (uuid_set_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter) { diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h index b6019ca32e..c3d1b9bc53 100755 --- a/indra/newview/llpanelplaces.h +++ b/indra/newview/llpanelplaces.h @@ -69,7 +69,7 @@ public: void changedGlobalPos(const LLVector3d &global_pos); // Opens landmark info panel when agent creates or receives landmark. - void showAddedLandmarkInfo(const uuid_vec_t& items); + void showAddedLandmarkInfo(const uuid_set_t& items); void setItem(LLInventoryItem* item); diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index 8fddd9523f..652d2be6f6 100755 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -341,6 +341,7 @@ LLContextMenu* LLTeleportHistoryPanel::ContextMenu::createMenu() registrar.add("TeleportHistory.CopyToClipboard",boost::bind(&LLTeleportHistoryPanel::ContextMenu::onCopyToClipboard, this)); // create the context menu from the XUI + llassert(LLMenuGL::sMenuContainer != NULL); return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( "menu_teleport_history_item.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); } @@ -935,6 +936,7 @@ void LLTeleportHistoryPanel::onAccordionTabRightClick(LLView *view, S32 x, S32 y registrar.add("TeleportHistory.TabClose", boost::bind(&LLTeleportHistoryPanel::onAccordionTabClose, this, tab)); // create the context menu from the XUI + llassert(LLMenuGL::sMenuContainer != NULL); mAccordionTabMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( "menu_teleport_history_tab.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index ae5b3b4e76..4977a72dc6 100755 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -103,17 +103,16 @@ LLHTTPRegistration<LLAgentStateChangeNode> gHTTPRegistrationAgentStateChangeNode class NavMeshStatusResponder : public LLHTTPClient::Responder { + LOG_CLASS(NavMeshStatusResponder); public: - NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly); + NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly); virtual ~NavMeshStatusResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); - protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LLViewerRegion *mRegion; LLUUID mRegionUUID; bool mIsGetStatusOnly; @@ -125,17 +124,16 @@ private: class NavMeshResponder : public LLHTTPClient::Responder { + LOG_CLASS(NavMeshResponder); public: - NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr); + NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr); virtual ~NavMeshResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); - protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; U32 mNavMeshVersion; LLPathfindingNavMeshPtr mNavMeshPtr; }; @@ -146,17 +144,14 @@ private: class AgentStateResponder : public LLHTTPClient::Responder { + LOG_CLASS(AgentStateResponder); public: - AgentStateResponder(const std::string &pCapabilityURL); + AgentStateResponder(); virtual ~AgentStateResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); - protected: - -private: - std::string mCapabilityURL; + virtual void httpSuccess(); + virtual void httpFailure(); }; @@ -165,17 +160,16 @@ private: //--------------------------------------------------------------------------- class NavMeshRebakeResponder : public LLHTTPClient::Responder { + LOG_CLASS(NavMeshRebakeResponder); public: - NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback); + NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback); virtual ~NavMeshRebakeResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); - protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LLPathfindingManager::rebake_navmesh_callback_t mRebakeNavMeshCallback; }; @@ -190,11 +184,9 @@ public: virtual ~LinksetsResponder(); void handleObjectLinksetsResult(const LLSD &pContent); - void handleObjectLinksetsError(U32 pStatus, const std::string &pReason, - const LLSD& pContent, const std::string &pURL); + void handleObjectLinksetsError(); void handleTerrainLinksetsResult(const LLSD &pContent); - void handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, - const LLSD& pContent, const std::string &pURL); + void handleTerrainLinksetsError(); protected: @@ -227,17 +219,16 @@ typedef boost::shared_ptr<LinksetsResponder> LinksetsResponderPtr; class ObjectLinksetsResponder : public LLHTTPClient::Responder { + LOG_CLASS(ObjectLinksetsResponder); public: - ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr); + ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr); virtual ~ObjectLinksetsResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent); - protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LinksetsResponderPtr mLinksetsResponsderPtr; }; @@ -247,17 +238,16 @@ private: class TerrainLinksetsResponder : public LLHTTPClient::Responder { + LOG_CLASS(TerrainLinksetsResponder); public: - TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr); + TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr); virtual ~TerrainLinksetsResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent); - protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LinksetsResponderPtr mLinksetsResponsderPtr; }; @@ -267,17 +257,16 @@ private: class CharactersResponder : public LLHTTPClient::Responder { + LOG_CLASS(TerrainLinksetsResponder); public: - CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback); + CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback); virtual ~CharactersResponder(); - virtual void result(const LLSD &pContent); - virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent); - protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LLPathfindingManager::request_id_t mRequestId; LLPathfindingManager::object_request_callback_t mCharactersCallback; }; @@ -364,7 +353,7 @@ void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion, b std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion); llassert(!navMeshStatusURL.empty()); navMeshPtr->handleNavMeshCheckVersion(); - LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(navMeshStatusURL, pRegion, pIsGetStatusOnly); + LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(pRegion, pIsGetStatusOnly); LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder); } } @@ -398,12 +387,12 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re bool doRequestTerrain = isAllowViewTerrainProperties(); LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain)); - LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); + LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr); LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder); if (doRequestTerrain) { - LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); + LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr); LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder); } } @@ -447,13 +436,13 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP if (!objectPostData.isUndefined()) { - LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); + LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr); LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder); } if (!terrainPostData.isUndefined()) { - LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); + LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr); LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder); } } @@ -486,7 +475,7 @@ void LLPathfindingManager::requestGetCharacters(request_id_t pRequestId, object_ { pCharactersCallback(pRequestId, kRequestStarted, emptyCharacterListPtr); - LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(charactersURL, pRequestId, pCharactersCallback); + LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(pRequestId, pCharactersCallback); LLHTTPClient::get(charactersURL, charactersResponder); } } @@ -519,7 +508,7 @@ void LLPathfindingManager::requestGetAgentState() { std::string agentStateURL = getAgentStateURLForRegion(currentRegion); llassert(!agentStateURL.empty()); - LLHTTPClient::ResponderPtr responder = new AgentStateResponder(agentStateURL); + LLHTTPClient::ResponderPtr responder = new AgentStateResponder(); LLHTTPClient::get(agentStateURL, responder); } } @@ -543,7 +532,7 @@ void LLPathfindingManager::requestRebakeNavMesh(rebake_navmesh_callback_t pRebak llassert(!navMeshStatusURL.empty()); LLSD postData; postData["command"] = "rebuild"; - LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(navMeshStatusURL, pRebakeNavMeshCallback); + LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(pRebakeNavMeshCallback); LLHTTPClient::post(navMeshStatusURL, postData, responder); } } @@ -565,7 +554,7 @@ void LLPathfindingManager::sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPt else { navMeshPtr->handleNavMeshStart(pNavMeshStatus); - LLHTTPClient::ResponderPtr responder = new NavMeshResponder(navMeshURL, pNavMeshStatus.getVersion(), navMeshPtr); + LLHTTPClient::ResponderPtr responder = new NavMeshResponder(pNavMeshStatus.getVersion(), navMeshPtr); LLSD postData; LLHTTPClient::post(navMeshURL, postData, responder); @@ -779,9 +768,8 @@ void LLAgentStateChangeNode::post(ResponsePtr pResponse, const LLSD &pContext, c // NavMeshStatusResponder //--------------------------------------------------------------------------- -NavMeshStatusResponder::NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly) +NavMeshStatusResponder::NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly) : LLHTTPClient::Responder(), - mCapabilityURL(pCapabilityURL), mRegion(pRegion), mRegionUUID(), mIsGetStatusOnly(pIsGetStatusOnly) @@ -796,15 +784,15 @@ NavMeshStatusResponder::~NavMeshStatusResponder() { } -void NavMeshStatusResponder::result(const LLSD &pContent) +void NavMeshStatusResponder::httpSuccess() { - LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, pContent); + LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, getContent()); LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly); } -void NavMeshStatusResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void NavMeshStatusResponder::httpFailure() { - LL_WARNS() << "NavMeshStatusResponder error [status:" << pStatus << "]: " << pContent << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID); LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly); } @@ -813,9 +801,8 @@ void NavMeshStatusResponder::errorWithContent(U32 pStatus, const std::string& pR // NavMeshResponder //--------------------------------------------------------------------------- -NavMeshResponder::NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr) +NavMeshResponder::NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr) : LLHTTPClient::Responder(), - mCapabilityURL(pCapabilityURL), mNavMeshVersion(pNavMeshVersion), mNavMeshPtr(pNavMeshPtr) { @@ -825,23 +812,23 @@ NavMeshResponder::~NavMeshResponder() { } -void NavMeshResponder::result(const LLSD &pContent) +void NavMeshResponder::httpSuccess() { - mNavMeshPtr->handleNavMeshResult(pContent, mNavMeshVersion); + mNavMeshPtr->handleNavMeshResult(getContent(), mNavMeshVersion); } -void NavMeshResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void NavMeshResponder::httpFailure() { - mNavMeshPtr->handleNavMeshError(pStatus, pReason, pContent, mCapabilityURL, mNavMeshVersion); + LL_WARNS() << dumpResponse() << LL_ENDL; + mNavMeshPtr->handleNavMeshError(mNavMeshVersion); } //--------------------------------------------------------------------------- // AgentStateResponder //--------------------------------------------------------------------------- -AgentStateResponder::AgentStateResponder(const std::string &pCapabilityURL) +AgentStateResponder::AgentStateResponder() : LLHTTPClient::Responder() -, mCapabilityURL(pCapabilityURL) { } @@ -849,17 +836,18 @@ AgentStateResponder::~AgentStateResponder() { } -void AgentStateResponder::result(const LLSD &pContent) +void AgentStateResponder::httpSuccess() { + const LLSD& pContent = getContent(); llassert(pContent.has(AGENT_STATE_CAN_REBAKE_REGION_FIELD)); llassert(pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).isBoolean()); BOOL canRebakeRegion = pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).asBoolean(); LLPathfindingManager::getInstance()->handleAgentState(canRebakeRegion); } -void AgentStateResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void AgentStateResponder::httpFailure() { - LL_WARNS() << "AgentStateResponder error [status:" << pStatus << "]: " << pContent << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; LLPathfindingManager::getInstance()->handleAgentState(FALSE); } @@ -867,9 +855,8 @@ void AgentStateResponder::errorWithContent(U32 pStatus, const std::string &pReas //--------------------------------------------------------------------------- // navmesh rebake responder //--------------------------------------------------------------------------- -NavMeshRebakeResponder::NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback) +NavMeshRebakeResponder::NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback) : LLHTTPClient::Responder(), - mCapabilityURL(pCapabilityURL), mRebakeNavMeshCallback(pRebakeNavMeshCallback) { } @@ -878,14 +865,14 @@ NavMeshRebakeResponder::~NavMeshRebakeResponder() { } -void NavMeshRebakeResponder::result(const LLSD &pContent) +void NavMeshRebakeResponder::httpSuccess() { mRebakeNavMeshCallback(true); } -void NavMeshRebakeResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void NavMeshRebakeResponder::httpFailure() { - LL_WARNS() << "NavMeshRebakeResponder error [status:" << pStatus << "]: " << pContent << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; mRebakeNavMeshCallback(false); } @@ -918,11 +905,9 @@ void LinksetsResponder::handleObjectLinksetsResult(const LLSD &pContent) } } -void LinksetsResponder::handleObjectLinksetsError(U32 pStatus, const std::string &pReason, - const LLSD& pContent, const std::string &pURL) +void LinksetsResponder::handleObjectLinksetsError() { - LL_WARNS() << "LinksetsResponder object linksets error with request to URL '" << pURL << "' [status:" - << pStatus << "]: " << pContent << LL_ENDL; + LL_WARNS() << "LinksetsResponder object linksets error" << LL_ENDL; mObjectMessagingState = kReceivedError; if (mTerrainMessagingState != kWaiting) { @@ -941,11 +926,9 @@ void LinksetsResponder::handleTerrainLinksetsResult(const LLSD &pContent) } } -void LinksetsResponder::handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, - const LLSD& pContent, const std::string &pURL) +void LinksetsResponder::handleTerrainLinksetsError() { - LL_WARNS() << "LinksetsResponder terrain linksets error with request to URL '" << pURL << "' [status:" - << pStatus << "]: " << pContent << LL_ENDL; + LL_WARNS() << "LinksetsResponder terrain linksets error" << LL_ENDL; mTerrainMessagingState = kReceivedError; if (mObjectMessagingState != kWaiting) { @@ -979,9 +962,8 @@ void LinksetsResponder::sendCallback() // ObjectLinksetsResponder //--------------------------------------------------------------------------- -ObjectLinksetsResponder::ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) +ObjectLinksetsResponder::ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr) : LLHTTPClient::Responder(), - mCapabilityURL(pCapabilityURL), mLinksetsResponsderPtr(pLinksetsResponsderPtr) { } @@ -990,23 +972,23 @@ ObjectLinksetsResponder::~ObjectLinksetsResponder() { } -void ObjectLinksetsResponder::result(const LLSD &pContent) +void ObjectLinksetsResponder::httpSuccess() { - mLinksetsResponsderPtr->handleObjectLinksetsResult(pContent); + mLinksetsResponsderPtr->handleObjectLinksetsResult(getContent()); } -void ObjectLinksetsResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void ObjectLinksetsResponder::httpFailure() { - mLinksetsResponsderPtr->handleObjectLinksetsError(pStatus, pReason, pContent, mCapabilityURL); + LL_WARNS() << dumpResponse() << LL_ENDL; + mLinksetsResponsderPtr->handleObjectLinksetsError(); } //--------------------------------------------------------------------------- // TerrainLinksetsResponder //--------------------------------------------------------------------------- -TerrainLinksetsResponder::TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) +TerrainLinksetsResponder::TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr) : LLHTTPClient::Responder(), - mCapabilityURL(pCapabilityURL), mLinksetsResponsderPtr(pLinksetsResponsderPtr) { } @@ -1015,23 +997,23 @@ TerrainLinksetsResponder::~TerrainLinksetsResponder() { } -void TerrainLinksetsResponder::result(const LLSD &pContent) +void TerrainLinksetsResponder::httpSuccess() { - mLinksetsResponsderPtr->handleTerrainLinksetsResult(pContent); + mLinksetsResponsderPtr->handleTerrainLinksetsResult(getContent()); } -void TerrainLinksetsResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void TerrainLinksetsResponder::httpFailure() { - mLinksetsResponsderPtr->handleTerrainLinksetsError(pStatus, pReason, pContent, mCapabilityURL); + LL_WARNS() << dumpResponse() << LL_ENDL; + mLinksetsResponsderPtr->handleTerrainLinksetsError(); } //--------------------------------------------------------------------------- // CharactersResponder //--------------------------------------------------------------------------- -CharactersResponder::CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback) +CharactersResponder::CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback) : LLHTTPClient::Responder(), - mCapabilityURL(pCapabilityURL), mRequestId(pRequestId), mCharactersCallback(pCharactersCallback) { @@ -1041,15 +1023,15 @@ CharactersResponder::~CharactersResponder() { } -void CharactersResponder::result(const LLSD &pContent) +void CharactersResponder::httpSuccess() { - LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(pContent)); + LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(getContent())); mCharactersCallback(mRequestId, LLPathfindingManager::kRequestCompleted, characterListPtr); } -void CharactersResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void CharactersResponder::httpFailure() { - LL_WARNS() << "CharactersResponder error [status:" << pStatus << "]: " << pContent << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList()); mCharactersCallback(mRequestId, LLPathfindingManager::kRequestError, characterListPtr); diff --git a/indra/newview/llpathfindingnavmesh.cpp b/indra/newview/llpathfindingnavmesh.cpp index 40f5d8c23e..0287c07f96 100755 --- a/indra/newview/llpathfindingnavmesh.cpp +++ b/indra/newview/llpathfindingnavmesh.cpp @@ -184,10 +184,8 @@ void LLPathfindingNavMesh::handleNavMeshError() setRequestStatus(kNavMeshRequestError); } -void LLPathfindingNavMesh::handleNavMeshError(U32 pStatus, const std::string &pReason, const LLSD& pContent, const std::string &pURL, U32 pNavMeshVersion) +void LLPathfindingNavMesh::handleNavMeshError(U32 pNavMeshVersion) { - LL_WARNS() << "LLPathfindingNavMesh error with request to URL '" << pURL << "' [status:" - << pStatus << "]: " << pContent << LL_ENDL; if (mNavMeshStatus.getVersion() == pNavMeshVersion) { handleNavMeshError(); diff --git a/indra/newview/llpathfindingnavmesh.h b/indra/newview/llpathfindingnavmesh.h index b872ccad7c..87f32b8d56 100755 --- a/indra/newview/llpathfindingnavmesh.h +++ b/indra/newview/llpathfindingnavmesh.h @@ -74,7 +74,7 @@ public: void handleNavMeshResult(const LLSD &pContent, U32 pNavMeshVersion); void handleNavMeshNotEnabled(); void handleNavMeshError(); - void handleNavMeshError(U32 pStatus, const std::string &pReason, const LLSD& pContent, const std::string &pURL, U32 pNavMeshVersion); + void handleNavMeshError(U32 pNavMeshVersion); protected: diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index 05ef436bd9..ea10d03264 100755 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -668,9 +668,7 @@ BOOL LLPhysicsMotion::onUpdate(F32 time) if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) && (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT)) { - mCharacter->setVisualParamWeight(driver_param, - 0, - FALSE); + mCharacter->setVisualParamWeight(driver_param, 0); } S32 num_driven = driver_param->getDrivenParamsCount(); for (S32 i = 0; i < num_driven; ++i) @@ -770,7 +768,5 @@ void LLPhysicsMotion::setParamValue(const LLViewerVisualParam *param, // Scale from [0,1] to [value_min_local,value_max_local] const F32 new_value_local = value_min_local + (value_max_local-value_min_local) * new_value_rescaled; - mCharacter->setVisualParamWeight(param, - new_value_local, - FALSE); + mCharacter->setVisualParamWeight(param, new_value_local); } diff --git a/indra/newview/llplacesfolderview.cpp b/indra/newview/llplacesfolderview.cpp index 9e1b75b7e9..fe89c1e314 100755 --- a/indra/newview/llplacesfolderview.cpp +++ b/indra/newview/llplacesfolderview.cpp @@ -31,6 +31,7 @@ #include "llplacesinventorypanel.h" #include "llpanellandmarks.h" +#include "llmenugl.h" LLPlacesFolderView::LLPlacesFolderView(const LLFolderView::Params& p) : LLFolderView(p) @@ -67,6 +68,16 @@ BOOL LLPlacesFolderView::handleRightMouseDown(S32 x, S32 y, MASK mask) return LLFolderView::handleRightMouseDown(x, y, mask); } +void LLPlacesFolderView::updateMenu() +{ + LLFolderView::updateMenu(); + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if (menu && menu->getVisible()) + { + mParentLandmarksPanel->updateMenuVisibility(menu); + } +} + void LLPlacesFolderView::setupMenuHandle(LLInventoryType::EType asset_type, LLHandle<LLView> menu_handle) { mMenuHandlesByInventoryType[asset_type] = menu_handle; diff --git a/indra/newview/llplacesfolderview.h b/indra/newview/llplacesfolderview.h index 8c5be39b5e..65fe76007a 100755 --- a/indra/newview/llplacesfolderview.h +++ b/indra/newview/llplacesfolderview.h @@ -51,6 +51,8 @@ public: */ /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + /*virtual*/ void updateMenu(); + void setupMenuHandle(LLInventoryType::EType asset_type, LLHandle<LLView> menu_handle); void setParentLandmarksPanel(LLLandmarksPanel* panel) diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index b379ef7bdb..6d032ad3d3 100755 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -400,13 +400,6 @@ void LLPreview::onDiscardBtn(void* data) self->mForceClose = TRUE; self->closeFloater(); - // Delete the item entirely - /* - item->removeFromServer(); - gInventory.deleteObject(item->getUUID()); - gInventory.notifyObservers(); - */ - // Move the item to the trash const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if (item->getParentUUID() != trash_id) diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 870304a7b8..e694045f9a 100755 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -192,11 +192,11 @@ public: private: LLScriptEdCore* mEditorCore; - static LLFloaterScriptSearch* sInstance; protected: LLLineEditor* mSearchBox; + LLLineEditor* mReplaceBox; void onSearchBoxCommit(); }; @@ -205,6 +205,7 @@ LLFloaterScriptSearch* LLFloaterScriptSearch::sInstance = NULL; LLFloaterScriptSearch::LLFloaterScriptSearch(LLScriptEdCore* editor_core) : LLFloater(LLSD()), mSearchBox(NULL), + mReplaceBox(NULL), mEditorCore(editor_core) { buildFromFile("floater_script_search.xml"); @@ -227,6 +228,7 @@ LLFloaterScriptSearch::LLFloaterScriptSearch(LLScriptEdCore* editor_core) BOOL LLFloaterScriptSearch::postBuild() { + mReplaceBox = getChild<LLLineEditor>("replace_text"); mSearchBox = getChild<LLLineEditor>("search_text"); mSearchBox->setCommitCallback(boost::bind(&LLFloaterScriptSearch::onSearchBoxCommit, this)); mSearchBox->setCommitOnFocusLost(FALSE); @@ -242,8 +244,12 @@ BOOL LLFloaterScriptSearch::postBuild() //static void LLFloaterScriptSearch::show(LLScriptEdCore* editor_core) { + LLSD::String search_text; + LLSD::String replace_text; if (sInstance && sInstance->mEditorCore && sInstance->mEditorCore != editor_core) { + search_text=sInstance->mSearchBox->getValue().asString(); + replace_text=sInstance->mReplaceBox->getValue().asString(); sInstance->closeFloater(); delete sInstance; } @@ -252,6 +258,8 @@ void LLFloaterScriptSearch::show(LLScriptEdCore* editor_core) { // sInstance will be assigned in the constructor. new LLFloaterScriptSearch(editor_core); + sInstance->mSearchBox->setValue(search_text); + sInstance->mReplaceBox->setValue(replace_text); } sInstance->openFloater(); @@ -272,7 +280,7 @@ void LLFloaterScriptSearch::onBtnSearch(void *userdata) void LLFloaterScriptSearch::handleBtnSearch() { LLCheckBoxCtrl* caseChk = getChild<LLCheckBoxCtrl>("case_text"); - mEditorCore->mEditor->selectNext(getChild<LLUICtrl>("search_text")->getValue().asString(), caseChk->get()); + mEditorCore->mEditor->selectNext(mSearchBox->getValue().asString(), caseChk->get()); } // static @@ -285,7 +293,7 @@ void LLFloaterScriptSearch::onBtnReplace(void *userdata) void LLFloaterScriptSearch::handleBtnReplace() { LLCheckBoxCtrl* caseChk = getChild<LLCheckBoxCtrl>("case_text"); - mEditorCore->mEditor->replaceText(getChild<LLUICtrl>("search_text")->getValue().asString(), getChild<LLUICtrl>("replace_text")->getValue().asString(), caseChk->get()); + mEditorCore->mEditor->replaceText(mSearchBox->getValue().asString(), mReplaceBox->getValue().asString(), caseChk->get()); } // static @@ -298,7 +306,7 @@ void LLFloaterScriptSearch::onBtnReplaceAll(void *userdata) void LLFloaterScriptSearch::handleBtnReplaceAll() { LLCheckBoxCtrl* caseChk = getChild<LLCheckBoxCtrl>("case_text"); - mEditorCore->mEditor->replaceTextAll(getChild<LLUICtrl>("search_text")->getValue().asString(), getChild<LLUICtrl>("replace_text")->getValue().asString(), caseChk->get()); + mEditorCore->mEditor->replaceTextAll(mSearchBox->getValue().asString(), mReplaceBox->getValue().asString(), caseChk->get()); } bool LLFloaterScriptSearch::hasAccelerators() const @@ -329,7 +337,7 @@ void LLFloaterScriptSearch::onSearchBoxCommit() if (mEditorCore && mEditorCore->mEditor) { LLCheckBoxCtrl* caseChk = getChild<LLCheckBoxCtrl>("case_text"); - mEditorCore->mEditor->selectNext(getChild<LLUICtrl>("search_text")->getValue().asString(), caseChk->get()); + mEditorCore->mEditor->selectNext(mSearchBox->getValue().asString(), caseChk->get()); } } @@ -518,6 +526,10 @@ void LLScriptEdCore::initMenu() menuItem->setClickCallback(boost::bind(&LLTextEditor::selectAll, mEditor)); menuItem->setEnableCallback(boost::bind(&LLTextEditor::canSelectAll, mEditor)); + menuItem = getChild<LLMenuItemCallGL>("Deselect"); + menuItem->setClickCallback(boost::bind(&LLTextEditor::deselect, mEditor)); + menuItem->setEnableCallback(boost::bind(&LLTextEditor::canDeselect, mEditor)); + menuItem = getChild<LLMenuItemCallGL>("Search / Replace..."); menuItem->setClickCallback(boost::bind(&LLFloaterScriptSearch::show, this)); @@ -1864,7 +1876,7 @@ void LLLiveLSLEditor::loadAsset() mIsModifiable = item && gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE); - + refreshFromItem(); // This is commented out, because we don't completely // handle script exports yet. /* diff --git a/indra/newview/llpreviewsound.cpp b/indra/newview/llpreviewsound.cpp index 33d2d015ad..11b81a58fc 100755 --- a/indra/newview/llpreviewsound.cpp +++ b/indra/newview/llpreviewsound.cpp @@ -55,7 +55,9 @@ BOOL LLPreviewSound::postBuild() { getChild<LLUICtrl>("desc")->setValue(item->getDescription()); if (gAudiop) + { gAudiop->preloadSound(item->getAssetUUID()); // preload the sound + } } childSetAction("Sound play btn",&LLPreviewSound::playSound,this); @@ -94,6 +96,6 @@ void LLPreviewSound::auditionSound( void *userdata ) if(item && gAudiop) { LLVector3d lpos_global = gAgent.getPositionGlobal(); - gAudiop->triggerSound(item->getAssetUUID(), gAgent.getID(), SOUND_GAIN, LLAudioEngine::AUDIO_TYPE_UI, lpos_global); + gAudiop->triggerSound(item->getAssetUUID(), gAgent.getID(), SOUND_GAIN, LLAudioEngine::AUDIO_TYPE_SFX, lpos_global); } } diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 1ed48a978f..5c41c5ad97 100755 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -127,9 +127,28 @@ BOOL LLPreviewTexture::postBuild() getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe); } } + + // Fill in ratios list with common aspect ratio values + mRatiosList.clear(); + mRatiosList.push_back(LLTrans::getString("Unconstrained")); + mRatiosList.push_back("1:1"); + mRatiosList.push_back("4:3"); + mRatiosList.push_back("10:7"); + mRatiosList.push_back("3:2"); + mRatiosList.push_back("16:10"); + mRatiosList.push_back("16:9"); + mRatiosList.push_back("2:1"); - childSetCommitCallback("combo_aspect_ratio", onAspectRatioCommit, this); + // Now fill combo box with provided list LLComboBox* combo = getChild<LLComboBox>("combo_aspect_ratio"); + combo->removeall(); + + for (std::vector<std::string>::const_iterator it = mRatiosList.begin(); it != mRatiosList.end(); ++it) + { + combo->add(*it); + } + + childSetCommitCallback("combo_aspect_ratio", onAspectRatioCommit, this); combo->setCurrentByIndex(0); return LLPreview::postBuild(); @@ -414,6 +433,13 @@ void LLPreviewTexture::updateDimensions() { return; } + + if (mAssetStatus != PREVIEW_ASSET_LOADED) + { + mAssetStatus = PREVIEW_ASSET_LOADED; + // Asset has been fully loaded, adjust aspect ratio + adjustAspectRatio(); + } // Update the width/height display every time getChild<LLUICtrl>("dimensions")->setTextArg("[WIDTH]", llformat("%d", mImage->getFullWidth())); @@ -501,6 +527,46 @@ LLPreview::EAssetStatus LLPreviewTexture::getAssetStatus() return mAssetStatus; } +void LLPreviewTexture::adjustAspectRatio() +{ + S32 w = mImage->getFullWidth(); + S32 h = mImage->getFullHeight(); + + // Determine aspect ratio of the image + S32 tmp; + while (h != 0) + { + tmp = w % h; + w = h; + h = tmp; + } + S32 divisor = w; + S32 num = mImage->getFullWidth() / divisor; + S32 denom = mImage->getFullHeight() / divisor; + + if (setAspectRatio(num, denom)) + { + // Select corresponding ratio entry in the combo list + LLComboBox* combo = getChild<LLComboBox>("combo_aspect_ratio"); + if (combo) + { + std::ostringstream ratio; + ratio << num << ":" << denom; + std::vector<std::string>::const_iterator found = std::find(mRatiosList.begin(), mRatiosList.end(), ratio.str()); + if (found == mRatiosList.end()) + { + combo->setCurrentByIndex(0); + } + else + { + combo->setCurrentByIndex(found - mRatiosList.begin()); + } + } + } + + mUpdateDimensions = TRUE; +} + void LLPreviewTexture::updateImageID() { const LLViewerInventoryItem *item = static_cast<const LLViewerInventoryItem*>(getItem()); diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h index cd16bacde2..97e74706cc 100755 --- a/indra/newview/llpreviewtexture.h +++ b/indra/newview/llpreviewtexture.h @@ -70,6 +70,7 @@ protected: /* virtual */ BOOL postBuild(); bool setAspectRatio(const F32 width, const F32 height); static void onAspectRatioCommit(LLUICtrl*,void* userdata); + void adjustAspectRatio(); private: void updateImageID(); // set what image is being uploaded. @@ -95,5 +96,6 @@ private: F32 mAspectRatio; LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ; + std::vector<std::string> mRatiosList; }; #endif // LL_LLPREVIEWTEXTURE_H diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp index e85194d173..e92bf4590d 100755 --- a/indra/newview/llproductinforequest.cpp +++ b/indra/newview/llproductinforequest.cpp @@ -35,18 +35,24 @@ class LLProductInfoRequestResponder : public LLHTTPClient::Responder { -public: + LOG_CLASS(LLProductInfoRequestResponder); +private: //If we get back a normal response, handle it here - virtual void result(const LLSD& content) + /* virtual */ void httpSuccess() { - LLProductInfoRequestManager::instance().setSkuDescriptions(content); + const LLSD& content = getContent(); + if (!content.isArray()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + LLProductInfoRequestManager::instance().setSkuDescriptions(getContent()); } //If we get back an error (not found, etc...), handle it here - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + /* virtual */ void httpFailure() { - LL_WARNS() << "LLProductInfoRequest error [status:" - << status << ":] " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; } }; diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index 13120fdf45..29dcc12f9e 100755 --- a/indra/newview/llremoteparcelrequest.cpp +++ b/indra/newview/llremoteparcelrequest.cpp @@ -47,9 +47,15 @@ LLRemoteParcelRequestResponder::LLRemoteParcelRequestResponder(LLHandle<LLRemote //If we get back a normal response, handle it here //virtual -void LLRemoteParcelRequestResponder::result(const LLSD& content) +void LLRemoteParcelRequestResponder::httpSuccess() { - LLUUID parcel_id = content["parcel_id"]; + const LLSD& content = getContent(); + if (!content.isMap() || !content.has("parcel_id")) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + LLUUID parcel_id = getContent()["parcel_id"]; // Panel inspecting the information may be closed and destroyed // before this response is received. @@ -62,17 +68,16 @@ void LLRemoteParcelRequestResponder::result(const LLSD& content) //If we get back an error (not found, etc...), handle it here //virtual -void LLRemoteParcelRequestResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLRemoteParcelRequestResponder::httpFailure() { - LL_WARNS() << "LLRemoteParcelRequest error [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; // Panel inspecting the information may be closed and destroyed // before this response is received. LLRemoteParcelInfoObserver* observer = mObserverHandle.get(); if (observer) { - observer->setErrorStatus(status, reason); + observer->setErrorStatus(getStatus(), getReason()); } } diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h index e4b8791f7c..35348b69ff 100755 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -38,16 +38,17 @@ class LLRemoteParcelInfoObserver; class LLRemoteParcelRequestResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLRemoteParcelRequestResponder); public: LLRemoteParcelRequestResponder(LLHandle<LLRemoteParcelInfoObserver> observer_handle); +private: //If we get back a normal response, handle it here - /*virtual*/ void result(const LLSD& content); + /*virtual*/ void httpSuccess(); //If we get back an error (not found, etc...), handle it here - /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + /*virtual*/ void httpFailure(); -protected: LLHandle<LLRemoteParcelInfoObserver> mObserverHandle; }; @@ -79,7 +80,7 @@ public: virtual ~LLRemoteParcelInfoObserver() {} virtual void processParcelInfo(const LLParcelData& parcel_data) = 0; virtual void setParcelID(const LLUUID& parcel_id) = 0; - virtual void setErrorStatus(U32 status, const std::string& reason) = 0; + virtual void setErrorStatus(S32 status, const std::string& reason) = 0; LLHandle<LLRemoteParcelInfoObserver> getObserverHandle() const { return mObserverHandle; } protected: diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 6a840f3f40..8708fb87ee 100755 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -273,6 +273,14 @@ void LLScreenChannel::addToast(const LLToast::Params& p) // only cancel notification if it isn't being used in IM session LLNotifications::instance().cancel(notification); } + + // It was assumed that the toast would take ownership of the panel pointer. + // But since we have decided not to display the toast, kill the panel to + // prevent the memory leak. + if (p.panel != NULL) + { + p.panel()->die(); + } return; } diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp index a7e24b86b1..bfa453a0ae 100755 --- a/indra/newview/llscrollingpanelparam.cpp +++ b/indra/newview/llscrollingpanelparam.cpp @@ -266,7 +266,7 @@ void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint ) if (slider->getMinValue() < new_percent && new_percent < slider->getMaxValue()) { - mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight, FALSE); + mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight); mWearable->writeToAvatar(gAgentAvatarp); gAgentAvatarp->updateVisualParams(); @@ -299,7 +299,7 @@ void LLScrollingPanelParam::onHintMinMouseUp( void* userdata ) if (slider->getMinValue() < new_percent && new_percent < slider->getMaxValue()) { - self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); + self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); self->mWearable->writeToAvatar(gAgentAvatarp); slider->setValue( self->weightToPercent( new_weight ) ); } @@ -333,7 +333,7 @@ void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata ) if (slider->getMinValue() < new_percent && new_percent < slider->getMaxValue()) { - self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); + self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); self->mWearable->writeToAvatar(gAgentAvatarp); slider->setValue( self->weightToPercent( new_weight ) ); } diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp index 8e083ddb6c..fe7a362723 100755 --- a/indra/newview/llscrollingpanelparambase.cpp +++ b/indra/newview/llscrollingpanelparambase.cpp @@ -93,7 +93,7 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata) F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() ); if (current_weight != new_weight ) { - self->mWearable->setVisualParamWeight( param->getID(), new_weight, FALSE ); + self->mWearable->setVisualParamWeight( param->getID(), new_weight); self->mWearable->writeToAvatar(gAgentAvatarp); gAgentAvatarp->updateVisualParams(); } diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index c938a478f7..64f24cd291 100755 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -452,7 +452,7 @@ void LLSidepanelAppearance::editWearable(LLViewerWearable *wearable, LLView *dat LLFloaterSidePanelContainer::showPanel("appearance", LLSD()); LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(data); if (panel) - { + { panel->showWearableEditPanel(wearable, disable_camera_switch); } } diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp index 243d4cf910..2556714792 100755 --- a/indra/newview/llsidepanelinventory.cpp +++ b/indra/newview/llsidepanelinventory.cpp @@ -710,13 +710,13 @@ void LLSidepanelInventory::clearSelections(bool clearMain, bool clearInbox) if (inv_panel) { - inv_panel->clearSelection(); + inv_panel->getRootFolder()->clearSelection(); } } if (clearInbox && mInboxEnabled && mInventoryPanelInbox.get()) { - mInventoryPanelInbox.get()->clearSelection(); + mInventoryPanelInbox.get()->getRootFolder()->clearSelection(); } updateVerbs(); diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 737f665954..d8ad071ba6 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -50,7 +50,6 @@ #include "llviewerstats.h" #include "llvfile.h" #include "llvfs.h" -#include "llwebsharing.h" #include "llwindow.h" #include "llworld.h" @@ -845,30 +844,3 @@ BOOL LLSnapshotLivePreview::saveLocal() } return success; } - -void LLSnapshotLivePreview::saveWeb() -{ - // *FIX: Will break if the window closes because of CloseSnapshotOnKeep! - // Needs to pass on ownership of the image. - LLImageJPEG* jpg = dynamic_cast<LLImageJPEG*>(mFormattedImage.get()); - if(!jpg) - { - LL_WARNS() << "Formatted image not a JPEG" << LL_ENDL; - return; - } - - LLSD metadata; - metadata["description"] = getChild<LLLineEditor>("description")->getText(); - - LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(gAgentCamera.getCameraPositionGlobal(), - boost::bind(&LLSnapshotLivePreview::regionNameCallback, this, jpg, metadata, _1, _2, _3, _4)); - - gViewerWindow->playSnapshotAnimAndSound(); -} - -void LLSnapshotLivePreview::regionNameCallback(LLImageJPEG* snapshot, LLSD& metadata, const std::string& name, S32 x, S32 y, S32 z) -{ - metadata["slurl"] = LLSLURL(name, LLVector3d(x, y, z)).getSLURLString(); - - LLWebSharing::instance().shareSnapshot(snapshot, metadata); -} diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h index fe3d257b02..0f09ef214a 100644 --- a/indra/newview/llsnapshotlivepreview.h +++ b/indra/newview/llsnapshotlivepreview.h @@ -96,7 +96,6 @@ public: void setSnapshotQuality(S32 quality); void setSnapshotBufferType(LLViewerWindow::ESnapshotType type) { mSnapshotBufferType = type; } void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f); - void saveWeb(); void saveTexture(); BOOL saveLocal(); @@ -113,9 +112,6 @@ public: // Returns TRUE when snapshot generated, FALSE otherwise. static BOOL onIdle( void* snapshot_preview ); - // callback for region name resolve - void regionNameCallback(LLImageJPEG* snapshot, LLSD& metadata, const std::string& name, S32 x, S32 y, S32 z); - private: LLColor4 mColor; LLPointer<LLViewerTexture> mViewerImage[2]; //used to represent the scene when the frame is frozen. diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index a7b99a0f6b..08a4d00d0f 100755 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -640,12 +640,26 @@ class LLVolumeGeometryManager: public LLGeometryManager DISTANCE_SORT } eSortType; - virtual ~LLVolumeGeometryManager() { } + LLVolumeGeometryManager(); + virtual ~LLVolumeGeometryManager(); virtual void rebuildGeom(LLSpatialGroup* group); virtual void rebuildMesh(LLSpatialGroup* group); virtual void getGeometry(LLSpatialGroup* group); void genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE, BOOL no_materials = FALSE); void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type); + +private: + void allocateFaces(U32 pMaxFaceCount); + void freeFaces(); + + static int32_t sInstanceCount; + static LLFace** sFullbrightFaces; + static LLFace** sBumpFaces; + static LLFace** sSimpleFaces; + static LLFace** sNormFaces; + static LLFace** sSpecFaces; + static LLFace** sNormSpecFaces; + static LLFace** sAlphaFaces; }; //spatial partition that uses volume geometry manager (implemented in LLVOVolume.cpp) diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index f25076d47e..89302c3c64 100755 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -270,21 +270,23 @@ bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id) class ModerationResponder : public LLHTTPClient::Responder { + LOG_CLASS(ModerationResponder); public: ModerationResponder(const LLUUID& session_id) { mSessionID = session_id; } - virtual void error(U32 status, const std::string& reason) +protected: + virtual void httpFailure() { - LL_WARNS() << status << ": " << reason << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; if ( gIMMgr ) { //403 == you're not a mod //should be disabled if you're not a moderator - if ( 403 == status ) + if ( HTTP_FORBIDDEN == getStatus() ) { gIMMgr->showSessionEventError( "mute", @@ -855,10 +857,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) } } } -/*prep# - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - LL_WARNS() << "ModerationResponder error [status:" << status << "]: " << content << LL_ENDL; - */ + void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) { LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index a72b93e84e..56fac3b092 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -311,6 +311,12 @@ void update_texture_fetch() gTextureList.updateImages(0.10f); } +void set_flags_and_update_appearance() +{ + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); +} + // Returns false to skip other idle processing. Should only return // true when all initialization done. bool idle_startup() @@ -622,25 +628,22 @@ bool idle_startup() if (FALSE == gSavedSettings.getBOOL("NoAudio")) { + delete gAudiop; gAudiop = NULL; #ifdef LL_FMODEX - if (!gAudiop #if !LL_WINDOWS - && NULL == getenv("LL_BAD_FMODEX_DRIVER") + if (NULL == getenv("LL_BAD_FMODEX_DRIVER")) #endif // !LL_WINDOWS - ) { gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX(gSavedSettings.getBOOL("FMODExProfilerEnable")); } #endif #ifdef LL_OPENAL - if (!gAudiop #if !LL_WINDOWS - && NULL == getenv("LL_BAD_OPENAL_DRIVER") + if (NULL == getenv("LL_BAD_OPENAL_DRIVER")) #endif // !LL_WINDOWS - ) { gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); } @@ -1290,6 +1293,8 @@ bool idle_startup() LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from init_idle(). Seed cap == " + << gFirstSimSeedCap << LL_ENDL; regionp->setSeedCapability(gFirstSimSeedCap); LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL; display_startup(); @@ -1774,6 +1779,15 @@ bool idle_startup() // This method MUST be called before gInventory.findCategoryUUIDForType because of // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. gInventory.buildParentChildMap(); + gInventory.createCommonSystemCategories(); + + // It's debatable whether this flag is a good idea - sets all + // bits, and in general it isn't true that inventory + // initialization generates all types of changes. Maybe add an + // INITIALIZE mask bit instead? + gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); + gInventory.notifyObservers(); + display_startup(); //all categories loaded. lets create "My Favorites" category @@ -2021,7 +2035,7 @@ bool idle_startup() { display_startup(); F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; - + // We now have an inventory skeleton, so if this is a user's first // login, we can start setting up their clothing and avatar // appearance. This helps to avoid the generic "Ruth" avatar in @@ -2030,18 +2044,38 @@ bool idle_startup() && !sInitialOutfit.empty() // registration set up an outfit && !sInitialOutfitGender.empty() // and a gender && isAgentAvatarValid() // can't wear clothes without object - && !gAgent.isGenderChosen() ) // nothing already loading + && !gAgent.isOutfitChosen()) // nothing already loading { // Start loading the wearables, textures, gestures LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender ); } + // If not first login, we need to fetch COF contents and + // compute appearance from that. + if (isAgentAvatarValid() && !gAgent.isFirstLogin() && !gAgent.isOutfitChosen()) + { + gAgentWearables.notifyLoadingStarted(); + gAgent.setOutfitChosen(TRUE); + gAgentWearables.sendDummyAgentWearablesUpdate(); + callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(), set_flags_and_update_appearance); + } display_startup(); // wait precache-delay and for agent's avatar or a lot longer. - if(((timeout_frac > 1.f) && isAgentAvatarValid()) - || (timeout_frac > 3.f)) + if ((timeout_frac > 1.f) && isAgentAvatarValid()) + { + LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); + } + else if (timeout_frac > 10.f) { + // If we exceed the wait above while isAgentAvatarValid is + // not true yet, we will change startup state and + // eventually (once avatar does get created) wind up at + // the gender chooser. This should occur only in very + // unusual circumstances, so set the timeout fairly high + // to minimize mistaken hits here. + LL_WARNS() << "Wait for valid avatar state exceeded " + << timeout.getElapsedTimeF32() << " will invoke gender chooser" << LL_ENDL; LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); } else @@ -2063,12 +2097,11 @@ bool idle_startup() const F32 wearables_time = wearables_timer.getElapsedTimeF32(); static LLCachedControl<F32> max_wearables_time(gSavedSettings, "ClothingLoadingDelay"); - display_startup(); - if (!gAgent.isGenderChosen() && isAgentAvatarValid()) + if (!gAgent.isOutfitChosen() && isAgentAvatarValid()) { - // No point in waiting for clothing, we don't even - // know what gender we are. Pop a dialog to ask and - // proceed to draw the world. JC + // No point in waiting for clothing, we don't even know + // what outfit we want. Pop up a gender chooser dialog to + // ask and proceed to draw the world. JC // // *NOTE: We might hit this case even if we have an // initial outfit, but if the load hasn't started @@ -2078,7 +2111,10 @@ bool idle_startup() callback_choose_gender); LLStartUp::setStartupState( STATE_CLEANUP ); } - else if (wearables_time >= max_wearables_time()) + + display_startup(); + + if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) { LLNotificationsUtil::add("ClothingLoading"); record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); @@ -2089,25 +2125,24 @@ bool idle_startup() && gAgentAvatarp->isFullyLoaded()) { // wait for avatar to be completely loaded - //LL_INFOS() << "avatar fully loaded" << LL_ENDL; - LLStartUp::setStartupState( STATE_CLEANUP ); - } - // OK to just get the wearables - else if (!gAgent.isFirstLogin() && gAgentWearables.areWearablesLoaded() ) - { - // We have our clothing, proceed. - //LL_INFOS() << "wearables loaded" << LL_ENDL; - LLStartUp::setStartupState( STATE_CLEANUP ); + if (isAgentAvatarValid() + && gAgentAvatarp->isFullyLoaded()) + { + LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } } else { - display_startup(); - update_texture_fetch(); - display_startup(); - set_startup_status(0.9f + 0.1f * wearables_time / max_wearables_time(), - LLTrans::getString("LoginDownloadingClothing").c_str(), - gAgent.mMOTD.c_str()); - display_startup(); + // OK to just get the wearables + if ( gAgentWearables.areWearablesLoaded() ) + { + // We have our clothing, proceed. + LL_DEBUGS("Avatar") << "wearables loaded" << LL_ENDL; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } } //fall through this frame to STATE_CLEANUP } @@ -2354,8 +2389,6 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); - msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse); - msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures); msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); @@ -2429,9 +2462,6 @@ void register_viewer_callbacks(LLMessageSystem* msg) // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, // LLFloaterRate::processReputationIndividualReply); - msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate, - LLAgentWearables::processAgentInitialWearablesUpdate ); - msg->setHandlerFunc("ScriptControlChange", LLAgent::processScriptControlChange ); @@ -2588,9 +2618,8 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL; } - // This is really misnamed -- it means we have started loading - // an outfit/shape that will give the avatar a gender eventually. JC - gAgent.setGenderChosen(TRUE); + gAgent.setOutfitChosen(TRUE); + gAgentWearables.sendDummyAgentWearablesUpdate(); } //static @@ -2603,10 +2632,10 @@ void LLStartUp::saveInitialOutfit() if (sWearablesLoadedCon.connected()) { - LL_DEBUGS() << "sWearablesLoadedCon is connected, disconnecting" << LL_ENDL; + LL_DEBUGS("Avatar") << "sWearablesLoadedCon is connected, disconnecting" << LL_ENDL; sWearablesLoadedCon.disconnect(); } - LL_DEBUGS() << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << LL_ENDL; + LL_DEBUGS("Avatar") << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << LL_ENDL; LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false); } @@ -3351,7 +3380,11 @@ bool process_login_success_response() flag = login_flags["gendered"].asString(); if(flag == "Y") { - gAgent.setGenderChosen(TRUE); + // We don't care about this flag anymore; now base whether + // outfit is chosen on COF contents, initial outfit + // requested and available, etc. + + //gAgent.setGenderChosen(TRUE); } bool pacific_daylight_time = false; diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 9d1290b86d..c12753acb0 100755 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -242,7 +242,7 @@ void LLFloaterTexturePicker::setImageID(const LLUUID& image_id) LLUUID item_id = findItemID(mImageAssetID, FALSE); if (item_id.isNull()) { - mInventoryPanel->clearSelection(); + mInventoryPanel->getRootFolder()->clearSelection(); } else { diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 2acd38b753..14a42dd8dc 100755 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -36,7 +36,7 @@ #include "lldir.h" #include "llhttpclient.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h" #include "llimage.h" #include "llimagej2c.h" #include "llimageworker.h" @@ -64,6 +64,8 @@ #include "bufferarray.h" #include "bufferstream.h" +#include "llhttpretrypolicy.h" + bool LLTextureFetchDebugger::sDebuggerEnabled = false ; LLTrace::EventStatHandle<LLUnit<F32, LLUnits::Percent> > LLTextureFetch::sCacheHitRate("texture_cache_hits"); LLTrace::EventStatHandle<F64Milliseconds > LLTextureFetch::sCacheReadLatency("texture_cache_read_latency"); @@ -245,6 +247,25 @@ static const S32 HTTP_REQUESTS_IN_QUEUE_LOW_WATER = 20; // Active level at whi ////////////////////////////////////////////////////////////////////////////// +static const char* e_state_name[] = +{ + "INVALID", + "INIT", + "LOAD_FROM_TEXTURE_CACHE", + "CACHE_POST", + "LOAD_FROM_NETWORK", + "LOAD_FROM_SIMULATOR", + "WAIT_HTTP_RESOURCE", + "WAIT_HTTP_RESOURCE2", + "SEND_HTTP_REQ", + "WAIT_HTTP_REQ", + "DECODE_IMAGE", + "DECODE_IMAGE_UPDATE", + "WRITE_TO_CACHE", + "WAIT_ON_WRITE", + "DONE" +}; + class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler { @@ -383,12 +404,14 @@ public: void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; } bool getCanUseHTTP() const { return mCanUseHTTP; } + void setUrl(const std::string& url) { mUrl = url; } + LLTextureFetch & getFetcher() { return *mFetcher; } // Inherited from LLCore::HttpHandler // Threads: Ttf virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); - + protected: LLTextureFetchWorker(LLTextureFetch* fetcher, FTType f_type, const std::string& url, const LLUUID& id, const LLHost& host, @@ -549,6 +572,8 @@ private: S32 mActiveCount; LLCore::HttpStatus mGetStatus; std::string mGetReason; + LLAdaptiveRetryPolicy mFetchRetryPolicy; + // Work Data LLMutex mWorkMutex; @@ -894,7 +919,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, mHttpHasResource(false), mCacheReadCount(0U), mCacheWriteCount(0U), - mResourceWaitCount(0U) + mResourceWaitCount(0U), + mFetchRetryPolicy(10.0,3600.0,2.0,10) { mCanUseNET = mUrl.empty() ; @@ -1153,6 +1179,7 @@ bool LLTextureFetchWorker::doWork(S32 param) mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); // min desired size is TEXTURE_CACHE_ENTRY_SIZE LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority) << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL; + // fall through } @@ -1183,9 +1210,7 @@ bool LLTextureFetchWorker::doWork(S32 param) offset, size, responder); mCacheReadTimer.reset(); } -/* SH-3980 - disabling caching of server bakes until we can fix the blurring problems */ -/* else if ((mUrl.empty()||mFTType==FTT_SERVER_BAKE) && mFetcher->canLoadFromCache()) */ - else if (mUrl.empty() && mFetcher->canLoadFromCache()) + else if ((mUrl.empty() || mFTType==FTT_SERVER_BAKE) && mFetcher->canLoadFromCache()) { setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it @@ -1275,6 +1300,21 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == LOAD_FROM_NETWORK) { + // Check for retries to previous server failures. + F32 wait_seconds; + if (mFetchRetryPolicy.shouldRetry(wait_seconds)) + { + if (wait_seconds <= 0.0) + { + LL_INFOS() << mID << " retrying now" << LL_ENDL; + } + else + { + //LL_INFOS() << mID << " waiting to retry for " << wait_seconds << " seconds" << LL_ENDL; + return false; + } + } + static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP", true); // if (mHost != LLHost::invalid) get_url = false; @@ -1291,7 +1331,11 @@ bool LLTextureFetchWorker::doWork(S32 param) std::string http_url = region->getHttpUrl() ; if (!http_url.empty()) { - mUrl = http_url + "/?texture_id=" + mID.asString().c_str(); + if (mFTType != FTT_DEFAULT) + { + LL_WARNS() << "trying to seek a non-default texture on the sim. Bad!" << LL_ENDL; + } + setUrl(http_url + "/?texture_id=" + mID.asString().c_str()); mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id. } else @@ -1306,12 +1350,11 @@ bool LLTextureFetchWorker::doWork(S32 param) mCanUseHTTP = false; } } -#if 0 /* SH-3980 - disabling caching of server bakes until we can fix the blurring problems */ - if (mFTType == FTT_SERVER_BAKE) + else if (mFTType == FTT_SERVER_BAKE) { mWriteToCacheState = CAN_WRITE; } -#endif + if (mCanUseHTTP && !mUrl.empty()) { setState(WAIT_HTTP_RESOURCE); @@ -1345,7 +1388,6 @@ bool LLTextureFetchWorker::doWork(S32 param) //recordTextureStart(false); //setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - LL_DEBUGS("Texture") << mID << " does this happen?" << LL_ENDL; return false; } } @@ -1487,12 +1529,14 @@ bool LLTextureFetchWorker::doWork(S32 param) << LL_ENDL; // Will call callbackHttpGet when curl request completes + // Only server bake images use the returned headers currently, for getting retry-after field. + LLCore::HttpOptions *options = (mFTType == FTT_SERVER_BAKE) ? mFetcher->mHttpOptionsWithHeaders: mFetcher->mHttpOptions; mHttpHandle = mFetcher->mHttpRequest->requestGetByteRange(mHttpPolicyClass, mWorkPriority, mUrl, mRequestedOffset, mRequestedSize, - mFetcher->mHttpOptions, + options, mFetcher->mHttpHeaders, this); } @@ -1524,16 +1568,22 @@ bool LLTextureFetchWorker::doWork(S32 param) { if (http_not_found == mGetStatus) { - if(mWriteToCacheState == NOT_WRITE) //map tiles + if (mFTType != FTT_MAP_TILE) + { + LL_WARNS() << "Texture missing from server (404): " << mUrl << LL_ENDL; + } + + if(mWriteToCacheState == NOT_WRITE) //map tiles or server bakes { setState(DONE); releaseHttpSemaphore(); - LL_DEBUGS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << LL_ENDL; - return true; // failed, means no map tile on the empty region. + if (mFTType != FTT_MAP_TILE) + { + LL_WARNS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << LL_ENDL; + } + return true; } - LL_WARNS() << "Texture missing from server (404): " << mUrl << LL_ENDL; - // roll back to try UDP if (mCanUseNET) { @@ -1548,6 +1598,10 @@ bool LLTextureFetchWorker::doWork(S32 param) else if (http_service_unavail == mGetStatus) { LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL; + LL_INFOS() << "503: HTTP GET failed for: " << mUrl + << " Status: " << mGetStatus.toHex() + << " Reason: '" << mGetReason << "'" + << LL_ENDL; } else if (http_not_sat == mGetStatus) { @@ -1562,7 +1616,10 @@ bool LLTextureFetchWorker::doWork(S32 param) << LL_ENDL; } - mUrl.clear(); + if (mFTType != FTT_SERVER_BAKE) + { + mUrl.clear(); + } if (cur_size > 0) { // Use available data @@ -1589,7 +1646,7 @@ bool LLTextureFetchWorker::doWork(S32 param) // Clear the url since we're done with the fetch // Note: mUrl is used to check is fetching is required so failure to clear it will force an http fetch // next time the texture is requested, even if the data have already been fetched. - if(mWriteToCacheState != NOT_WRITE) + if(mWriteToCacheState != NOT_WRITE && mFTType != FTT_SERVER_BAKE) { // Why do we want to keep url if NOT_WRITE - is this a proxy for map tiles? mUrl.clear(); @@ -1768,7 +1825,7 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mCachedSize > 0 && !mInLocalCache && mRetryAttempt == 0) { // Cache file should be deleted, try again -// LL_WARNS() << mID << ": Decode of cached file failed (removed), retrying" << LL_ENDL; + LL_WARNS() << mID << ": Decode of cached file failed (removed), retrying" << LL_ENDL; llassert_always(mDecodeHandle == 0); mFormattedImage = NULL; ++mRetryAttempt; @@ -1895,14 +1952,48 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, LLTimer::getTotalTime()); } + static LLCachedControl<F32> fake_failure_rate(gSavedSettings, "TextureFetchFakeFailureRate", 0.0f); + F32 rand_val = ll_frand(); + F32 rate = fake_failure_rate; + if (mFTType == FTT_SERVER_BAKE && (fake_failure_rate > 0.0) && (rand_val < fake_failure_rate)) + { + LL_WARNS() << mID << " for debugging, setting fake failure status for texture " << mID + << " (rand was " << rand_val << "/" << rate << ")" << LL_ENDL; + response->setStatus(LLCore::HttpStatus(503)); + } bool success = true; bool partial = false; LLCore::HttpStatus status(response->getStatus()); + if (!status && (mFTType == FTT_SERVER_BAKE)) + { + LL_INFOS() << mID << " state " << e_state_name[mState] << LL_ENDL; + mFetchRetryPolicy.onFailure(response); + F32 retry_after; + if (mFetchRetryPolicy.shouldRetry(retry_after)) + { + LL_INFOS() << mID << " will retry after " << retry_after << " seconds, resetting state to LOAD_FROM_NETWORK" << LL_ENDL; + mFetcher->removeFromHTTPQueue(mID, S32Bytes(0)); + std::string reason(status.toString()); + setGetStatus(status, reason); + releaseHttpSemaphore(); + setState(LOAD_FROM_NETWORK); + return; + } + else + { + LL_INFOS() << mID << " will not retry" << LL_ENDL; + } + } + else + { + mFetchRetryPolicy.onSuccess(); + } LL_DEBUGS("Texture") << "HTTP COMPLETE: " << mID - << " status: " << status.toTerseString() - << " '" << status.toString() << "'" + << " status: " << status.toTerseString() + << " '" << status.toString() << "'" << LL_ENDL; + // unsigned int offset(0), length(0), full_length(0); // response->getRange(&offset, &length, &full_length); // LL_WARNS() << "HTTP COMPLETE: " << mID << " handle: " << handle @@ -1911,13 +2002,18 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe // << " offset: " << offset << " length: " << length // << LL_ENDL; + std::string reason(status.toString()); + setGetStatus(status, reason); if (! status) { success = false; - std::string reason(status.toString()); - setGetStatus(status, reason); - LL_WARNS() << "CURL GET FAILED, status: " << status.toTerseString() - << " reason: " << reason << LL_ENDL; + if (mFTType != FTT_MAP_TILE) // missing map tiles are normal, don't complain about them. + { + std::string reason(status.toString()); + setGetStatus(status, reason); + LL_WARNS() << "CURL GET FAILED, status: " << status.toTerseString() + << " reason: " << reason << LL_ENDL; + } } else { @@ -2477,7 +2573,11 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const { return false; } - + + if (f_type == FTT_SERVER_BAKE) + { + LL_DEBUGS("Avatar") << " requesting " << id << " " << w << "x" << h << " discard " << desired_discard << " type " << f_type << LL_ENDL; + } LLTextureFetchWorker* worker = getWorker(id) ; if (worker) { @@ -2493,7 +2593,18 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const S32 desired_size; std::string exten = gDirUtilp->getExtension(url); - if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)) + if (f_type == FTT_SERVER_BAKE) + { + // SH-4030: This case should be redundant with the following one, just + // breaking it out here to clarify that it's intended behavior. + llassert(!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)); + + // Do full requests for baked textures to reduce interim blurring. + LL_DEBUGS("Texture") << "full request for " << id << " texture is FTT_SERVER_BAKE" << LL_ENDL; + desired_size = MAX_IMAGE_DATA_SIZE; + desired_discard = 0; + } + else if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)) { LL_DEBUGS("Texture") << "full request for " << id << " exten is not J2C: " << exten << LL_ENDL; // Only do partial requests for J2C at the moment @@ -2535,7 +2646,8 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const worker->mNeedsAux = needs_aux; worker->setImagePriority(priority); worker->setDesiredDiscard(desired_discard, desired_size); - worker->setCanUseHTTP(can_use_http) ; + worker->setCanUseHTTP(can_use_http); + worker->setUrl(url); if (!worker->haveWork()) { worker->setState(LLTextureFetchWorker::INIT); @@ -2562,7 +2674,8 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const worker->unlockWorkMutex(); // -Mw } - LL_DEBUGS("Texture") << "REQUESTED: " << id << " Discard: " << desired_discard << " size " << desired_size << LL_ENDL; + LL_DEBUGS("Texture") << "REQUESTED: " << id << " f_type " << fttype_to_string(f_type) + << " Discard: " << desired_discard << " size " << desired_size << LL_ENDL; return true; } @@ -2741,7 +2854,8 @@ LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id) // Threads: T* bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, - LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux) + LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux, + LLCore::HttpStatus& last_http_get_status) { bool res = false; LLTextureFetchWorker* worker = getWorker(id); @@ -2763,6 +2877,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, else if (worker->checkWork()) { worker->lockWorkMutex(); // +Mw + last_http_get_status = worker->mGetStatus; discard_level = worker->mDecodedDiscard; raw = worker->mRawImage; aux = worker->mAuxImage; @@ -3233,25 +3348,14 @@ bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size) void LLTextureFetchWorker::setState(e_state new_state) { - static const char* e_state_name[] = - { - "INVALID", - "INIT", - "LOAD_FROM_TEXTURE_CACHE", - "CACHE_POST", - "LOAD_FROM_NETWORK", - "LOAD_FROM_SIMULATOR", - "WAIT_HTTP_RESOURCE", - "WAIT_HTTP_RESOURCE2", - "SEND_HTTP_REQ", - "WAIT_HTTP_REQ", - "DECODE_IMAGE", - "DECODE_IMAGE_UPDATE", - "WRITE_TO_CACHE", - "WAIT_ON_WRITE", - "DONE" - }; - LL_DEBUGS("Texture") << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << LL_ENDL; + if (mFTType == FTT_SERVER_BAKE) + { + // NOTE: turning on these log statements is a reliable way to get + // blurry images fairly frequently. Presumably this is an + // indication of some subtle timing or locking issue. + +// LL_INFOS("Texture") << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << LL_ENDL; + } mState = new_state; } @@ -4016,7 +4120,7 @@ LLTextureFetchDebugger::~LLTextureFetchDebugger() void LLTextureFetchDebugger::init() { - mState = IDLE; + setDebuggerState(IDLE); mCacheReadTime = -1.f; mCacheWriteTime = -1.f; @@ -4113,7 +4217,7 @@ void LLTextureFetchDebugger::startDebug() //clear the current fetching queue gTextureList.clearFetchingRequests(); - mState = START_DEBUG; + setDebuggerState(START_DEBUG); } bool LLTextureFetchDebugger::processStartDebug(F32 max_time) @@ -4188,7 +4292,7 @@ void LLTextureFetchDebugger::tryToStopDebug() //clear the current debug work S32 size = mFetchingHistory.size(); - switch(mState) + switch(mDebuggerState) { case READ_CACHE: for(S32 i = 0 ; i < size; i++) @@ -4261,7 +4365,7 @@ void LLTextureFetchDebugger::addHistoryEntry(LLTextureFetchWorker* worker) if(mFreezeHistory) { - if(mState == REFETCH_VIS_CACHE || mState == REFETCH_VIS_HTTP) + if(mDebuggerState == REFETCH_VIS_CACHE || mDebuggerState == REFETCH_VIS_HTTP) { mRefetchedVisPixels += worker->mRawImage->getWidth() * worker->mRawImage->getHeight(); mRefetchedVisData += worker->mFormattedImage->getDataSize(); @@ -4306,9 +4410,9 @@ void LLTextureFetchDebugger::unlockCache() void LLTextureFetchDebugger::debugCacheRead() { lockCache(); - llassert_always(mState == IDLE); + llassert_always(mDebuggerState == IDLE); mTimer.reset(); - mState = READ_CACHE; + setDebuggerState(READ_CACHE); mCacheReadTime = -1.f; S32 size = mFetchingHistory.size(); @@ -4342,9 +4446,9 @@ void LLTextureFetchDebugger::debugCacheWrite() clearCache(); lockCache(); - llassert_always(mState == IDLE); + llassert_always(mDebuggerState == IDLE); mTimer.reset(); - mState = WRITE_CACHE; + setDebuggerState(WRITE_CACHE); mCacheWriteTime = -1.f; S32 size = mFetchingHistory.size(); @@ -4371,9 +4475,9 @@ void LLTextureFetchDebugger::unlockDecoder() void LLTextureFetchDebugger::debugDecoder() { lockDecoder(); - llassert_always(mState == IDLE); + llassert_always(mDebuggerState == IDLE); mTimer.reset(); - mState = DECODING; + setDebuggerState(DECODING); mDecodingTime = -1.f; S32 size = mFetchingHistory.size(); @@ -4392,7 +4496,7 @@ void LLTextureFetchDebugger::debugDecoder() void LLTextureFetchDebugger::debugHTTP() { - llassert_always(mState == IDLE); + llassert_always(mDebuggerState == IDLE); LLViewerRegion* region = gAgent.getRegion(); if (!region) @@ -4409,7 +4513,7 @@ void LLTextureFetchDebugger::debugHTTP() } mTimer.reset(); - mState = HTTP_FETCHING; + setDebuggerState(HTTP_FETCHING); mHTTPTime = -1.f; S32 size = mFetchingHistory.size(); @@ -4489,8 +4593,8 @@ S32 LLTextureFetchDebugger::fillCurlQueue() void LLTextureFetchDebugger::debugGLTextureCreation() { - llassert_always(mState == IDLE); - mState = GL_TEX; + llassert_always(mDebuggerState == IDLE); + setDebuggerState(GL_TEX); mTempTexList.clear(); S32 size = mFetchingHistory.size(); @@ -4611,8 +4715,8 @@ void LLTextureFetchDebugger::scanRefetchList() void LLTextureFetchDebugger::debugRefetchVisibleFromCache() { - llassert_always(mState == IDLE); - mState = REFETCH_VIS_CACHE; + llassert_always(mDebuggerState == IDLE); + setDebuggerState(REFETCH_VIS_CACHE); clearTextures(); mFetcher->setLoadSource(LLTextureFetch::FROM_ALL); @@ -4626,8 +4730,8 @@ void LLTextureFetchDebugger::debugRefetchVisibleFromCache() void LLTextureFetchDebugger::debugRefetchVisibleFromHTTP() { - llassert_always(mState == IDLE); - mState = REFETCH_VIS_HTTP; + llassert_always(mDebuggerState == IDLE); + setDebuggerState(REFETCH_VIS_HTTP); clearTextures(); mFetcher->setLoadSource(LLTextureFetch::FROM_HTTP_ONLY); @@ -4641,8 +4745,8 @@ void LLTextureFetchDebugger::debugRefetchVisibleFromHTTP() void LLTextureFetchDebugger::debugRefetchAllFromCache() { - llassert_always(mState == IDLE); - mState = REFETCH_ALL_CACHE; + llassert_always(mDebuggerState == IDLE); + setDebuggerState(REFETCH_ALL_CACHE); clearTextures(); makeRefetchList(); @@ -4658,8 +4762,8 @@ void LLTextureFetchDebugger::debugRefetchAllFromCache() void LLTextureFetchDebugger::debugRefetchAllFromHTTP() { - llassert_always(mState == IDLE); - mState = REFETCH_ALL_HTTP; + llassert_always(mDebuggerState == IDLE); + setDebuggerState(REFETCH_ALL_HTTP); clearTextures(); makeRefetchList(); @@ -4675,19 +4779,19 @@ void LLTextureFetchDebugger::debugRefetchAllFromHTTP() bool LLTextureFetchDebugger::update(F32 max_time) { - switch(mState) + switch(mDebuggerState) { case START_DEBUG: if(processStartDebug(max_time)) { - mState = IDLE; + setDebuggerState(IDLE); } break; case READ_CACHE: if(!mTextureCache->update(1)) { mCacheReadTime = mTimer.getElapsedTimeF32() ; - mState = IDLE; + setDebuggerState(IDLE); unlockCache(); } break; @@ -4695,7 +4799,7 @@ bool LLTextureFetchDebugger::update(F32 max_time) if(!mTextureCache->update(1)) { mCacheWriteTime = mTimer.getElapsedTimeF32() ; - mState = IDLE; + setDebuggerState(IDLE); unlockCache(); } break; @@ -4703,7 +4807,7 @@ bool LLTextureFetchDebugger::update(F32 max_time) if(!mImageDecodeThread->update(1)) { mDecodingTime = mTimer.getElapsedTimeF32() ; - mState = IDLE; + setDebuggerState(IDLE); unlockDecoder(); } break; @@ -4713,13 +4817,13 @@ bool LLTextureFetchDebugger::update(F32 max_time) if (!fillCurlQueue() && mNbCurlCompleted == mFetchingHistory.size()) { mHTTPTime = mTimer.getElapsedTimeF32() ; - mState = IDLE; + setDebuggerState(IDLE); } break; case GL_TEX: if(processGLCreation(max_time)) { - mState = IDLE; + setDebuggerState(IDLE); mTempTexList.clear(); } break; @@ -4727,7 +4831,7 @@ bool LLTextureFetchDebugger::update(F32 max_time) if (LLAppViewer::getTextureFetch()->getNumRequests() == 0) { mRefetchVisCacheTime = mTimer.getElapsedTimeF32() ; - mState = IDLE; + setDebuggerState(IDLE); mFetcher->lockFetcher(true); mFetcher->resetLoadSource(); } @@ -4736,7 +4840,7 @@ bool LLTextureFetchDebugger::update(F32 max_time) if (LLAppViewer::getTextureFetch()->getNumRequests() == 0) { mRefetchVisHTTPTime = mTimer.getElapsedTimeF32() ; - mState = IDLE; + setDebuggerState(IDLE); mFetcher->lockFetcher(true); mFetcher->resetLoadSource(); } @@ -4753,7 +4857,7 @@ bool LLTextureFetchDebugger::update(F32 max_time) } mRefetchAllCacheTime = mTimer.getElapsedTimeF32() ; - mState = IDLE; + setDebuggerState(IDLE); mFetcher->lockFetcher(true); mFetcher->resetLoadSource(); mRefetchList.clear(); @@ -4765,7 +4869,7 @@ bool LLTextureFetchDebugger::update(F32 max_time) if (LLAppViewer::getTextureFetch()->getNumRequests() == 0) { mRefetchAllHTTPTime = mTimer.getElapsedTimeF32() ; - mState = IDLE; + setDebuggerState(IDLE); mFetcher->lockFetcher(true); mFetcher->resetLoadSource(); mRefetchList.clear(); @@ -4773,11 +4877,11 @@ bool LLTextureFetchDebugger::update(F32 max_time) } break; default: - mState = IDLE; + setDebuggerState(IDLE); break; } - return mState == IDLE; + return mDebuggerState == IDLE; } void LLTextureFetchDebugger::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index d7fb2b4356..c4da2e8685 100755 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -95,7 +95,8 @@ public: // Threads: T* bool getRequestFinished(const LLUUID& id, S32& discard_level, - LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux); + LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux, + LLCore::HttpStatus& last_http_get_status); // Threads: T* bool updateRequestPriority(const LLUUID& id, F32 priority); @@ -396,6 +397,9 @@ private: e_tex_source mFetchSource; e_tex_source mOriginFetchSource; + // Retry logic + //LLAdaptiveRetryPolicy mFetchRetryPolicy; + public: //debug use LLTextureFetchDebugger* getFetchDebugger() { return mFetchDebugger;} @@ -475,8 +479,9 @@ private: typedef std::map<LLCore::HttpHandle, S32> handle_fetch_map_t; handle_fetch_map_t mHandleToFetchIndex; - - e_debug_state mState; + + void setDebuggerState(e_debug_state new_state) { mDebuggerState = new_state; } + e_debug_state mDebuggerState; F32 mCacheReadTime; F32 mCacheWriteTime; @@ -549,7 +554,7 @@ public: void callbackDecoded(S32 id, bool success, LLImageRaw* raw, LLImageRaw* aux); void callbackHTTP(FetchEntry & fetch, LLCore::HttpResponse * response); - e_debug_state getState() {return mState;} + e_debug_state getState() {return mDebuggerState;} S32 getNumFetchedTextures() {return mNumFetchedTextures;} S32 getNumFetchingRequests() {return mFetchingHistory.size();} S32 getNumCacheHits() {return mNumCacheHits;} diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 8ee83b5df0..aa1f680a1e 100755 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -434,15 +434,7 @@ void LLAvatarTexBar::draw() if (!layerset_buffer) continue; LLColor4 text_color = LLColor4::white; - - if (layerset_buffer->uploadNeeded()) - { - text_color = LLColor4::red; - } - if (layerset_buffer->uploadInProgress()) - { - text_color = LLColor4::magenta; - } + std::string text = layerset_buffer->dumpTextureInfo(); LLFontGL::getFontMonospace()->renderUTF8(text, 0, l_offset, v_offset + line_height*line_num, text_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp index a27105e22d..39adfb3431 100755 --- a/indra/newview/lltoastimpanel.cpp +++ b/indra/newview/lltoastimpanel.cpp @@ -54,6 +54,7 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notif mAvatarName = getChild<LLTextBox>("user_name"); mTime = getChild<LLTextBox>("time_box"); mMessage = getChild<LLTextBox>("message"); + mMessage->setContentTrusted(false); LLStyle::Params style_params; LLFontGL* fontp = LLViewerChat::getChatFont(); diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index 51935dc03b..907baf0661 100755 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -270,8 +270,12 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images ) // customize panel's attributes // is it intended for displaying a tip? mIsTip = mNotification->getType() == "notifytip"; + + std::string notif_name = mNotification->getName(); // is it a script dialog? - mIsScriptDialog = (mNotification->getName() == "ScriptDialog" || mNotification->getName() == "ScriptDialogGroup"); + mIsScriptDialog = (notif_name == "ScriptDialog" || notif_name == "ScriptDialogGroup"); + + bool is_content_trusted = (notif_name != "LoadWebPage"); // is it a caution? // // caution flag can be set explicitly by specifying it in the notification payload, or it can be set implicitly if the @@ -314,6 +318,7 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images ) mTextBox->setMaxTextLength(MAX_LENGTH); mTextBox->setVisible(TRUE); mTextBox->setPlainText(!show_images); + mTextBox->setContentTrusted(is_content_trusted); mTextBox->setValue(mNotification->getMessage()); mTextBox->setIsFriendCallback(LLAvatarActions::isFriend); diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 12086dad5f..d307a31843 100755 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1611,16 +1611,19 @@ static void show_item_sharing_confirmation(const std::string name, llassert(NULL != inv_item); return; } - - LLSD substitutions; - substitutions["RESIDENTS"] = name; - substitutions["ITEMS"] = inv_item->getName(); - LLSD payload; - payload["agent_id"] = dest_agent; - payload["item_id"] = inv_item->getUUID(); - payload["session_id"] = session_id; - payload["d&d_dest"] = dest.asString(); - LLNotificationsUtil::add("ShareItemsConfirmation", substitutions, payload, &give_inventory_cb); + if(gInventory.getItem(inv_item->getUUID()) + && LLGiveInventory::isInventoryGiveAcceptable(inv_item)) + { + LLSD substitutions; + substitutions["RESIDENTS"] = name; + substitutions["ITEMS"] = inv_item->getName(); + LLSD payload; + payload["agent_id"] = dest_agent; + payload["item_id"] = inv_item->getUUID(); + payload["session_id"] = session_id; + payload["d&d_dest"] = dest.asString(); + LLNotificationsUtil::add("ShareItemsConfirmation", substitutions, payload, &give_inventory_cb); + } } static void get_name_cb(const LLUUID& id, diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index 148e5a015b..2d458db36b 100755 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -54,6 +54,7 @@ #include "llviewercamera.h" #include "llviewertexturelist.h" #include "llviewerobject.h" +#include "llviewerwearable.h" #include "llviewerwindow.h" #include "llvoavatarself.h" #include "pipeline.h" @@ -147,13 +148,20 @@ BOOL LLVisualParamHint::needsRender() void LLVisualParamHint::preRender(BOOL clear_depth) { + LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr; + if (wearable) + { + wearable->setVolatile(TRUE); + } mLastParamWeight = mVisualParam->getWeight(); - mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); - gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); + mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight); + gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight); gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f); gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f); gAgentAvatarp->updateComposites(); - gAgentAvatarp->updateVisualParams(); + // Calling LLCharacter version, as we don't want position/height changes to cause the avatar to jump + // up and down when we're doing preview renders. -Nyx + gAgentAvatarp->LLCharacter::updateVisualParams(); gAgentAvatarp->updateGeometry(gAgentAvatarp->mDrawable); gAgentAvatarp->updateLOD(); @@ -238,7 +246,13 @@ BOOL LLVisualParamHint::render() gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); - mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE); + mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); + LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr; + if (wearable) + { + wearable->setVolatile(FALSE); + } + gAgentAvatarp->updateVisualParams(); gGL.color4f(1,1,1,1); mGLTexturep->setGLTextureCreated(true); diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index 7e80d72dec..c0ba0a1f39 100755 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -84,7 +84,7 @@ bool LLGoogleTranslationHandler::parseResponse( return false; } - if (status != STATUS_OK) + if (status != HTTP_OK) { // Request failed. Extract error message from the response. parseErrorResponse(root, status, err_msg); @@ -186,7 +186,7 @@ bool LLBingTranslationHandler::parseResponse( std::string& detected_lang, std::string& err_msg) const { - if (status != STATUS_OK) + if (status != HTTP_OK) { static const std::string MSG_BEGIN_MARKER = "Message: "; size_t begin = body.find(MSG_BEGIN_MARKER); @@ -251,8 +251,6 @@ LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_la // virtual void LLTranslate::TranslationReceiver::completedRaw( - U32 http_status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { @@ -262,8 +260,8 @@ void LLTranslate::TranslationReceiver::completedRaw( const std::string body = strstrm.str(); std::string translation, detected_lang, err_msg; - int status = http_status; - LL_DEBUGS("Translate") << "HTTP status: " << status << " " << reason << LL_ENDL; + int status = getStatus(); + LL_DEBUGS("Translate") << "HTTP status: " << status << " " << getReason() << LL_ENDL; LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL; if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg)) { @@ -301,12 +299,10 @@ LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const // virtual void LLTranslate::KeyVerificationReceiver::completedRaw( - U32 http_status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - bool ok = (http_status == 200); + bool ok = (getStatus() == HTTP_OK); setVerificationStatus(ok); } @@ -398,8 +394,8 @@ void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr LLVersionInfo::getPatch(), LLVersionInfo::getBuild()); - sHeader.insert("Accept", "text/plain"); - sHeader.insert("User-Agent", user_agent); + sHeader.insert(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); + sHeader.insert(HTTP_OUT_HEADER_USER_AGENT, user_agent); } LLHTTPClient::get(url, responder, sHeader, REQUEST_TIMEOUT); diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index db5ad9479c..972274714a 100755 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -95,9 +95,6 @@ public: virtual bool isConfigured() const = 0; virtual ~LLTranslationAPIHandler() {} - -protected: - static const int STATUS_OK = 200; }; /// Google Translate v2 API handler. @@ -201,8 +198,6 @@ public : * @see mHandler */ /*virtual*/ void completedRaw( - U32 http_status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); @@ -250,8 +245,6 @@ public : * @see setVerificationStatus() */ /*virtual*/ void completedRaw( - U32 http_status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); diff --git a/indra/newview/lluploadfloaterobservers.cpp b/indra/newview/lluploadfloaterobservers.cpp index 248f1bf1d5..69b9b1f9f1 100755 --- a/indra/newview/lluploadfloaterobservers.cpp +++ b/indra/newview/lluploadfloaterobservers.cpp @@ -1,6 +1,6 @@ /** * @file lluploadfloaterobservers.cpp - * @brief LLUploadModelPremissionsResponder definition + * @brief LLUploadModelPermissionsResponder definition * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code @@ -28,26 +28,31 @@ #include "lluploadfloaterobservers.h" -LLUploadModelPremissionsResponder::LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer) +LLUploadModelPermissionsResponder::LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer) :mObserverHandle(observer) { } -void LLUploadModelPremissionsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLUploadModelPermissionsResponder::httpFailure() { - LL_WARNS() << "LLUploadModelPremissionsResponder error [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; LLUploadPermissionsObserver* observer = mObserverHandle.get(); if (observer) { - observer->setPermissonsErrorStatus(status, reason); + observer->setPermissonsErrorStatus(getStatus(), getReason()); } } -void LLUploadModelPremissionsResponder::result(const LLSD& content) +void LLUploadModelPermissionsResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLUploadPermissionsObserver* observer = mObserverHandle.get(); if (observer) @@ -55,3 +60,4 @@ void LLUploadModelPremissionsResponder::result(const LLSD& content) observer->onPermissionsReceived(content); } } + diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h index b43ddb44d9..4ff4a827a5 100755 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -1,6 +1,6 @@ /** * @file lluploadfloaterobservers.h - * @brief LLUploadModelPremissionsResponder declaration + * @brief LLUploadModelPermissionsResponder declaration * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code @@ -39,7 +39,7 @@ public: virtual ~LLUploadPermissionsObserver() {} virtual void onPermissionsReceived(const LLSD& result) = 0; - virtual void setPermissonsErrorStatus(U32 status, const std::string& reason) = 0; + virtual void setPermissonsErrorStatus(S32 status, const std::string& reason) = 0; LLHandle<LLUploadPermissionsObserver> getPermObserverHandle() const {return mUploadPermObserverHandle;} @@ -54,7 +54,7 @@ public: virtual ~LLWholeModelFeeObserver() {} virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; - virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0; + virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0; LLHandle<LLWholeModelFeeObserver> getWholeModelFeeObserverHandle() const { return mWholeModelFeeObserverHandle; } @@ -80,17 +80,16 @@ protected: }; -class LLUploadModelPremissionsResponder : public LLHTTPClient::Responder +class LLUploadModelPermissionsResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLUploadModelPermissionsResponder); public: - - LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer); - - void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - - void result(const LLSD& content); + LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer); private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); + LLHandle<LLUploadPermissionsObserver> mObserverHandle; }; diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index b905ea2684..615064c782 100755 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -34,6 +34,7 @@ #include "llfloaterreg.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterworldmap.h" +#include "llnotifications.h" #include "llpanellogin.h" #include "llregionhandle.h" #include "llslurl.h" @@ -253,13 +254,15 @@ void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const LLSLURL& //--------------------------------------------------------------------------- // Teleportation links are handled here because they are tightly coupled // to SLURL parsing and sim-fragment parsing + class LLTeleportHandler : public LLCommandHandler { public: // Teleport requests *must* come from a trusted browser // inside the app, otherwise a malicious web page could // cause a constant teleport loop. JC - LLTeleportHandler() : LLCommandHandler("teleport", UNTRUSTED_BLOCK) { } + LLTeleportHandler() : LLCommandHandler("teleport", UNTRUSTED_THROTTLE) { } + bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) @@ -276,18 +279,50 @@ public: tokens[3].asReal()); } + LLSD args; + args["LOCATION"] = tokens[0]; + // Region names may be %20 escaped. - std::string region_name = LLURI::unescape(tokens[0]); + LLSD payload; + payload["region_name"] = region_name; + payload["callback_url"] = LLSLURL(region_name, coords).getSLURLString(); + + LLNotificationsUtil::add("TeleportViaSLAPP", args, payload); + return true; + } + + static void teleport_via_slapp(std::string region_name, std::string callback_url) + { + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name, LLURLDispatcherImpl::regionHandleCallback, - LLSLURL(region_name, coords).getSLURLString(), + callback_url, true); // teleport - return true; } + + static bool teleport_via_slapp_callback(const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + std::string region_name = notification["payload"]["region_name"].asString(); + std::string callback_url = notification["payload"]["callback_url"].asString(); + + if (option == 0) + { + teleport_via_slapp(region_name, callback_url); + return true; + } + + return false; + } + }; LLTeleportHandler gTeleportHandler; +static LLNotificationFunctorRegistration open_landmark_callback_reg("TeleportViaSLAPP", LLTeleportHandler::teleport_via_slapp_callback); + + //--------------------------------------------------------------------------- diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index e27ebe8663..7ce9d858dd 100755 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -94,7 +94,12 @@ void LLViewerAudio::startInternetStreamWithAutoFade(std::string streamURI) switch (mFadeState) { - case FADE_IDLE: + case FADE_IDLE: + if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + break; + } // If a stream is playing fade it out first if (!gAudiop->getInternetStreamURL().empty()) { @@ -116,18 +121,18 @@ void LLViewerAudio::startInternetStreamWithAutoFade(std::string streamURI) break; } - case FADE_OUT: - startFading(); - registerIdleListener(); - break; + case FADE_OUT: + startFading(); + registerIdleListener(); + break; - case FADE_IN: - registerIdleListener(); - break; + case FADE_IN: + registerIdleListener(); + break; - default: - LL_WARNS() << "Unknown fading state: " << mFadeState << LL_ENDL; - break; + default: + LL_WARNS() << "Unknown fading state: " << mFadeState << LL_ENDL; + break; } } @@ -158,19 +163,26 @@ bool LLViewerAudio::onIdleUpdate() // we have finished the current fade operation if (mFadeState == FADE_OUT) { - // Clear URI - gAudiop->startInternetStream(LLStringUtil::null); - gAudiop->stopInternetStream(); + if (gAudiop) + { + // Clear URI + gAudiop->startInternetStream(LLStringUtil::null); + gAudiop->stopInternetStream(); + } if (!mNextStreamURI.empty()) { mFadeState = FADE_IN; - LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); - if(stream && stream->supportsAdjustableBufferSizes()) - stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize")); + if (gAudiop) + { + LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); + if(stream && stream->supportsAdjustableBufferSizes()) + stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize")); + + gAudiop->startInternetStream(mNextStreamURI); + } - gAudiop->startInternetStream(mNextStreamURI); startFading(); } else @@ -182,7 +194,7 @@ bool LLViewerAudio::onIdleUpdate() } else if (mFadeState == FADE_IN) { - if (mNextStreamURI != gAudiop->getInternetStreamURL()) + if (gAudiop && mNextStreamURI != gAudiop->getInternetStreamURL()) { mFadeState = FADE_OUT; startFading(); @@ -204,9 +216,12 @@ void LLViewerAudio::stopInternetStreamWithAutoFade() mFadeState = FADE_IDLE; mNextStreamURI = LLStringUtil::null; mDone = true; - - gAudiop->startInternetStream(LLStringUtil::null); - gAudiop->stopInternetStream(); + + if (gAudiop) + { + gAudiop->startInternetStream(LLStringUtil::null); + gAudiop->stopInternetStream(); + } } void LLViewerAudio::startFading() @@ -268,7 +283,7 @@ F32 LLViewerAudio::getFadeVolume() void LLViewerAudio::onTeleportStarted() { - if (!LLViewerAudio::getInstance()->getForcedTeleportFade()) + if (gAudiop && !LLViewerAudio::getInstance()->getForcedTeleportFade()) { // Even though the music was turned off it was starting up (with autoplay disabled) occasionally // after a failed teleport or after an intra-parcel teleport. Also, the music sometimes was not @@ -394,9 +409,10 @@ void audio_update_volume(bool force_update) } F32 mute_volume = mute_audio ? 0.0f : 1.0f; - // Sound Effects if (gAudiop) { + // Sound Effects + gAudiop->setMasterGain ( master_volume ); gAudiop->setDopplerFactor(gSavedSettings.getF32("AudioLevelDoppler")); @@ -426,11 +442,9 @@ void audio_update_volume(bool force_update) gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI")); gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_AMBIENT, gSavedSettings.getBOOL("MuteAmbient") ? 0.f : gSavedSettings.getF32("AudioLevelAmbient")); - } - // Streaming Music - if (gAudiop) - { + // Streaming Music + if (!progress_view_visible && LLViewerAudio::getInstance()->getForcedTeleportFade()) { LLViewerAudio::getInstance()->setWasPlaying(!gAudiop->getInternetStreamURL().empty()); @@ -528,6 +542,12 @@ void audio_update_wind(bool force_update) volume_delta = 1.f; } + if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + return; + } + // mute wind when not flying if (gAgent.getFlying()) { diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index 3d794f0d91..e390e8776d 100755 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -58,12 +58,12 @@ namespace LLViewerDisplayName class LLSetDisplayNameResponder : public LLHTTPClient::Responder { -public: + LOG_CLASS(LLSetDisplayNameResponder); +private: // only care about errors - /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + /*virtual*/ void httpFailure() { - LL_WARNS() << "LLSetDisplayNameResponder error [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD()); LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); } @@ -86,7 +86,7 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl // People API can return localized error messages. Indicate our // language preference via header. LLSD headers; - headers["Accept-Language"] = LLUI::getLanguage(); + headers[HTTP_OUT_HEADER_ACCEPT_LANGUAGE] = LLUI::getLanguage(); // People API requires both the old and new value to change a variable. // Our display name will be in cache before the viewer's UI is available @@ -128,7 +128,7 @@ public: LLSD body = input["body"]; S32 status = body["status"].asInteger(); - bool success = (status == 200); + bool success = (status == HTTP_OK); std::string reason = body["reason"].asString(); LLSD content = body["content"]; @@ -137,7 +137,7 @@ public: // If viewer's concept of display name is out-of-date, the set request // will fail with 409 Conflict. If that happens, fetch up-to-date // name information. - if (status == 409) + if (status == HTTP_CONFLICT) { LLUUID agent_id = gAgent.getID(); // Flush stale data diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp index 4237ffd295..2c196ece51 100644 --- a/indra/newview/llviewerfoldertype.cpp +++ b/indra/newview/llviewerfoldertype.cpp @@ -143,14 +143,10 @@ LLViewerFolderDictionary::LLViewerFolderDictionary() addEntry(LLFolderType::FT_NONE, new ViewerFolderEntry("New Folder", "Inv_FolderOpen", "Inv_FolderClosed", FALSE, false, "default")); -#if SUPPORT_ENSEMBLES - initEnsemblesFromFile(); -#else for (U32 type = (U32)LLFolderType::FT_ENSEMBLE_START; type <= (U32)LLFolderType::FT_ENSEMBLE_END; ++type) { addEntry((LLFolderType::EType)type, new ViewerFolderEntry("New Folder", "Inv_FolderOpen", "Inv_FolderClosed", FALSE, false)); - } -#endif + } } bool LLViewerFolderDictionary::initEnsemblesFromFile() diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index a4773646ef..b236bba3b7 100755 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -31,6 +31,7 @@ #include "llsdserialize.h" #include "message.h" +#include "llaisapi.h" #include "llagent.h" #include "llagentcamera.h" #include "llagentwearables.h" @@ -65,9 +66,12 @@ #include "llavataractions.h" #include "lllogininstance.h" #include "llfavoritesbar.h" +#include "llclipboard.h" +#include "llhttpretrypolicy.h" -// Two do-nothing ops for use in callbacks. +// do-nothing ops for use in callbacks. void no_op_inventory_func(const LLUUID&) {} +void no_op_llsd_func(const LLSD&) {} void no_op() {} ///---------------------------------------------------------------------------- @@ -256,7 +260,6 @@ public: }; LLInventoryHandler gInventoryHandler; - ///---------------------------------------------------------------------------- /// Class LLViewerInventoryItem ///---------------------------------------------------------------------------- @@ -345,24 +348,6 @@ void LLViewerInventoryItem::cloneViewerItem(LLPointer<LLViewerInventoryItem>& ne } } -void LLViewerInventoryItem::removeFromServer() -{ - LL_DEBUGS() << "Removing inventory item " << mUUID << " from server." - << LL_ENDL; - - LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1); - gInventory.accountForUpdate(up); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RemoveInventoryItem); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_ItemID, mUUID); - gAgent.sendReliableMessage(); -} - void LLViewerInventoryItem::updateServer(BOOL is_new) const { if(!mIsComplete) @@ -376,8 +361,9 @@ void LLViewerInventoryItem::updateServer(BOOL is_new) const if(gAgent.getID() != mPermissions.getOwner()) { // *FIX: deal with this better. - LL_WARNS() << "LLViewerInventoryItem::updateServer() - for unowned item" - << LL_ENDL; + LL_WARNS() << "LLViewerInventoryItem::updateServer() - for unowned item " + << ll_pretty_print_sd(this->asLLSD()) + << LL_ENDL; return; } LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0); @@ -444,7 +430,7 @@ void LLViewerInventoryItem::fetchFromServer(void) const } // virtual -BOOL LLViewerInventoryItem::unpackMessage(LLSD item) +BOOL LLViewerInventoryItem::unpackMessage(const LLSD& item) { BOOL rv = LLInventoryItem::fromLLSD(item); @@ -469,7 +455,7 @@ void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_ { mTransactionID = transaction_id; } -// virtual + void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const { msg->addUUIDFast(_PREHASH_ItemID, mUUID); @@ -488,6 +474,7 @@ void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const U32 crc = getCRC32(); msg->addU32Fast(_PREHASH_CRC, crc); } + // virtual BOOL LLViewerInventoryItem::importFile(LLFILE* fp) { @@ -599,6 +586,15 @@ void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCatego } +void LLViewerInventoryCategory::packMessage(LLMessageSystem* msg) const +{ + msg->addUUIDFast(_PREHASH_FolderID, mUUID); + msg->addUUIDFast(_PREHASH_ParentID, mParentUUID); + S8 type = static_cast<S8>(mPreferredType); + msg->addS8Fast(_PREHASH_Type, type); + msg->addStringFast(_PREHASH_Name, mName); +} + void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const { LLMessageSystem* msg = gMessageSystem; @@ -637,30 +633,6 @@ void LLViewerInventoryCategory::updateServer(BOOL is_new) const gAgent.sendReliableMessage(); } -void LLViewerInventoryCategory::removeFromServer( void ) -{ - LL_INFOS() << "Removing inventory category " << mUUID << " from server." - << LL_ENDL; - // communicate that change with the server. - if(LLFolderType::lookupIsProtectedType(mPreferredType)) - { - LLNotificationsUtil::add("CannotRemoveProtectedCategories"); - return; - } - - LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1); - gInventory.accountForUpdate(up); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RemoveInventoryFolder); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, mUUID); - gAgent.sendReliableMessage(); -} - S32 LLViewerInventoryCategory::getVersion() const { return mVersion; @@ -729,6 +701,19 @@ bool LLViewerInventoryCategory::fetch() return false; } +S32 LLViewerInventoryCategory::getViewerDescendentCount() const +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(getUUID(), cats, items); + S32 descendents_actual = 0; + if(cats && items) + { + descendents_actual = cats->size() + items->size(); + } + return descendents_actual; +} + bool LLViewerInventoryCategory::importFileLocal(LLFILE* fp) { // *NOTE: This buffer size is hard coded into scanf() below. @@ -894,6 +879,21 @@ void LLViewerInventoryCategory::localizeName() LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName); } +// virtual +BOOL LLViewerInventoryCategory::unpackMessage(const LLSD& category) +{ + BOOL rv = LLInventoryCategory::fromLLSD(category); + localizeName(); + return rv; +} + +// virtual +void LLViewerInventoryCategory::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num) +{ + LLInventoryCategory::unpackMessage(msg, block, block_num); + localizeName(); +} + ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- @@ -1087,75 +1087,148 @@ void copy_inventory_item( gAgent.sendReliableMessage(); } -void link_inventory_item( - const LLUUID& agent_id, - const LLUUID& item_id, - const LLUUID& parent_id, - const std::string& new_name, - const std::string& new_description, - const LLAssetType::EType asset_type, - LLPointer<LLInventoryCallback> cb) +// Create link to single inventory object. +void link_inventory_object(const LLUUID& category, + LLConstPointer<LLInventoryObject> baseobj, + LLPointer<LLInventoryCallback> cb) { - const LLInventoryObject *baseobj = gInventory.getObject(item_id); if (!baseobj) { - LL_WARNS() << "attempt to link to unknown item, linked-to-item's itemID " << item_id << LL_ENDL; - return; - } - if (baseobj && baseobj->getIsLinkType()) - { - LL_WARNS() << "attempt to create a link to a link, linked-to-item's itemID " << item_id << LL_ENDL; + LL_WARNS() << "Attempt to link to non-existent object" << LL_ENDL; return; } - if (baseobj && !LLAssetType::lookupCanLink(baseobj->getType())) - { - // Fail if item can be found but is of a type that can't be linked. - // Arguably should fail if the item can't be found too, but that could - // be a larger behavioral change. - LL_WARNS() << "attempt to link an unlinkable item, type = " << baseobj->getActualType() << LL_ENDL; - return; - } - - LLUUID transaction_id; - LLInventoryType::EType inv_type = LLInventoryType::IT_NONE; - if (dynamic_cast<const LLInventoryCategory *>(baseobj)) - { - inv_type = LLInventoryType::IT_CATEGORY; - } - else + LLInventoryObject::const_object_list_t obj_array; + obj_array.push_back(baseobj); + link_inventory_array(category, obj_array, cb); +} + +void link_inventory_object(const LLUUID& category, + const LLUUID& id, + LLPointer<LLInventoryCallback> cb) +{ + LLConstPointer<LLInventoryObject> baseobj = gInventory.getObject(id); + link_inventory_object(category, baseobj, cb); +} + +// Create links to all listed inventory objects. +void link_inventory_array(const LLUUID& category, + LLInventoryObject::const_object_list_t& baseobj_array, + LLPointer<LLInventoryCallback> cb) +{ +#ifndef LL_RELEASE_FOR_DOWNLOAD + const LLViewerInventoryCategory *cat = gInventory.getCategory(category); + const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; +#endif + LLInventoryObject::const_object_list_t::const_iterator it = baseobj_array.begin(); + LLInventoryObject::const_object_list_t::const_iterator end = baseobj_array.end(); + LLSD links = LLSD::emptyArray(); + for (; it != end; ++it) { - const LLViewerInventoryItem *baseitem = dynamic_cast<const LLViewerInventoryItem *>(baseobj); - if (baseitem) + const LLInventoryObject* baseobj = *it; + if (!baseobj) { - inv_type = baseitem->getInventoryType(); + LL_WARNS() << "attempt to link to unknown object" << LL_ENDL; + continue; } - } -#if 1 // debugging stuff - LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); - LL_DEBUGS() << "cat: " << cat << LL_ENDL; - + if (!LLAssetType::lookupCanLink(baseobj->getType())) + { + // Fail if item can be found but is of a type that can't be linked. + // Arguably should fail if the item can't be found too, but that could + // be a larger behavioral change. + LL_WARNS() << "attempt to link an unlinkable object, type = " << baseobj->getActualType() << LL_ENDL; + continue; + } + + LLInventoryType::EType inv_type = LLInventoryType::IT_NONE; + LLAssetType::EType asset_type = LLAssetType::AT_NONE; + std::string new_desc; + LLUUID linkee_id; + if (dynamic_cast<const LLInventoryCategory *>(baseobj)) + { + inv_type = LLInventoryType::IT_CATEGORY; + asset_type = LLAssetType::AT_LINK_FOLDER; + linkee_id = baseobj->getUUID(); + } + else + { + const LLViewerInventoryItem *baseitem = dynamic_cast<const LLViewerInventoryItem *>(baseobj); + if (baseitem) + { + inv_type = baseitem->getInventoryType(); + new_desc = baseitem->getActualDescription(); + switch (baseitem->getActualType()) + { + case LLAssetType::AT_LINK: + case LLAssetType::AT_LINK_FOLDER: + linkee_id = baseobj->getLinkedUUID(); + asset_type = baseitem->getActualType(); + break; + default: + linkee_id = baseobj->getUUID(); + asset_type = LLAssetType::AT_LINK; + break; + } + } + else + { + LL_WARNS() << "could not convert object into an item or category: " << baseobj->getUUID() << LL_ENDL; + continue; + } + } + + LLSD link = LLSD::emptyMap(); + link["linked_id"] = linkee_id; + link["type"] = (S8)asset_type; + link["inv_type"] = (S8)inv_type; + link["name"] = baseobj->getName(); + link["desc"] = new_desc; + links.append(link); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS("Inventory") << "Linking Object [ name:" << baseobj->getName() + << " UUID:" << baseobj->getUUID() + << " ] into Category [ name:" << cat_name + << " UUID:" << category << " ] " << LL_ENDL; #endif - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_LinkInventoryItem); - msg->nextBlock(_PREHASH_AgentData); + } + + bool ais_ran = false; + if (AISCommand::isAPIAvailable()) { - msg->addUUIDFast(_PREHASH_AgentID, agent_id); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + LLSD new_inventory = LLSD::emptyMap(); + new_inventory["links"] = links; + LLPointer<AISCommand> cmd_ptr = new CreateInventoryCommand(category, new_inventory, cb); + ais_ran = cmd_ptr->run_command(); } - msg->nextBlock(_PREHASH_InventoryBlock); + + if (!ais_ran) { - msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); - msg->addUUIDFast(_PREHASH_FolderID, parent_id); - msg->addUUIDFast(_PREHASH_TransactionID, transaction_id); - msg->addUUIDFast(_PREHASH_OldItemID, item_id); - msg->addS8Fast(_PREHASH_Type, (S8)asset_type); - msg->addS8Fast(_PREHASH_InvType, (S8)inv_type); - msg->addStringFast(_PREHASH_Name, new_name); - msg->addStringFast(_PREHASH_Description, new_description); + LLMessageSystem* msg = gMessageSystem; + for (LLSD::array_iterator iter = links.beginArray(); iter != links.endArray(); ++iter ) + { + msg->newMessageFast(_PREHASH_LinkInventoryItem); + msg->nextBlock(_PREHASH_AgentData); + { + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + msg->nextBlock(_PREHASH_InventoryBlock); + { + LLSD link = (*iter); + msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); + msg->addUUIDFast(_PREHASH_FolderID, category); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); + msg->addUUIDFast(_PREHASH_OldItemID, link["linked_id"].asUUID()); + msg->addS8Fast(_PREHASH_Type, link["type"].asInteger()); + msg->addS8Fast(_PREHASH_InvType, link["inv_type"].asInteger()); + msg->addStringFast(_PREHASH_Name, link["name"].asString()); + msg->addStringFast(_PREHASH_Description, link["desc"].asString()); + } + gAgent.sendReliableMessage(); + } } - gAgent.sendReliableMessage(); } void move_inventory_item( @@ -1179,6 +1252,392 @@ void move_inventory_item( gAgent.sendReliableMessage(); } +// Should call this with an update_item that's been copied and +// modified from an original source item, rather than modifying the +// source item directly. +void update_inventory_item( + LLViewerInventoryItem *update_item, + LLPointer<LLInventoryCallback> cb) +{ + const LLUUID& item_id = update_item->getUUID(); + bool ais_ran = false; + if (AISCommand::isAPIAvailable()) + { + LLSD updates = update_item->asLLSD(); + // Replace asset_id and/or shadow_id with transaction_id (hash_id) + if (updates.has("asset_id")) + { + updates.erase("asset_id"); + updates["hash_id"] = update_item->getTransactionID(); + } + if (updates.has("shadow_id")) + { + updates.erase("shadow_id"); + updates["hash_id"] = update_item->getTransactionID(); + } + LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb); + ais_ran = cmd_ptr->run_command(); + } + if (!ais_ran) + { + LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id); + LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (update_item ? update_item->getName() : "(NOT FOUND)") << LL_ENDL; + if(obj) + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, update_item->getTransactionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_CallbackID, 0); + update_item->packMessage(msg); + gAgent.sendReliableMessage(); + + LLInventoryModel::LLCategoryUpdate up(update_item->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.updateItem(update_item); + if (cb) + { + cb->fire(item_id); + } + } + } +} + +// Note this only supports updating an existing item. Goes through AISv3 +// code path where available. Not all uses of item->updateServer() can +// easily be switched to this paradigm. +void update_inventory_item( + const LLUUID& item_id, + const LLSD& updates, + LLPointer<LLInventoryCallback> cb) +{ + bool ais_ran = false; + if (AISCommand::isAPIAvailable()) + { + LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb); + ais_ran = cmd_ptr->run_command(); + } + if (!ais_ran) + { + LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id); + LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << LL_ENDL; + if(obj) + { + LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem); + new_item->copyViewerItem(obj); + new_item->fromLLSD(updates,false); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, new_item->getTransactionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_CallbackID, 0); + new_item->packMessage(msg); + gAgent.sendReliableMessage(); + + LLInventoryModel::LLCategoryUpdate up(new_item->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.updateItem(new_item); + if (cb) + { + cb->fire(item_id); + } + } + } +} + +void update_inventory_category( + const LLUUID& cat_id, + const LLSD& updates, + LLPointer<LLInventoryCallback> cb) +{ + LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id); + LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << LL_ENDL; + if(obj) + { + if (LLFolderType::lookupIsProtectedType(obj->getPreferredType())) + { + LLNotificationsUtil::add("CannotModifyProtectedCategories"); + return; + } + + LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(obj); + new_cat->fromLLSD(updates); + // FIXME - restore this once the back-end work has been done. + if (AISCommand::isAPIAvailable()) + { + LLSD new_llsd = new_cat->asLLSD(); + LLPointer<AISCommand> cmd_ptr = new UpdateCategoryCommand(cat_id, new_llsd, cb); + cmd_ptr->run_command(); + } + else // no cap + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + new_cat->packMessage(msg); + gAgent.sendReliableMessage(); + + LLInventoryModel::LLCategoryUpdate up(new_cat->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.updateCategory(new_cat); + if (cb) + { + cb->fire(cat_id); + } + } + } +} + +void remove_inventory_items( + LLInventoryObject::object_list_t& items_to_kill, + LLPointer<LLInventoryCallback> cb) +{ + for (LLInventoryObject::object_list_t::iterator it = items_to_kill.begin(); + it != items_to_kill.end(); + ++it) + { + remove_inventory_item(*it, cb); + } +} + +void remove_inventory_item( + const LLUUID& item_id, + LLPointer<LLInventoryCallback> cb) +{ + LLPointer<LLInventoryObject> obj = gInventory.getItem(item_id); + if (obj) + { + remove_inventory_item(obj, cb); + } + else + { + LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << "(NOT FOUND)" << LL_ENDL; + } +} + +void remove_inventory_item( + LLPointer<LLInventoryObject> obj, + LLPointer<LLInventoryCallback> cb) +{ + if(obj) + { + const LLUUID item_id(obj->getUUID()); + LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << obj->getName() << LL_ENDL; + if (AISCommand::isAPIAvailable()) + { + LLPointer<AISCommand> cmd_ptr = new RemoveItemCommand(item_id, cb); + cmd_ptr->run_command(); + } + else // no cap + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RemoveInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addUUIDFast(_PREHASH_ItemID, item_id); + gAgent.sendReliableMessage(); + + // Update inventory and call callback immediately since + // message-based system has no callback mechanism (!) + gInventory.onObjectDeletedFromServer(item_id); + if (cb) + { + cb->fire(item_id); + } + } + } + else + { + // *TODO: Clean up callback? + LL_WARNS() << "remove_inventory_item called for invalid or nonexistent item." << LL_ENDL; + } +} + +class LLRemoveCategoryOnDestroy: public LLInventoryCallback +{ +public: + LLRemoveCategoryOnDestroy(const LLUUID& cat_id, LLPointer<LLInventoryCallback> cb): + mID(cat_id), + mCB(cb) + { + } + /* virtual */ void fire(const LLUUID& item_id) {} + ~LLRemoveCategoryOnDestroy() + { + LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(mID); + if(children != LLInventoryModel::CHILDREN_NO) + { + LL_WARNS() << "remove descendents failed, cannot remove category " << LL_ENDL; + } + else + { + remove_inventory_category(mID, mCB); + } + } +private: + LLUUID mID; + LLPointer<LLInventoryCallback> mCB; +}; + +void remove_inventory_category( + const LLUUID& cat_id, + LLPointer<LLInventoryCallback> cb) +{ + LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] " << LL_ENDL; + LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id); + if(obj) + { + if(LLFolderType::lookupIsProtectedType(obj->getPreferredType())) + { + LLNotificationsUtil::add("CannotRemoveProtectedCategories"); + return; + } + if (AISCommand::isAPIAvailable()) + { + LLPointer<AISCommand> cmd_ptr = new RemoveCategoryCommand(cat_id, cb); + cmd_ptr->run_command(); + } + else // no cap + { + // RemoveInventoryFolder does not remove children, so must + // clear descendents first. + LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(cat_id); + if(children != LLInventoryModel::CHILDREN_NO) + { + LL_DEBUGS("Inventory") << "Will purge descendents first before deleting category " << cat_id << LL_ENDL; + LLPointer<LLInventoryCallback> wrap_cb = new LLRemoveCategoryOnDestroy(cat_id, cb); + purge_descendents_of(cat_id, wrap_cb); + return; + } + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RemoveInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, cat_id); + gAgent.sendReliableMessage(); + + // Update inventory and call callback immediately since + // message-based system has no callback mechanism (!) + gInventory.onObjectDeletedFromServer(cat_id); + if (cb) + { + cb->fire(cat_id); + } + } + } + else + { + LL_WARNS() << "remove_inventory_category called for invalid or nonexistent item " << cat_id << LL_ENDL; + } +} + +void remove_inventory_object( + const LLUUID& object_id, + LLPointer<LLInventoryCallback> cb) +{ + if (gInventory.getCategory(object_id)) + { + remove_inventory_category(object_id, cb); + } + else + { + remove_inventory_item(object_id, cb); + } +} + +// This is a method which collects the descendents of the id +// provided. If the category is not found, no action is +// taken. This method goes through the long winded process of +// cancelling any calling cards, removing server representation of +// folders, items, etc in a fairly efficient manner. +void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb) +{ + LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(id); + if(children == LLInventoryModel::CHILDREN_NO) + { + LL_DEBUGS("Inventory") << "No descendents to purge for " << id << LL_ENDL; + return; + } + LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(id); + if (cat.notNull()) + { + if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode()) + { + // Something on the clipboard is in "cut mode" and needs to be preserved + LL_DEBUGS("Inventory") << "purge_descendents_of clipboard case " << cat->getName() + << " iterate and purge non hidden items" << LL_ENDL; + LLInventoryModel::cat_array_t* categories; + LLInventoryModel::item_array_t* items; + // Get the list of direct descendants in tha categoy passed as argument + gInventory.getDirectDescendentsOf(id, categories, items); + std::vector<LLUUID> list_uuids; + // Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently) + // Note: we need to do that shallow copy as purging things will invalidate the categories or items lists + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) + { + list_uuids.push_back((*it)->getUUID()); + } + for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) + { + list_uuids.push_back((*it)->getUUID()); + } + // Iterate through the list and only purge the UUIDs that are not on the clipboard + for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) + { + if (!LLClipboard::instance().isOnClipboard(*it)) + { + remove_inventory_object(*it, NULL); + } + } + } + else + { + if (AISCommand::isAPIAvailable()) + { + LLPointer<AISCommand> cmd_ptr = new PurgeDescendentsCommand(id, cb); + cmd_ptr->run_command(); + } + else // no cap + { + // Fast purge + LL_DEBUGS("Inventory") << "purge_descendents_of fast case " << cat->getName() << LL_ENDL; + + // send it upstream + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("PurgeInventoryDescendents"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("InventoryData"); + msg->addUUID("FolderID", id); + gAgent.sendReliableMessage(); + + // Update model immediately because there is no callback mechanism. + gInventory.onDescendentsPurgedFromServer(id); + if (cb) + { + cb->fire(id); + } + } + } + } +} + const LLUUID get_folder_by_itemtype(const LLInventoryItem *src) { LLUUID retval = LLUUID::null; @@ -1278,6 +1737,53 @@ void create_new_item(const std::string& name, } +void slam_inventory_folder(const LLUUID& folder_id, + const LLSD& contents, + LLPointer<LLInventoryCallback> cb) +{ + if (AISCommand::isAPIAvailable()) + { + LL_DEBUGS("Avatar") << "using AISv3 to slam folder, id " << folder_id + << " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL; + LLPointer<AISCommand> cmd_ptr = new SlamFolderCommand(folder_id, contents, cb); + cmd_ptr->run_command(); + } + else // no cap + { + LL_DEBUGS("Avatar") << "using item-by-item calls to slam folder, id " << folder_id + << " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL; + for (LLSD::array_const_iterator it = contents.beginArray(); + it != contents.endArray(); + ++it) + { + const LLSD& item_contents = *it; + LLViewerInventoryItem *item = new LLViewerInventoryItem; + item->fromLLSD(item_contents); + link_inventory_object(folder_id, item, cb); + } + remove_folder_contents(folder_id,false,cb); + } +} + +void remove_folder_contents(const LLUUID& category, bool keep_outfit_links, + LLPointer<LLInventoryCallback> cb) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(category, cats, items, + LLInventoryModel::EXCLUDE_TRASH); + for (S32 i = 0; i < items.size(); ++i) + { + LLViewerInventoryItem *item = items.at(i); + if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER)) + continue; + if (item->getIsLinkType()) + { + remove_inventory_item(item->getUUID(), cb); + } + } +} + const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not) const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not) const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not) @@ -1713,3 +2219,5 @@ BOOL LLViewerInventoryItem::regenerateLink() gInventory.notifyObservers(); return TRUE; } + + diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index a10eda947d..c284c703d4 100755 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -118,14 +118,13 @@ public: void cloneViewerItem(LLPointer<LLViewerInventoryItem>& newitem) const; // virtual methods - virtual void removeFromServer( void ); virtual void updateParentOnServer(BOOL restamp) const; virtual void updateServer(BOOL is_new) const; void fetchFromServer(void) const; - //virtual void packMessage(LLMessageSystem* msg) const; + virtual void packMessage(LLMessageSystem* msg) const; virtual BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); - virtual BOOL unpackMessage(LLSD item); + virtual BOOL unpackMessage(const LLSD& item); virtual BOOL importFile(LLFILE* fp); virtual BOOL importLegacyStream(std::istream& input_stream); @@ -139,7 +138,6 @@ public: void setComplete(BOOL complete) { mIsComplete = complete; } //void updateAssetOnServer() const; - virtual void packMessage(LLMessageSystem* msg) const; virtual void setTransactionID(const LLTransactionID& transaction_id); struct comparePointers { @@ -198,10 +196,11 @@ public: LLViewerInventoryCategory(const LLViewerInventoryCategory* other); void copyViewerCategory(const LLViewerInventoryCategory* other); - virtual void removeFromServer(); virtual void updateParentOnServer(BOOL restamp_children) const; virtual void updateServer(BOOL is_new) const; + virtual void packMessage(LLMessageSystem* msg) const; + const LLUUID& getOwnerID() const { return mOwnerID; } // Version handling @@ -218,6 +217,8 @@ public: enum { DESCENDENT_COUNT_UNKNOWN = -1 }; S32 getDescendentCount() const { return mDescendentCount; } void setDescendentCount(S32 descendents) { mDescendentCount = descendents; } + // How many descendents do we currently have information for in the InventoryModel? + S32 getViewerDescendentCount() const; // file handling on the viewer. These are not meant for anything // other than caching. @@ -225,6 +226,8 @@ public: bool importFileLocal(LLFILE* fp); void determineFolderType(); void changeType(LLFolderType::EType new_folder_type); + virtual void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); + virtual BOOL unpackMessage(const LLSD& category); private: friend class LLInventoryModel; @@ -264,9 +267,11 @@ private: }; typedef boost::function<void(const LLUUID&)> inventory_func_type; -void no_op_inventory_func(const LLUUID&); // A do-nothing inventory_func - +typedef boost::function<void(const LLSD&)> llsd_func_type; typedef boost::function<void()> nullary_func_type; + +void no_op_inventory_func(const LLUUID&); // A do-nothing inventory_func +void no_op_llsd_func(const LLSD&); // likewise for LLSD void no_op(); // A do-nothing nullary func. // Shim between inventory callback and boost function/callable @@ -274,7 +279,7 @@ class LLBoostFuncInventoryCallback: public LLInventoryCallback { public: - LLBoostFuncInventoryCallback(inventory_func_type fire_func, + LLBoostFuncInventoryCallback(inventory_func_type fire_func = no_op_inventory_func, nullary_func_type destroy_func = no_op): mFireFunc(fire_func), mDestroyFunc(destroy_func) @@ -348,14 +353,16 @@ void copy_inventory_item( const std::string& new_name, LLPointer<LLInventoryCallback> cb); -void link_inventory_item( - const LLUUID& agent_id, - const LLUUID& item_id, - const LLUUID& parent_id, - const std::string& new_name, - const std::string& new_description, - const LLAssetType::EType asset_type, - LLPointer<LLInventoryCallback> cb); +// utility functions for inventory linking. +void link_inventory_object(const LLUUID& category, + LLConstPointer<LLInventoryObject> baseobj, + LLPointer<LLInventoryCallback> cb); +void link_inventory_object(const LLUUID& category, + const LLUUID& id, + LLPointer<LLInventoryCallback> cb); +void link_inventory_array(const LLUUID& category, + LLInventoryObject::const_object_list_t& baseobj_array, + LLPointer<LLInventoryCallback> cb); void move_inventory_item( const LLUUID& agent_id, @@ -365,6 +372,44 @@ void move_inventory_item( const std::string& new_name, LLPointer<LLInventoryCallback> cb); +void update_inventory_item( + LLViewerInventoryItem *update_item, + LLPointer<LLInventoryCallback> cb); + +void update_inventory_item( + const LLUUID& item_id, + const LLSD& updates, + LLPointer<LLInventoryCallback> cb); + +void update_inventory_category( + const LLUUID& cat_id, + const LLSD& updates, + LLPointer<LLInventoryCallback> cb); + +void remove_inventory_items( + LLInventoryObject::object_list_t& items, + LLPointer<LLInventoryCallback> cb); + +void remove_inventory_item( + LLPointer<LLInventoryObject> obj, + LLPointer<LLInventoryCallback> cb); + +void remove_inventory_item( + const LLUUID& item_id, + LLPointer<LLInventoryCallback> cb); + +void remove_inventory_category( + const LLUUID& cat_id, + LLPointer<LLInventoryCallback> cb); + +void remove_inventory_object( + const LLUUID& object_id, + LLPointer<LLInventoryCallback> cb); + +void purge_descendents_of( + const LLUUID& cat_id, + LLPointer<LLInventoryCallback> cb); + const LLUUID get_folder_by_itemtype(const LLInventoryItem *src); void copy_inventory_from_notecard(const LLUUID& destination_id, @@ -379,4 +424,11 @@ void menu_create_inventory_item(LLInventoryPanel* root, const LLSD& userdata, const LLUUID& default_parent_uuid = LLUUID::null); +void slam_inventory_folder(const LLUUID& folder_id, + const LLSD& contents, + LLPointer<LLInventoryCallback> cb); + +void remove_folder_contents(const LLUUID& folder_id, bool keep_outfit_links, + LLPointer<LLInventoryCallback> cb); + #endif // LL_LLVIEWERINVENTORY_H diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 7958537856..ed26842035 100755 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -67,7 +67,6 @@ #include "llvoavatarself.h" #include "llvovolume.h" #include "llwebprofile.h" -#include "llwebsharing.h" // For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this! #include "llwindow.h" #include "llvieweraudio.h" @@ -158,7 +157,7 @@ LLViewerMediaObserver::~LLViewerMediaObserver() // on the Panel Land Media and to discover the MIME type class LLMimeDiscoveryResponder : public LLHTTPClient::Responder { -LOG_CLASS(LLMimeDiscoveryResponder); + LOG_CLASS(LLMimeDiscoveryResponder); public: LLMimeDiscoveryResponder( viewer_media_t media_impl) : mMediaImpl(media_impl), @@ -177,13 +176,19 @@ public: disconnectOwner(); } - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) +private: + /* virtual */ void httpCompleted() { - std::string media_type = content["content-type"].asString(); + if (!isGoodStatus()) + { + LL_WARNS() << dumpResponse() + << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; + } + const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE); std::string::size_type idx1 = media_type.find_first_of(";"); std::string mime_type = media_type.substr(0, idx1); - LL_DEBUGS() << "status is " << status << ", media type \"" << media_type << "\"" << LL_ENDL; + LL_DEBUGS() << "status is " << getStatus() << ", media type \"" << media_type << "\"" << LL_ENDL; // 2xx status codes indicate success. // Most 4xx status codes are successful enough for our purposes. @@ -200,32 +205,27 @@ public: // ) // We now no longer check the error code returned from the probe. // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting. - if(1) + //if(1) { // The probe was successful. if(mime_type.empty()) { // Some sites don't return any content-type header at all. // Treat an empty mime type as text/html. - mime_type = "text/html"; - } - - completeAny(status, mime_type); - } - else - { - LL_WARNS() << "responder failed with status " << status << ", reason " << reason << LL_ENDL; - - if(mMediaImpl) - { - mMediaImpl->mMediaSourceFailed = true; + mime_type = HTTP_CONTENT_TEXT_HTML; } } + //else + //{ + // LL_WARNS() << "responder failed with status " << dumpResponse() << LL_ENDL; + // + // if(mMediaImpl) + // { + // mMediaImpl->mMediaSourceFailed = true; + // } + // return; + //} - } - - void completeAny(U32 status, const std::string& mime_type) - { // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl. // Make a local copy so we can call loadURI() afterwards. LLViewerMediaImpl *impl = mMediaImpl; @@ -241,6 +241,7 @@ public: } } +public: void cancelRequest() { disconnectOwner(); @@ -269,7 +270,7 @@ public: class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder { -LOG_CLASS(LLViewerMediaOpenIDResponder); + LOG_CLASS(LLViewerMediaOpenIDResponder); public: LLViewerMediaOpenIDResponder( ) { @@ -279,23 +280,17 @@ public: { } - /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; - LL_DEBUGS("MediaAuth") << content << LL_ENDL; - std::string cookie = content["set-cookie"].asString(); - - LLViewerMedia::openIDCookieResponse(cookie); - } - /* virtual */ void completedRaw( - U32 status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - // This is just here to disable the default behavior (attempting to parse the response as llsd). - // We don't care about the content of the response, only the set-cookie header. + // We don't care about the content of the response, only the Set-Cookie header. + LL_DEBUGS("MediaAuth") << dumpResponse() + << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; + const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); + + // *TODO: What about bad status codes? Does this destroy previous cookies? + LLViewerMedia::openIDCookieResponse(cookie); } }; @@ -313,17 +308,23 @@ public: { } - /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + void completedRaw( + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { - LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + // We don't care about the content of the response, only the set-cookie header. + LL_WARNS("MediaAuth") << dumpResponse() + << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; - LLSD stripped_content = content; - stripped_content.erase("set-cookie"); + LLSD stripped_content = getResponseHeaders(); + // *TODO: Check that this works. + stripped_content.erase(HTTP_IN_HEADER_SET_COOKIE); LL_WARNS("MediaAuth") << stripped_content << LL_ENDL; - std::string cookie = content["set-cookie"].asString(); + const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); LL_DEBUGS("MediaAuth") << "cookie = " << cookie << LL_ENDL; + // *TODO: What about bad status codes? Does this destroy previous cookies? LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); // Set cookie for snapshot publishing. @@ -331,16 +332,6 @@ public: LLWebProfile::setAuthCookie(auth_cookie); } - void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - // This is just here to disable the default behavior (attempting to parse the response as llsd). - // We don't care about the content of the response, only the set-cookie header. - } - std::string mHost; }; @@ -1387,10 +1378,12 @@ void LLViewerMedia::removeCookie(const std::string &name, const std::string &dom LLSD LLViewerMedia::getHeaders() { LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - headers["Content-Type"] = "application/xml"; - headers["Cookie"] = sOpenIDCookie; - headers["User-Agent"] = getCurrentUserAgent(); + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; + // *TODO: Should this be 'application/llsd+xml' ? + // *TODO: Should this even be set at all? This header is only not overridden in 'GET' methods. + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML; + headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie; + headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent(); return headers; } @@ -1426,14 +1419,11 @@ void LLViewerMedia::setOpenIDCookie() getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start)); - // *HACK: Doing this here is nasty, find a better way. - LLWebSharing::instance().setOpenIDCookie(sOpenIDCookie); - // Do a web profile get so we can store the cookie LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - headers["Cookie"] = sOpenIDCookie; - headers["User-Agent"] = getCurrentUserAgent(); + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; + headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie; + headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent(); std::string profile_url = getProfileURL(""); LLURL raw_profile_url( profile_url.c_str() ); @@ -1463,9 +1453,9 @@ void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string LLSD headers = LLSD::emptyMap(); // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header - headers["Accept"] = "*/*"; + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" - headers["Content-Type"] = "application/x-www-form-urlencoded"; + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "application/x-www-form-urlencoded"; // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. size_t size = openid_token.size(); @@ -1537,7 +1527,7 @@ void LLViewerMedia::createSpareBrowserMediaSource() // The null owner will keep the browser plugin from fully initializing // (specifically, it keeps LLPluginClassMedia from negotiating a size change, // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) - sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); + sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0); } } @@ -1603,6 +1593,17 @@ void LLViewerMedia::cleanupClass() { gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, NULL); sTeleportFinishConnection.disconnect(); + if (sSpareBrowserMediaSource != NULL) + { + delete sSpareBrowserMediaSource; + sSpareBrowserMediaSource = NULL; + } + + if (sCookieStore != NULL) + { + delete sCookieStore; + sCookieStore = NULL; + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -2648,16 +2649,16 @@ void LLViewerMediaImpl::navigateInternal() // Accept: application/llsd+xml // which is really not what we want. LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; + headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; // Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com - headers["Cookie"] = ""; + headers[HTTP_OUT_HEADER_COOKIE] = ""; LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f); } else if("data" == scheme || "file" == scheme || "about" == scheme) { // FIXME: figure out how to really discover the type for these schemes // We use "data" internally for a text/html url for loading the login screen - if(initializeMedia("text/html")) + if(initializeMedia(HTTP_CONTENT_TEXT_HTML)) { loadURI(); } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 88f1dd14ff..b23e23f32e 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7839,6 +7839,7 @@ void handle_buy_currency_test(void*) LLFloaterReg::showInstance("buy_currency_html", LLSD(url)); } +// SUNSHINE CLEANUP - is only the request update at the end needed now? void handle_rebake_textures(void*) { if (!isAgentAvatarValid()) return; @@ -8225,6 +8226,45 @@ class LLWorldEnvSettings : public view_listener_t } }; +class LLWorldEnableEnvSettings : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool result = false; + std::string tod = userdata.asString(); + + if (tod == "region") + { + return LLEnvManagerNew::instance().getUseRegionSettings(); + } + + if (LLEnvManagerNew::instance().getUseFixedSky()) + { + if (tod == "sunrise") + { + result = (LLEnvManagerNew::instance().getSkyPresetName() == "Sunrise"); + } + else if (tod == "noon") + { + result = (LLEnvManagerNew::instance().getSkyPresetName() == "Midday"); + } + else if (tod == "sunset") + { + result = (LLEnvManagerNew::instance().getSkyPresetName() == "Sunset"); + } + else if (tod == "midnight") + { + result = (LLEnvManagerNew::instance().getSkyPresetName() == "Midnight"); + } + else + { + llwarns << "Unknown item" << llendl; + } + } + return result; + } +}; + class LLWorldEnvPreset : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -8563,6 +8603,7 @@ void initialize_menus() view_listener_t::addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun"); view_listener_t::addMenu(new LLWorldEnvSettings(), "World.EnvSettings"); + view_listener_t::addMenu(new LLWorldEnableEnvSettings(), "World.EnableEnvSettings"); view_listener_t::addMenu(new LLWorldEnvPreset(), "World.EnvPreset"); view_listener_t::addMenu(new LLWorldEnableEnvPreset(), "World.EnableEnvPreset"); view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess"); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 2930c130df..04697f3472 100755 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -494,7 +494,9 @@ class LLFileEnableCloseAllWindows : public view_listener_t { bool handleEvent(const LLSD& userdata) { - bool open_children = gFloaterView->allChildrenClosed() && !LLFloaterSnapshot::getInstance()->isInVisibleChain(); + LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance(); + bool is_floater_snapshot_opened = floater_snapshot && floater_snapshot->isInVisibleChain(); + bool open_children = gFloaterView->allChildrenClosed() && !is_floater_snapshot_opened; return !open_children; } }; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 65afdddd16..0d1ffd2b51 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1010,7 +1010,12 @@ class LLOpenTaskOffer : public LLInventoryAddedObserver protected: /*virtual*/ void done() { - for (uuid_vec_t::iterator it = mAdded.begin(); it != mAdded.end();) + uuid_vec_t added; + for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) + { + added.push_back(*it); + } + for (uuid_vec_t::iterator it = added.begin(); it != added.end();) { const LLUUID& item_uuid = *it; bool was_moved = false; @@ -1032,13 +1037,12 @@ protected: if (was_moved) { - it = mAdded.erase(it); + it = added.erase(it); } else ++it; } - open_inventory_offer(mAdded, ""); - mAdded.clear(); + open_inventory_offer(added, ""); } }; @@ -1047,8 +1051,12 @@ class LLOpenTaskGroupOffer : public LLInventoryAddedObserver protected: /*virtual*/ void done() { - open_inventory_offer(mAdded, "group_offer"); - mAdded.clear(); + uuid_vec_t added; + for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) + { + added.push_back(*it); + } + open_inventory_offer(added, "group_offer"); gInventory.removeObserver(this); delete this; } @@ -3529,6 +3537,12 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } else { + // make sure that we don't have an empty or all-whitespace name + LLStringUtil::trim(from_name); + if (from_name.empty()) + { + from_name = LLTrans::getString("Unnamed"); + } chat.mFromName = from_name; } @@ -3995,6 +4009,8 @@ void process_teleport_finish(LLMessageSystem* msg, void**) gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_teleport_finish(). Seed cap == " + << seedCap << LL_ENDL; regionp->setSeedCapability(seedCap); // Don't send camera updates to the new region until we're @@ -4110,10 +4126,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); - // set the appearance on teleport since the new sim does not - // know what you look like. - gAgent.sendAgentSetAppearance(); - if (isAgentAvatarValid()) { // Set the new position @@ -4237,6 +4249,9 @@ void process_crossed_region(LLMessageSystem* msg, void**) send_complete_agent_movement(sim_host); LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); + + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == " + << seedCap << LL_ENDL; regionp->setSeedCapability(seedCap); } @@ -4664,7 +4679,11 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data) void process_sound_trigger(LLMessageSystem *msg, void **) { - if (!gAudiop) return; + if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + return; + } U64 region_handle = 0; F32 gain = 0; @@ -4724,6 +4743,7 @@ void process_preload_sound(LLMessageSystem *msg, void **user_data) { if (!gAudiop) { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; return; } @@ -4754,9 +4774,9 @@ void process_preload_sound(LLMessageSystem *msg, void **user_data) LLVector3d pos_global = objectp->getPositionGlobal(); if (gAgent.canAccessMaturityAtGlobal(pos_global)) { - // Add audioData starts a transfer internally. - sourcep->addAudioData(datap, FALSE); -} + // Add audioData starts a transfer internally. + sourcep->addAudioData(datap, FALSE); + } } void process_attached_sound(LLMessageSystem *msg, void **user_data) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index db1f9ac11a..7c60be7046 100755 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -56,6 +56,7 @@ #include "llaudiosourcevo.h" #include "llagent.h" #include "llagentcamera.h" +#include "llagentwearables.h" #include "llbbox.h" #include "llbox.h" #include "llcylinder.h" @@ -152,6 +153,7 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco { gAgentAvatarp = new LLVOAvatarSelf(id, pcode, regionp); gAgentAvatarp->initInstance(); + gAgentWearables.setAvatarObject(gAgentAvatarp); } else { @@ -5175,6 +5177,7 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow { if (!gAudiop) { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; return; } @@ -5257,7 +5260,10 @@ LLAudioSource *LLViewerObject::getAudioSource(const LLUUID& owner_id) LLAudioSourceVO *asvop = new LLAudioSourceVO(mID, owner_id, 0.01f, this); mAudioSourcep = asvop; - if(gAudiop) gAudiop->addAudioSource(asvop); + if(gAudiop) + { + gAudiop->addAudioSource(asvop); + } } return mAudioSourcep; @@ -5265,10 +5271,6 @@ LLAudioSource *LLViewerObject::getAudioSource(const LLUUID& owner_id) void LLViewerObject::adjustAudioGain(const F32 gain) { - if (!gAudiop) - { - return; - } if (mAudioSourcep) { mAudioGain = gain; @@ -5502,6 +5504,28 @@ void LLViewerObject::clearDrawableState(U32 state, BOOL recursive) } } +BOOL LLViewerObject::isDrawableState(U32 state, BOOL recursive) const +{ + BOOL matches = FALSE; + if (mDrawable) + { + matches = mDrawable->isState(state); + } + if (recursive) + { + for (child_list_t::const_iterator iter = mChildList.begin(); + (iter != mChildList.end()) && matches; iter++) + { + LLViewerObject* child = *iter; + matches &= child->isDrawableState(state, recursive); + } + } + + return matches; +} + + + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // RN: these functions assume a 2-level hierarchy //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index d92c00a6b2..bab107cc57 100755 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -415,6 +415,7 @@ public: void setDrawableState(U32 state, BOOL recursive = TRUE); void clearDrawableState(U32 state, BOOL recursive = TRUE); + BOOL isDrawableState(U32 state, BOOL recursive = TRUE) const; // Called when the drawable shifts virtual void onShift(const LLVector4a &shift_vector) { } diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 0e40db8504..7f5d2ac125 100755 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -796,6 +796,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) class LLObjectCostResponder : public LLCurl::Responder { + LOG_CLASS(LLObjectCostResponder); public: LLObjectCostResponder(const LLSD& object_ids) : mObjectIDs(object_ids) @@ -816,20 +817,19 @@ public: } } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +private: + /* virtual */ void httpFailure() { - LL_WARNS() - << "Transport error requesting object cost " - << "[status: " << statusNum << "]: " - << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; // TODO*: Error message to user // For now just clear the request from the pending list clear_object_list_pending_requests(); } - void result(const LLSD& content) + /* virtual */ void httpSuccess() { + const LLSD& content = getContent(); if ( !content.isMap() || content.has("error") ) { // Improper response or the request had an error, @@ -885,6 +885,7 @@ private: class LLPhysicsFlagsResponder : public LLCurl::Responder { + LOG_CLASS(LLPhysicsFlagsResponder); public: LLPhysicsFlagsResponder(const LLSD& object_ids) : mObjectIDs(object_ids) @@ -905,20 +906,19 @@ public: } } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +private: + /* virtual */ void httpFailure() { - LL_WARNS() - << "Transport error requesting object physics flags " - << "[status: " << statusNum << "]: " - << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; // TODO*: Error message to user // For now just clear the request from the pending list clear_object_list_pending_requests(); } - void result(const LLSD& content) + /* virtual void */ void httpSuccess() { + const LLSD& content = getContent(); if ( !content.isMap() || content.has("error") ) { // Improper response or the request had an error, diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index b55154f889..37b249dddd 100755 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -99,7 +99,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel) std::string mediaCurrentUrl = std::string( parcel->getMediaCurrentURL()); // if we have a current (link sharing) url, use it instead - if (mediaCurrentUrl != "" && parcel->getMediaType() == "text/html") + if (mediaCurrentUrl != "" && parcel->getMediaType() == HTTP_CONTENT_TEXT_HTML) { mediaUrl = mediaCurrentUrl; } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 1932f4e8ce..f15ebda452 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -30,6 +30,7 @@ // linden libraries #include "indra_constants.h" +#include "llaisapi.h" #include "llavatarnamecache.h" // name lookup cap url #include "llfloaterreg.h" #include "llmath.h" @@ -80,6 +81,11 @@ #pragma warning(disable:4355) #endif +// When we receive a base grant of capabilities that has a different number of +// capabilities than the original base grant received for the region, print +// out the two lists of capabilities for analysis. +//#define DEBUG_CAPS_GRANTS + const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region const S16 MAX_MAP_DIST = 10; // The server only keeps our pending agent info for 60 seconds. @@ -97,6 +103,8 @@ S32 LLViewerRegion::sNewObjectCreationThrottle = -1; typedef std::map<std::string, std::string> CapabilityMap; +static void log_capabilities(const CapabilityMap &capmap); + class LLViewerRegionImpl { public: LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) @@ -164,7 +172,7 @@ public: CapabilityMap mCapabilities; CapabilityMap mSecondCapabilitiesTracker; - + LLEventPoll* mEventPoll; S32 mSeedCapMaxAttempts; @@ -228,24 +236,30 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder { LOG_CLASS(BaseCapabilitiesComplete); public: - BaseCapabilitiesComplete(U64 region_handle, S32 id) + BaseCapabilitiesComplete(U64 region_handle, S32 id) : mRegionHandle(region_handle), mID(id) - { } + { } virtual ~BaseCapabilitiesComplete() { } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) - { - LL_WARNS("AppInit", "Capabilities") << "[status:" << statusNum << ":] " << content << LL_ENDL; + static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) + { + return new BaseCapabilitiesComplete(region_handle, id); + } + +private: + /* virtual */void httpFailure() + { + LL_WARNS("AppInit", "Capabilities") << dumpResponse() << LL_ENDL; LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); if (regionp) { regionp->failedSeedCapability(); } - } + } - void result(const LLSD& content) - { + /* virtual */ void httpSuccess() + { LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); if(!regionp) //region was removed { @@ -259,12 +273,19 @@ public: return ; } + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLSD::map_const_iterator iter; for(iter = content.beginMap(); iter != content.endMap(); ++iter) { regionp->setCapability(iter->first, iter->second); - - LL_DEBUGS("AppInit", "Capabilities") << "got capability for " << iter->first << LL_ENDL; + + LL_DEBUGS("AppInit", "Capabilities") << "got capability for " + << iter->first << LL_ENDL; /* HACK we're waiting for the ServerReleaseNotes */ if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested()) @@ -281,11 +302,6 @@ public: } } - static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) - { - return new BaseCapabilitiesComplete(region_handle, id); - } - private: U64 mRegionHandle; S32 mID; @@ -302,19 +318,32 @@ public: virtual ~BaseCapabilitiesCompleteTracker() { } - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) + static BaseCapabilitiesCompleteTracker* build( U64 region_handle ) + { + return new BaseCapabilitiesCompleteTracker( region_handle ); + } + +private: + /* virtual */ void httpFailure() { - LL_WARNS() << "BaseCapabilitiesCompleteTracker error [status:" - << statusNum << "]: " << content << LL_ENDL; + LL_WARNS() << dumpResponse() << LL_ENDL; } - void result(const LLSD& content) + /* virtual */ void httpSuccess() { LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); if( !regionp ) { + LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; return ; - } + } + + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLSD::map_const_iterator iter; for(iter = content.beginMap(); iter != content.endMap(); ++iter) { @@ -324,32 +353,46 @@ public: if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() ) { - LL_INFOS() << "BaseCapabilitiesCompleteTracker " << "sim " << regionp->getName() - << " sent duplicate seed caps that differs in size - most likely content. " - << (S32) regionp->getRegionImpl()->mCapabilities.size() << " vs " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() - << LL_ENDL; - - //todo#add cap debug versus original check? - /* - CapabilityMap::const_iterator iter = regionp->getRegionImpl()->mCapabilities.begin(); - while (iter!=regionp->getRegionImpl()->mCapabilities.end() ) + LL_WARNS("AppInit", "Capabilities") + << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. " + << "mCapabilities == " << regionp->getRegionImpl()->mCapabilities.size() + << " mSecondCapabilitiesTracker == " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() + << LL_ENDL; +#ifdef DEBUG_CAPS_GRANTS + LL_WARNS("AppInit", "Capabilities") + << "Initial Base capabilities: " << LL_ENDL; + + log_capabilities(regionp->getRegionImpl()->mCapabilities); + + LL_WARNS("AppInit", "Capabilities") + << "Latest base capabilities: " << LL_ENDL; + + log_capabilities(regionp->getRegionImpl()->mSecondCapabilitiesTracker); + +#endif + + if (regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() > regionp->getRegionImpl()->mCapabilities.size() ) { - LL_INFOS() << "BaseCapabilitiesCompleteTracker Original " << iter->first << " " << iter->second<<LL_ENDL; - ++iter; + // *HACK Since we were granted more base capabilities in this grant request than the initial, replace + // the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a + // sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the + // inventory api capability grants. + + // Need to clear a std::map before copying into it because old keys take precedence. + regionp->getRegionImplNC()->mCapabilities.clear(); + regionp->getRegionImplNC()->mCapabilities = regionp->getRegionImpl()->mSecondCapabilitiesTracker; } - */ - regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear(); } - + else + { + LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL; + } + regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear(); } - static BaseCapabilitiesCompleteTracker* build( U64 region_handle ) - { - return new BaseCapabilitiesCompleteTracker( region_handle ); - } private: - U64 mRegionHandle; + U64 mRegionHandle; }; @@ -369,7 +412,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mSimAccess( SIM_ACCESS_MIN ), mBillableFactor(1.0), mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT), - mCentralBakeVersion(0), + mCentralBakeVersion(1), mClassID(0), mCPURatio(0), mColoName("unknown"), @@ -2584,6 +2627,8 @@ void LLViewerRegion::unpackRegionHandshake() msg->nextBlock("RegionInfo"); U32 flags = 0; + flags |= REGION_HANDSHAKE_SUPPORTS_SELF_APPEARANCE; + if(sVOCacheCullingEnabled) { flags |= 0x00000001; //set the bit 0 to be 1 to ask sim to send all cacheable objects. @@ -2616,12 +2661,13 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) //capabilityNames.append("FacebookRedirect"); if (gSavedSettings.getBOOL("UseHTTPInventory")) - { + { capabilityNames.append("FetchLib2"); capabilityNames.append("FetchLibDescendents2"); capabilityNames.append("FetchInventory2"); capabilityNames.append("FetchInventoryDescendents2"); capabilityNames.append("IncrementCOFVersion"); + AISCommand::getCapabilityNames(capabilityNames); } capabilityNames.append("GetDisplayNames"); @@ -2630,13 +2676,14 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("GetObjectCost"); capabilityNames.append("GetObjectPhysicsData"); capabilityNames.append("GetTexture"); + capabilityNames.append("GroupAPIv1"); capabilityNames.append("GroupMemberData"); capabilityNames.append("GroupProposalBallot"); capabilityNames.append("HomeLocation"); capabilityNames.append("LandResources"); capabilityNames.append("MapLayer"); capabilityNames.append("MapLayerGod"); - capabilityNames.append("MeshUploadFlag"); + capabilityNames.append("MeshUploadFlag"); capabilityNames.append("NavMeshGenerationStatus"); capabilityNames.append("NewFileAgentInventory"); capabilityNames.append("ObjectMedia"); @@ -2677,7 +2724,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("ViewerMetrics"); capabilityNames.append("ViewerStartAuction"); capabilityNames.append("ViewerStats"); - + // Please add new capabilities alphabetically to reduce // merge conflicts. } @@ -2685,8 +2732,11 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) void LLViewerRegion::setSeedCapability(const std::string& url) { if (getCapability("Seed") == url) - { - //LL_WARNS() << "Ignoring duplicate seed capability" << LL_ENDL; + { + setCapabilityDebug("Seed", url); + LL_DEBUGS("CrossingCaps") << "Received duplicate seed capability, posting to seed " << + url << LL_ENDL; + //Instead of just returning we build up a second set of seed caps and compare them //to the "original" seed cap received and determine why there is problem! LLSD capabilityNames = LLSD::emptyArray(); @@ -2759,31 +2809,36 @@ class SimulatorFeaturesReceived : public LLHTTPClient::Responder { LOG_CLASS(SimulatorFeaturesReceived); public: - SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, - S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) - : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) - { } - - - void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) - { - LL_WARNS("AppInit", "SimulatorFeatures") << "[status:" << statusNum << "]: " << content << LL_ENDL; + SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, + S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) + : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) + { } + + /* virtual */ void httpFailure() + { + LL_WARNS("AppInit", "SimulatorFeatures") << dumpResponse() << LL_ENDL; retry(); - } + } - void result(const LLSD& content) - { + /* virtual */ void httpSuccess() + { LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); if(!regionp) //region is removed or responder is not created. { - LL_WARNS("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL; + LL_WARNS("AppInit", "SimulatorFeatures") + << "Received results for region that no longer exists!" << LL_ENDL; return ; } - + + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } regionp->setSimulatorFeatures(content); } -private: void retry() { if (mAttempt < mMaxAttempts) @@ -2793,7 +2848,7 @@ private: LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT); } } - + std::string mRetryURL; U64 mRegionHandle; S32 mAttempt; @@ -2830,7 +2885,16 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::string& url) { - mImpl->mSecondCapabilitiesTracker[name] = url; + // Continue to not add certain caps, as we do in setCapability. This is so they match up when we check them later. + if ( ! ( name == "EventQueueGet" || name == "UntrustedSimulatorMessage" || name == "SimulatorFeatures" ) ) + { + mImpl->mSecondCapabilitiesTracker[name] = url; + if(name == "GetTexture") + { + mHttpUrl = url ; + } + } + } bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) @@ -2842,7 +2906,7 @@ std::string LLViewerRegion::getCapability(const std::string& name) const { if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) { - LL_WARNS() << "getCapability called before caps received" << LL_ENDL; + LL_WARNS() << "getCapability called before caps received for " << name << LL_ENDL; } CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); @@ -2854,6 +2918,22 @@ std::string LLViewerRegion::getCapability(const std::string& name) const return iter->second; } +bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const +{ + if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) + { + LL_WARNS() << "isCapabilityAvailable called before caps received for " << name << LL_ENDL; + } + + CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); + if(iter == mImpl->mCapabilities.end()) + { + return false; + } + + return true; +} + bool LLViewerRegion::capabilitiesReceived() const { return mCapabilitiesReceived; @@ -2881,16 +2961,7 @@ boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(cons void LLViewerRegion::logActiveCapabilities() const { - int count = 0; - CapabilityMap::const_iterator iter; - for (iter = mImpl->mCapabilities.begin(); iter != mImpl->mCapabilities.end(); ++iter, ++count) - { - if (!iter->second.empty()) - { - LL_INFOS() << iter->first << " URL is " << iter->second << LL_ENDL; - } - } - LL_INFOS() << "Dumped " << count << " entries." << LL_ENDL; + log_capabilities(mImpl->mCapabilities); } LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) @@ -2982,7 +3053,21 @@ bool LLViewerRegion::dynamicPathfindingEnabled() const return ( mSimulatorFeatures.has("DynamicPathfindingEnabled") && mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean()); } +/* Static Functions */ +void log_capabilities(const CapabilityMap &capmap) +{ + S32 count = 0; + CapabilityMap::const_iterator iter; + for (iter = capmap.begin(); iter != capmap.end(); ++iter, ++count) + { + if (!iter->second.empty()) + { + LL_INFOS() << "log_capabilities: " << iter->first << " URL is " << iter->second << LL_ENDL; + } + } + LL_INFOS() << "log_capabilities: Dumped " << count << " entries." << LL_ENDL; +} void LLViewerRegion::resetMaterialsCapThrottle() { F32 requests_per_sec = 1.0f; // original default; @@ -3027,3 +3112,4 @@ U32 LLViewerRegion::getMaxMaterialsPerTransaction() const } + diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 7f6a8186a5..1e225553b8 100755 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -48,6 +48,8 @@ #define WATER 2 const U32 MAX_OBJECT_CACHE_ENTRIES = 50000; +// Region handshake flags +const U32 REGION_HANDSHAKE_SUPPORTS_SELF_APPEARANCE = 1U << 2; class LLEventPoll; class LLVLComposition; @@ -117,7 +119,7 @@ public: void setAllowSetHome(BOOL b) { setRegionFlag(REGION_FLAGS_ALLOW_SET_HOME, b); } void setResetHomeOnTeleport(BOOL b) { setRegionFlag(REGION_FLAGS_RESET_HOME_ON_TELEPORT, b); } void setSunFixed(BOOL b) { setRegionFlag(REGION_FLAGS_SUN_FIXED, b); } - void setBlockFly(BOOL b) { setRegionFlag(REGION_FLAGS_BLOCK_FLY, b); } + //void setBlockFly(BOOL b) { setRegionFlag(REGION_FLAGS_BLOCK_FLY, b); } Never used void setAllowDirectTeleport(BOOL b) { setRegionFlag(REGION_FLAGS_ALLOW_DIRECT_TELEPORT, b); } @@ -255,6 +257,7 @@ public: S32 getNumSeedCapRetries(); void setCapability(const std::string& name, const std::string& url); void setCapabilityDebug(const std::string& name, const std::string& url); + bool isCapabilityAvailable(const std::string& name) const; // implements LLCapabilityProvider virtual std::string getCapability(const std::string& name) const; diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 9d2a4a50e1..dafe2cafec 100755 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -355,6 +355,16 @@ LLViewerShaderMgr * LLViewerShaderMgr::instance() return static_cast<LLViewerShaderMgr*>(sInstance); } +// static +void LLViewerShaderMgr::releaseInstance() +{ + if (sInstance != NULL) + { + delete sInstance; + sInstance = NULL; + } +} + void LLViewerShaderMgr::initAttribsAndUniforms(void) { if (mReservedAttribs.empty()) diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 42147fdd29..923aa522ad 100755 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -43,6 +43,7 @@ public: // singleton pattern implementation static LLViewerShaderMgr * instance(); + static void releaseInstance(); void initAttribsAndUniforms(void); void setShaders(); diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index d5ae2d1030..f60829e9e8 100755 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -412,18 +412,19 @@ void update_statistics() class ViewerStatsResponder : public LLHTTPClient::Responder { + LOG_CLASS(ViewerStatsResponder); public: - ViewerStatsResponder() { } + ViewerStatsResponder() { } - void error(U32 statusNum, const std::string& reason) - { - LL_INFOS() << "ViewerStatsResponder::error " << statusNum << " " - << reason << LL_ENDL; - } +private: + /* virtual */ void httpFailure() + { + LL_WARNS() << dumpResponse() << LL_ENDL; + } - void result(const LLSD& content) - { - LL_INFOS() << "ViewerStatsResponder::result" << LL_ENDL; + /* virtual */ void httpSuccess() + { + LL_INFOS() << "OK" << LL_ENDL; } }; @@ -622,44 +623,28 @@ void send_stats() LLViewerStats::instance().getRecording().resume(); } -LLFrameTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name) +LLTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name) { phase_map_t::iterator iter = mPhaseMap.find(phase_name); if (iter == mPhaseMap.end()) { - LLFrameTimer timer; + LLTimer timer; mPhaseMap[phase_name] = timer; } - LLFrameTimer& timer = mPhaseMap[phase_name]; + LLTimer& timer = mPhaseMap[phase_name]; return timer; } void LLViewerStats::PhaseMap::startPhase(const std::string& phase_name) { - LLFrameTimer& timer = getPhaseTimer(phase_name); - LL_DEBUGS() << "startPhase " << phase_name << LL_ENDL; - timer.unpause(); -} - -void LLViewerStats::PhaseMap::stopAllPhases() -{ - for (phase_map_t::iterator iter = mPhaseMap.begin(); - iter != mPhaseMap.end(); ++iter) - { - const std::string& phase_name = iter->first; - if (iter->second.getStarted()) - { - // Going from started to paused state - record stats. - recordPhaseStat(phase_name,iter->second.getElapsedTimeF32()); - } - LL_DEBUGS() << "stopPhase (all) " << phase_name << LL_ENDL; - iter->second.pause(); - } + LLTimer& timer = getPhaseTimer(phase_name); + timer.start(); + //LL_DEBUGS("Avatar") << "startPhase " << phase_name << LL_ENDL; } void LLViewerStats::PhaseMap::clearPhases() { - LL_DEBUGS() << "clearPhases" << LL_ENDL; + //LL_DEBUGS("Avatar") << "clearPhases" << LL_ENDL; mPhaseMap.clear(); } @@ -684,7 +669,6 @@ LLViewerStats::PhaseMap::PhaseMap() { } - void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name) { phase_map_t::iterator iter = mPhaseMap.find(phase_name); @@ -697,6 +681,7 @@ void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name) } } } + // static LLViewerStats::StatsAccumulator& LLViewerStats::PhaseMap::getPhaseStats(const std::string& phase_name) { @@ -720,14 +705,18 @@ void LLViewerStats::PhaseMap::recordPhaseStat(const std::string& phase_name, F32 bool LLViewerStats::PhaseMap::getPhaseValues(const std::string& phase_name, F32& elapsed, bool& completed) { phase_map_t::iterator iter = mPhaseMap.find(phase_name); + bool found = false; if (iter != mPhaseMap.end()) { + found = true; elapsed = iter->second.getElapsedTimeF32(); completed = !iter->second.getStarted(); - return true; + //LL_DEBUGS("Avatar") << " phase_name " << phase_name << " elapsed " << elapsed << " completed " << completed << " timer addr " << (S32)(&iter->second) << LL_ENDL; } else { - return false; + //LL_DEBUGS("Avatar") << " phase_name " << phase_name << " NOT FOUND" << LL_ENDL; } + + return found; } diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 0d959ed034..7843652589 100755 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -342,7 +342,7 @@ public: // Phase tracking (originally put in for avatar rezzing), tracking // progress of active/completed phases for activities like outfit changing. - typedef std::map<std::string,LLFrameTimer> phase_map_t; + typedef std::map<std::string,LLTimer> phase_map_t; typedef std::map<std::string,StatsAccumulator> phase_stats_t; class PhaseMap { @@ -351,11 +351,10 @@ public: static phase_stats_t sStats; public: PhaseMap(); - LLFrameTimer& getPhaseTimer(const std::string& phase_name); + LLTimer& getPhaseTimer(const std::string& phase_name); bool getPhaseValues(const std::string& phase_name, F32& elapsed, bool& completed); void startPhase(const std::string& phase_name); void stopPhase(const std::string& phase_name); - void stopAllPhases(); void clearPhases(); LLSD asLLSD(); static StatsAccumulator& getPhaseStats(const std::string& phase_name); diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp index 62e8da81ec..65ba3fb6e5 100755 --- a/indra/newview/llviewertexlayer.cpp +++ b/indra/newview/llviewertexlayer.cpp @@ -37,7 +37,6 @@ #include "llglslshader.h" #include "llvoavatarself.h" #include "pipeline.h" -#include "llassetuploadresponders.h" #include "llviewercontrol.h" static const S32 BAKE_UPLOAD_ATTEMPTS = 7; @@ -46,22 +45,6 @@ static const F32 BAKE_UPLOAD_RETRY_DELAY = 2.f; // actual delay grows by power o // runway consolidate extern std::string self_av_string(); - -//----------------------------------------------------------------------------- -// LLBakedUploadData() -//----------------------------------------------------------------------------- -LLBakedUploadData::LLBakedUploadData(const LLVOAvatarSelf* avatar, - LLViewerTexLayerSet* layerset, - const LLUUID& id, - bool highest_res) : - mAvatar(avatar), - mTexLayerSet(layerset), - mID(id), - mStartTime(LLFrameTimer::getTotalTime()), // Record starting time - mIsHighestRes(highest_res) -{ -} - //----------------------------------------------------------------------------- // LLViewerTexLayerSetBuffer // The composite image that a LLViewerTexLayerSet writes to. Each LLViewerTexLayerSet has one. @@ -75,15 +58,10 @@ LLViewerTexLayerSetBuffer::LLViewerTexLayerSetBuffer(LLTexLayerSet* const owner, // ORDER_LAST => must render these after the hints are created. LLTexLayerSetBuffer(owner), LLViewerDynamicTexture( width, height, 4, LLViewerDynamicTexture::ORDER_LAST, TRUE ), - mUploadPending(FALSE), // Not used for any logic here, just to sync sending of updates - mNeedsUpload(FALSE), - mNumLowresUploads(0), - mUploadFailCount(0), mNeedsUpdate(TRUE), mNumLowresUpdates(0) { LLViewerTexLayerSetBuffer::sGLByteCount += getSize(); - mNeedsUploadTimer.start(); mNeedsUpdateTimer.start(); } @@ -126,33 +104,6 @@ void LLViewerTexLayerSetBuffer::requestUpdate() restartUpdateTimer(); mNeedsUpdate = TRUE; mNumLowresUpdates = 0; - // If we're in the middle of uploading a baked texture, we don't care about it any more. - // When it's downloaded, ignore it. - mUploadID.setNull(); -} - -void LLViewerTexLayerSetBuffer::requestUpload() -{ - conditionalRestartUploadTimer(); - mNeedsUpload = TRUE; - mNumLowresUploads = 0; - mUploadPending = TRUE; -} - -void LLViewerTexLayerSetBuffer::conditionalRestartUploadTimer() -{ - // If we requested a new upload but haven't even uploaded - // a low res version of our last upload request, then - // keep the timer ticking instead of resetting it. - if (mNeedsUpload && (mNumLowresUploads == 0)) - { - mNeedsUploadTimer.unpause(); - } - else - { - mNeedsUploadTimer.reset(); - mNeedsUploadTimer.start(); - } } void LLViewerTexLayerSetBuffer::restartUpdateTimer() @@ -161,25 +112,16 @@ void LLViewerTexLayerSetBuffer::restartUpdateTimer() mNeedsUpdateTimer.start(); } -void LLViewerTexLayerSetBuffer::cancelUpload() -{ - mNeedsUpload = FALSE; - mUploadPending = FALSE; - mNeedsUploadTimer.pause(); - mUploadRetryTimer.reset(); -} - // virtual BOOL LLViewerTexLayerSetBuffer::needsRender() { llassert(mTexLayerSet->getAvatarAppearance() == gAgentAvatarp); if (!isAgentAvatarValid()) return FALSE; - const BOOL upload_now = mNeedsUpload && isReadyToUpload(); const BOOL update_now = mNeedsUpdate && isReadyToUpdate(); - // Don't render if we don't want to (or aren't ready to) upload or update. - if (!(update_now || upload_now)) + // Don't render if we don't want to (or aren't ready to) update. + if (!update_now) { return FALSE; } @@ -190,11 +132,10 @@ BOOL LLViewerTexLayerSetBuffer::needsRender() return FALSE; } - // Don't render if we are trying to create a shirt texture but aren't wearing a skirt. + // Don't render if we are trying to create a skirt texture but aren't wearing a skirt. if (gAgentAvatarp->getBakedTE(getViewerTexLayerSet()) == LLAvatarAppearanceDefines::TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT)) { - cancelUpload(); return FALSE; } @@ -222,36 +163,7 @@ void LLViewerTexLayerSetBuffer::postRenderTexLayerSet(BOOL success) // virtual void LLViewerTexLayerSetBuffer::midRenderTexLayerSet(BOOL success) { - // do we need to upload, and do we have sufficient data to create an uploadable composite? - // TODO: When do we upload the texture if gAgent.mNumPendingQueries is non-zero? - const BOOL upload_now = mNeedsUpload && isReadyToUpload(); const BOOL update_now = mNeedsUpdate && isReadyToUpdate(); - - if(upload_now) - { - if (!success) - { - LL_INFOS() << "Failed attempt to bake " << mTexLayerSet->getBodyRegionName() << LL_ENDL; - mUploadPending = FALSE; - } - else - { - LLViewerTexLayerSet* layer_set = getViewerTexLayerSet(); - if (layer_set->isVisible()) - { - layer_set->getAvatar()->debugBakedTextureUpload(layer_set->getBakedTexIndex(), FALSE); // FALSE for start of upload, TRUE for finish. - doUpload(); - } - else - { - mUploadPending = FALSE; - mNeedsUpload = FALSE; - mNeedsUploadTimer.pause(); - layer_set->getAvatar()->setNewBakedTexture(layer_set->getBakedTexIndex(),IMG_INVISIBLE); - } - } - } - if (update_now) { doUpdate(); @@ -267,60 +179,6 @@ BOOL LLViewerTexLayerSetBuffer::isInitialized(void) const return mGLTexturep.notNull() && mGLTexturep->isGLTextureCreated(); } -BOOL LLViewerTexLayerSetBuffer::uploadPending() const -{ - return mUploadPending; -} - -BOOL LLViewerTexLayerSetBuffer::uploadNeeded() const -{ - return mNeedsUpload; -} - -BOOL LLViewerTexLayerSetBuffer::uploadInProgress() const -{ - return !mUploadID.isNull(); -} - -BOOL LLViewerTexLayerSetBuffer::isReadyToUpload() const -{ - if (!gAgentQueryManager.hasNoPendingQueries()) return FALSE; // Can't upload if there are pending queries. - if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance()) return FALSE; // Don't upload if avatar is being edited. - - BOOL ready = FALSE; - if (getViewerTexLayerSet()->isLocalTextureDataFinal()) - { - // If we requested an upload and have the final LOD ready, upload (or wait a while if this is a retry) - if (mUploadFailCount == 0) - { - ready = TRUE; - } - else - { - ready = mUploadRetryTimer.getElapsedTimeF32() >= BAKE_UPLOAD_RETRY_DELAY * (1 << (mUploadFailCount - 1)); - } - } - else - { - // Upload if we've hit a timeout. Upload is a pretty expensive process so we need to make sure - // we aren't doing uploads too frequently. - const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureUploadTimeout"); - if (texture_timeout != 0) - { - // The timeout period increases exponentially between every lowres upload in order to prevent - // spamming the server with frequent uploads. - const U32 texture_timeout_threshold = texture_timeout*(1 << mNumLowresUploads); - - // If we hit our timeout and have textures available at even lower resolution, then upload. - const BOOL is_upload_textures_timeout = mNeedsUploadTimer.getElapsedTimeF32() >= texture_timeout_threshold; - const BOOL has_lower_lod = getViewerTexLayerSet()->isLocalTextureDataAvailable(); - ready = has_lower_lod && is_upload_textures_timeout; - } - } - - return ready; -} - BOOL LLViewerTexLayerSetBuffer::isReadyToUpdate() const { // If we requested an update and have the final LOD ready, then update. @@ -358,159 +216,6 @@ BOOL LLViewerTexLayerSetBuffer::requestUpdateImmediate() return result; } -// Create the baked texture, send it out to the server, then wait for it to come -// back so we can switch to using it. -void LLViewerTexLayerSetBuffer::doUpload() -{ - LLViewerTexLayerSet* layer_set = getViewerTexLayerSet(); - LL_DEBUGS("Avatar") << "Uploading baked " << layer_set->getBodyRegionName() << LL_ENDL; - add(LLStatViewer::TEX_BAKES, 1); - - // Don't need caches since we're baked now. (note: we won't *really* be baked - // until this image is sent to the server and the Avatar Appearance message is received.) - layer_set->deleteCaches(); - - // Get the COLOR information from our texture - U8* baked_color_data = new U8[ mFullWidth * mFullHeight * 4 ]; - glReadPixels(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data ); - stop_glerror(); - - // Get the MASK information from our texture - LLGLSUIDefault gls_ui; - LLPointer<LLImageRaw> baked_mask_image = new LLImageRaw(mFullWidth, mFullHeight, 1 ); - U8* baked_mask_data = baked_mask_image->getData(); - layer_set->gatherMorphMaskAlpha(baked_mask_data, - mOrigin.mX, mOrigin.mY, - mFullWidth, mFullHeight); - - - // Create the baked image from our color and mask information - const S32 baked_image_components = 5; // red green blue [bump] clothing - LLPointer<LLImageRaw> baked_image = new LLImageRaw( mFullWidth, mFullHeight, baked_image_components ); - U8* baked_image_data = baked_image->getData(); - S32 i = 0; - for (S32 u=0; u < mFullWidth; u++) - { - for (S32 v=0; v < mFullHeight; v++) - { - baked_image_data[5*i + 0] = baked_color_data[4*i + 0]; - baked_image_data[5*i + 1] = baked_color_data[4*i + 1]; - baked_image_data[5*i + 2] = baked_color_data[4*i + 2]; - baked_image_data[5*i + 3] = baked_color_data[4*i + 3]; // alpha should be correct for eyelashes. - baked_image_data[5*i + 4] = baked_mask_data[i]; - i++; - } - } - - LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C; - const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask) - if (compressedImage->encode(baked_image, comment_text)) - { - LLTransactionID tid; - tid.generate(); - const LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - if (LLVFile::writeFile(compressedImage->getData(), compressedImage->getDataSize(), - gVFS, asset_id, LLAssetType::AT_TEXTURE)) - { - // Read back the file and validate. - BOOL valid = FALSE; - LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C; - S32 file_size = 0; - LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE); - file_size = file.getSize(); - U8* data = integrity_test->allocateData(file_size); - file.read(data, file_size); - if (data) - { - valid = integrity_test->validate(data, file_size); // integrity_test will delete 'data' - } - else - { - integrity_test->setLastError("Unable to read entire file"); - } - - if (valid) - { - const bool highest_lod = layer_set->isLocalTextureDataFinal(); - // Baked_upload_data is owned by the responder and deleted after the request completes. - LLBakedUploadData* baked_upload_data = new LLBakedUploadData(gAgentAvatarp, - layer_set, - asset_id, - highest_lod); - // upload ID is used to avoid overlaps, e.g. when the user rapidly makes two changes outside of Face Edit. - mUploadID = asset_id; - - // Upload the image - const std::string url = gAgent.getRegion()->getCapability("UploadBakedTexture"); - if(!url.empty() - && !LLPipeline::sForceOldBakedUpload // toggle debug setting UploadBakedTexOld to change between the new caps method and old method - && (mUploadFailCount < (BAKE_UPLOAD_ATTEMPTS - 1))) // Try last ditch attempt via asset store if cap upload is failing. - { - LLSD body = LLSD::emptyMap(); - // The responder will call LLViewerTexLayerSetBuffer::onTextureUploadComplete() - LLHTTPClient::post(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data)); - LL_INFOS() << "Baked texture upload via capability of " << mUploadID << " to " << url << LL_ENDL; - } - else - { - gAssetStorage->storeAssetData(tid, - LLAssetType::AT_TEXTURE, - LLViewerTexLayerSetBuffer::onTextureUploadComplete, - baked_upload_data, - TRUE, // temp_file - TRUE, // is_priority - TRUE); // store_local - LL_INFOS() << "Baked texture upload via Asset Store." << LL_ENDL; - } - - if (highest_lod) - { - // Sending the final LOD for the baked texture. All done, pause - // the upload timer so we know how long it took. - mNeedsUpload = FALSE; - mNeedsUploadTimer.pause(); - } - else - { - // Sending a lower level LOD for the baked texture. Restart the upload timer. - mNumLowresUploads++; - mNeedsUploadTimer.unpause(); - mNeedsUploadTimer.reset(); - } - - // Print out notification that we uploaded this texture. - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) - { - const std::string lod_str = highest_lod ? "HighRes" : "LowRes"; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)layer_set->getAvatar()->debugGetExistenceTimeElapsedF32()); - args["TIME"] = llformat("%d",(U32)mNeedsUploadTimer.getElapsedTimeF32()); - args["BODYREGION"] = layer_set->getBodyRegionName(); - args["RESOLUTION"] = lod_str; - LLNotificationsUtil::add("AvatarRezSelfBakedTextureUploadNotification",args); - LL_DEBUGS("Avatar") << self_av_string() << "Uploading [ name: " << layer_set->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << LL_ENDL; - } - } - else - { - // The read back and validate operation failed. Remove the uploaded file. - mUploadPending = FALSE; - LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE, LLVFile::WRITE); - file.remove(); - LL_INFOS() << "Unable to create baked upload file (reason: corrupted)." << LL_ENDL; - } - } - } - else - { - // The VFS write file operation failed. - mUploadPending = FALSE; - LL_INFOS() << "Unable to create baked upload file (reason: failed to write file)" << LL_ENDL; - } - - delete [] baked_color_data; -} - // Mostly bookkeeping; don't need to actually "do" anything since // render() will actually do the update. void LLViewerTexLayerSetBuffer::doUpdate() @@ -547,82 +252,6 @@ void LLViewerTexLayerSetBuffer::doUpdate() } } -// static -void LLViewerTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, - void* userdata, - S32 result, - LLExtStat ext_status) // StoreAssetData callback (not fixed) -{ - LLBakedUploadData* baked_upload_data = (LLBakedUploadData*)userdata; - - if (isAgentAvatarValid() && - !gAgentAvatarp->isDead() && - (baked_upload_data->mAvatar == gAgentAvatarp) && // Sanity check: only the user's avatar should be uploading textures. - (baked_upload_data->mTexLayerSet->hasComposite())) - { - LLViewerTexLayerSetBuffer* layerset_buffer = baked_upload_data->mTexLayerSet->getViewerComposite(); - S32 failures = layerset_buffer->mUploadFailCount; - layerset_buffer->mUploadFailCount = 0; - - if (layerset_buffer->mUploadID.isNull()) - { - // The upload got canceled, we should be in the - // process of baking a new texture so request an - // upload with the new data - - // BAP: does this really belong in this callback, as - // opposed to where the cancellation takes place? - // suspect this does nothing. - layerset_buffer->requestUpload(); - } - else if (baked_upload_data->mID == layerset_buffer->mUploadID) - { - // This is the upload we're currently waiting for. - layerset_buffer->mUploadID.setNull(); - const std::string name(baked_upload_data->mTexLayerSet->getBodyRegionName()); - const std::string resolution = baked_upload_data->mIsHighestRes ? " full res " : " low res "; - if (result >= 0) - { - layerset_buffer->mUploadPending = FALSE; // Allows sending of AgentSetAppearance later - LLAvatarAppearanceDefines::ETextureIndex baked_te = gAgentAvatarp->getBakedTE(layerset_buffer->getViewerTexLayerSet()); - // Update baked texture info with the new UUID - U64 now = LLFrameTimer::getTotalTime(); // Record starting time - LL_INFOS() << "Baked" << resolution << "texture upload for " << name << " took " << (S32)((now - baked_upload_data->mStartTime) / 1000) << " ms" << LL_ENDL; - gAgentAvatarp->setNewBakedTexture(baked_te, uuid); - } - else - { - ++failures; - S32 max_attempts = baked_upload_data->mIsHighestRes ? BAKE_UPLOAD_ATTEMPTS : 1; // only retry final bakes - LL_WARNS() << "Baked" << resolution << "texture upload for " << name << " failed (attempt " << failures << "/" << max_attempts << ")" << LL_ENDL; - if (failures < max_attempts) - { - layerset_buffer->mUploadFailCount = failures; - layerset_buffer->mUploadRetryTimer.start(); - layerset_buffer->requestUpload(); - } - } - } - else - { - LL_INFOS() << "Received baked texture out of date, ignored." << LL_ENDL; - } - - gAgentAvatarp->dirtyMesh(); - } - else - { - // Baked texture failed to upload (in which case since we - // didn't set the new baked texture, it means that they'll try - // and rebake it at some point in the future (after login?)), - // or this response to upload is out of date, in which case a - // current response should be on the way or already processed. - LL_WARNS() << "Baked upload failed" << LL_ENDL; - } - - delete baked_upload_data; -} - //----------------------------------------------------------------------------- // LLViewerTexLayerSet // An ordered set of texture layers that get composited into a single texture. @@ -664,20 +293,6 @@ void LLViewerTexLayerSet::requestUpdate() } } -void LLViewerTexLayerSet::requestUpload() -{ - createComposite(); - getViewerComposite()->requestUpload(); -} - -void LLViewerTexLayerSet::cancelUpload() -{ - if(mComposite) - { - getViewerComposite()->cancelUpload(); - } -} - void LLViewerTexLayerSet::updateComposite() { createComposite(); @@ -730,19 +345,12 @@ const std::string LLViewerTexLayerSetBuffer::dumpTextureInfo() const { if (!isAgentAvatarValid()) return ""; - const BOOL is_high_res = !mNeedsUpload; - const U32 num_low_res = mNumLowresUploads; - const U32 upload_time = (U32)mNeedsUploadTimer.getElapsedTimeF32(); + const BOOL is_high_res = TRUE; + const U32 num_low_res = 0; const std::string local_texture_info = gAgentAvatarp->debugDumpLocalTextureDataInfo(getViewerTexLayerSet()); - std::string status = "CREATING "; - if (!uploadNeeded()) status = "DONE "; - if (uploadInProgress()) status = "UPLOADING"; - - std::string text = llformat("[%s] [HiRes:%d LoRes:%d] [Elapsed:%d] %s", - status.c_str(), + std::string text = llformat("[HiRes:%d LoRes:%d] %s", is_high_res, num_low_res, - upload_time, local_texture_info.c_str()); return text; } diff --git a/indra/newview/llviewertexlayer.h b/indra/newview/llviewertexlayer.h index 959c883da8..027ae255ec 100644..100755 --- a/indra/newview/llviewertexlayer.h +++ b/indra/newview/llviewertexlayer.h @@ -47,8 +47,6 @@ public: virtual ~LLViewerTexLayerSet(); /*virtual*/void requestUpdate(); - void requestUpload(); - void cancelUpload(); BOOL isLocalTextureDataAvailable() const; BOOL isLocalTextureDataFinal() const; void updateComposite(); @@ -116,31 +114,6 @@ protected: virtual BOOL render() { return renderTexLayerSet(); } //-------------------------------------------------------------------- - // Uploads - //-------------------------------------------------------------------- -public: - void requestUpload(); - void cancelUpload(); - BOOL uploadNeeded() const; // We need to upload a new texture - BOOL uploadInProgress() const; // We have started uploading a new texture and are awaiting the result - BOOL uploadPending() const; // We are expecting a new texture to be uploaded at some point - static void onTextureUploadComplete(const LLUUID& uuid, - void* userdata, - S32 result, LLExtStat ext_status); -protected: - BOOL isReadyToUpload() const; - void doUpload(); // Does a read back and upload. - void conditionalRestartUploadTimer(); -private: - BOOL mNeedsUpload; // Whether we need to send our baked textures to the server - U32 mNumLowresUploads; // Number of times we've sent a lowres version of our baked textures to the server - BOOL mUploadPending; // Whether we have received back the new baked textures - LLUUID mUploadID; // The current upload process (null if none). - LLFrameTimer mNeedsUploadTimer; // Tracks time since upload was requested and performed. - S32 mUploadFailCount; // Number of consecutive upload failures - LLFrameTimer mUploadRetryTimer; // Tracks time since last upload failure. - - //-------------------------------------------------------------------- // Updates //-------------------------------------------------------------------- public: @@ -156,25 +129,5 @@ private: LLFrameTimer mNeedsUpdateTimer; // Tracks time since update was requested and performed. }; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// LLBakedUploadData -// -// Used by LLTexLayerSetBuffer for a callback. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -struct LLBakedUploadData -{ - LLBakedUploadData(const LLVOAvatarSelf* avatar, - LLViewerTexLayerSet* layerset, - const LLUUID& id, - bool highest_res); - ~LLBakedUploadData() {} - const LLUUID mID; - const LLVOAvatarSelf* mAvatar; // note: backlink only; don't LLPointer - LLViewerTexLayerSet* mTexLayerSet; - const U64 mStartTime; // for measuring baked texture upload time - const bool mIsHighestRes; // whether this is a "final" bake, or intermediate low res -}; - #endif // LL_VIEWER_TEXLAYER_H diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 69f9bbdff8..0c4f55d704 100755 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -542,8 +542,8 @@ LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const case LLAssetType::AT_BODYPART: img_name = "Inv_Skin"; break; case LLAssetType::AT_ANIMATION: img_name = "Inv_Animation"; break; case LLAssetType::AT_GESTURE: img_name = "Inv_Gesture"; break; - case LLAssetType::AT_MESH: img_name = "Inv_Mesh"; break; - default: llassert(0); + case LLAssetType::AT_MESH: img_name = "Inv_Mesh"; break; + default: img_name = "Inv_Invalid"; break; // use the Inv_Invalid icon for undefined object types (see MAINT-3981) } return LLUI::getUIImage(img_name); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 3be82a5531..ba89aafc84 100755 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -961,6 +961,27 @@ void LLViewerTexture::updateBindStatsForTester() //end of LLViewerTexture //---------------------------------------------------------------------------------------------- +const std::string& fttype_to_string(const FTType& fttype) +{ + static const std::string ftt_unknown("FTT_UNKNOWN"); + static const std::string ftt_default("FTT_DEFAULT"); + static const std::string ftt_server_bake("FTT_SERVER_BAKE"); + static const std::string ftt_host_bake("FTT_HOST_BAKE"); + static const std::string ftt_map_tile("FTT_MAP_TILE"); + static const std::string ftt_local_file("FTT_LOCAL_FILE"); + static const std::string ftt_error("FTT_ERROR"); + switch(fttype) + { + case FTT_UNKNOWN: return ftt_unknown; break; + case FTT_DEFAULT: return ftt_default; break; + case FTT_SERVER_BAKE: return ftt_server_bake; break; + case FTT_HOST_BAKE: return ftt_host_bake; break; + case FTT_MAP_TILE: return ftt_map_tile; break; + case FTT_LOCAL_FILE: return ftt_local_file; break; + } + return ftt_error; +} + //---------------------------------------------------------------------------------------------- //start of LLViewerFetchedTexture //---------------------------------------------------------------------------------------------- @@ -973,7 +994,7 @@ LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, FTType f_type, mFTType = f_type; if (mFTType == FTT_HOST_BAKE) { - mCanUseHTTP = false; + LL_WARNS() << "Unsupported fetch type " << mFTType << LL_ENDL; } generateGLTexture(); } @@ -998,6 +1019,7 @@ void LLViewerFetchedTexture::init(bool firstinit) { mOrigWidth = 0; mOrigHeight = 0; + mHasAux = FALSE; mNeedsAux = FALSE; mRequestedDiscardLevel = -1; mRequestedDownloadPriority = 0.f; @@ -1054,7 +1076,7 @@ void LLViewerFetchedTexture::init(bool firstinit) mLastReferencedSavedRawImageTime = 0.0f; mKeptSavedRawImageTime = 0.f; mLastCallBackActiveTime = 0.f; - + mForceCallbackFetch = FALSE; mInDebug = FALSE; mFTType = FTT_UNKNOWN; @@ -1836,9 +1858,14 @@ bool LLViewerFetchedTexture::updateFetch() if (mRawImage.notNull()) sRawCount--; if (mAuxRawImage.notNull()) sAuxCount--; - bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage); + bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage, + mLastHttpGetStatus); if (mRawImage.notNull()) sRawCount++; - if (mAuxRawImage.notNull()) sAuxCount++; + if (mAuxRawImage.notNull()) + { + mHasAux = TRUE; + sAuxCount++; + } if (finished) { mIsFetching = FALSE; @@ -1899,20 +1926,34 @@ bool LLViewerFetchedTexture::updateFetch() if ((decode_priority > 0) && (mRawDiscardLevel < 0 || mRawDiscardLevel == INVALID_DISCARD_LEVEL)) { // We finished but received no data - if (current_discard < 0) + if (getDiscardLevel() < 0) { - LL_WARNS() << "!mIsFetching, setting as missing, decode_priority " << decode_priority - << " mRawDiscardLevel " << mRawDiscardLevel - << " current_discard " << current_discard - << LL_ENDL; + if (getFTType() != FTT_MAP_TILE) + { + LL_WARNS() << mID + << " Fetch failure, setting as missing, decode_priority " << decode_priority + << " mRawDiscardLevel " << mRawDiscardLevel + << " current_discard " << current_discard + << " stats " << mLastHttpGetStatus.toHex() + << LL_ENDL; + } setIsMissingAsset(); desired_discard = -1; } else { //LL_WARNS() << mID << ": Setting min discard to " << current_discard << LL_ENDL; - mMinDiscardLevel = current_discard; - desired_discard = current_discard; + if(current_discard >= 0) + { + mMinDiscardLevel = current_discard; + desired_discard = current_discard; + } + else + { + S32 dis_level = getDiscardLevel(); + mMinDiscardLevel = dis_level; + desired_discard = dis_level; + } } destroyRawImage(); } @@ -2083,29 +2124,43 @@ void LLViewerFetchedTexture::forceToDeleteRequest() mDesiredDiscardLevel = getMaxDiscardLevel() + 1; } -void LLViewerFetchedTexture::setIsMissingAsset() +void LLViewerFetchedTexture::setIsMissingAsset(BOOL is_missing) { - if (mUrl.empty()) + if (is_missing == mIsMissingAsset) { - LL_WARNS() << mID << ": Marking image as missing" << LL_ENDL; + return; } - else + if (is_missing) { - // This may or may not be an error - it is normal to have no - // map tile on an empty region, but bad if we're failing on a - // server bake texture. - LL_WARNS() << mUrl << ": Marking image as missing" << LL_ENDL; + if (mUrl.empty()) + { + LL_WARNS() << mID << ": Marking image as missing" << LL_ENDL; + } + else + { + // This may or may not be an error - it is normal to have no + // map tile on an empty region, but bad if we're failing on a + // server bake texture. + if (getFTType() != FTT_MAP_TILE) + { + LL_WARNS() << mUrl << ": Marking image as missing" << LL_ENDL; + } + } + if (mHasFetcher) + { + LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); + mHasFetcher = FALSE; + mIsFetching = FALSE; + mLastPacketTimer.reset(); + mFetchState = 0; + mFetchPriority = 0; + } } - if (mHasFetcher) + else { - LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); - mHasFetcher = FALSE; - mIsFetching = FALSE; - mLastPacketTimer.reset(); - mFetchState = 0; - mFetchPriority = 0; + LL_INFOS() << mID << ": un-flagging missing asset" << LL_ENDL; } - mIsMissingAsset = TRUE; + mIsMissingAsset = is_missing; } void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback, @@ -2148,10 +2203,19 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call } if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0) { - // We need aux data, but we've already loaded the image, and it didn't have any - LL_WARNS() << "No aux data available for callback for image:" << getID() << LL_ENDL; + if(mHasAux) + { + //trigger a refetch + forceToRefetchTexture(); + } + else + { + // We need aux data, but we've already loaded the image, and it didn't have any + LL_WARNS() << "No aux data available for callback for image:" << getID() << LL_ENDL; + } } - mLastCallBackActiveTime = sCurrentTime; + mLastCallBackActiveTime = sCurrentTime ; + mLastReferencedSavedRawImageTime = sCurrentTime; } void LLViewerFetchedTexture::clearCallbackEntryList() @@ -2262,8 +2326,9 @@ void LLViewerFetchedTexture::unpauseLoadedCallbacks(const LLLoadedCallbackEntry: } } } - mPauseLoadedCallBacks = FALSE; - mLastCallBackActiveTime = sCurrentTime; + mPauseLoadedCallBacks = FALSE ; + mLastCallBackActiveTime = sCurrentTime ; + mForceCallbackFetch = TRUE; if(need_raw) { mSaveRawImage = TRUE; @@ -2303,7 +2368,8 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s bool LLViewerFetchedTexture::doLoadedCallbacks() { - static const F32 MAX_INACTIVE_TIME = 900.f; //seconds + static const F32 MAX_INACTIVE_TIME = 900.f ; //seconds + static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds if (mNeedsCreateTexture) { @@ -2316,14 +2382,30 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() } if(sCurrentTime - mLastCallBackActiveTime > MAX_INACTIVE_TIME && !mIsFetching) { - clearCallbackEntryList(); //remove all callbacks. - return false; + if (mFTType == FTT_SERVER_BAKE) + { + //output some debug info + LL_INFOS() << "baked texture: " << mID << "clears all call backs due to inactivity." << LL_ENDL; + LL_INFOS() << mUrl << LL_ENDL; + LL_INFOS() << "current discard: " << getDiscardLevel() << " current discard for fetch: " << getCurrentDiscardLevelForFetching() << + " Desired discard: " << getDesiredDiscardLevel() << "decode Pri: " << getDecodePriority() << LL_ENDL; + } + + clearCallbackEntryList() ; //remove all callbacks. + return false ; } bool res = false; if (isMissingAsset()) { + if (mFTType == FTT_SERVER_BAKE) + { + //output some debug info + LL_INFOS() << "baked texture: " << mID << "is missing." << LL_ENDL; + LL_INFOS() << mUrl << LL_ENDL; + } + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); iter != mLoadedCallbackList.end(); ) { @@ -2508,6 +2590,9 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() } } + // Done with any raw image data at this point (will be re-created if we still have callbacks) + destroyRawImage(); + // // If we have no callbacks, take us off of the image callback list. // @@ -2515,10 +2600,13 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() { gTextureList.mCallbackList.erase(this); } + else if(!res && mForceCallbackFetch && sCurrentTime - mLastCallBackActiveTime > MAX_IDLE_WAIT_TIME && !mIsFetching) + { + //wait for long enough but no fetching request issued, force one. + forceToRefetchTexture(mLoadedCallbackDesiredDiscardLevel, 5.f); + mForceCallbackFetch = FALSE; //fire once. + } - // Done with any raw image data at this point (will be re-created if we still have callbacks) - destroyRawImage(); - return res; } @@ -2600,7 +2688,7 @@ bool LLViewerFetchedTexture::needsToSaveRawImage() void LLViewerFetchedTexture::destroyRawImage() { - if (mAuxRawImage.notNull()) + if (mAuxRawImage.notNull() && !needsToSaveRawImage()) { sAuxCount--; mAuxRawImage = NULL; @@ -2756,6 +2844,24 @@ void LLViewerFetchedTexture::saveRawImage() mLastReferencedSavedRawImageTime = sCurrentTime; } +//force to refetch the texture to the discard level +void LLViewerFetchedTexture::forceToRefetchTexture(S32 desired_discard, F32 kept_time) +{ + if(mForceToSaveRawImage) + { + desired_discard = llmin(desired_discard, mDesiredSavedRawDiscardLevel); + kept_time = llmax(kept_time, mKeptSavedRawImageTime); + } + + //trigger a new fetch. + mForceToSaveRawImage = TRUE ; + mDesiredSavedRawDiscardLevel = desired_discard ; + mKeptSavedRawImageTime = kept_time ; + mLastReferencedSavedRawImageTime = sCurrentTime ; + mSavedRawImage = NULL ; + mSavedRawDiscardLevel = -1 ; +} + void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, F32 kept_time) { mKeptSavedRawImageTime = kept_time; @@ -2796,13 +2902,19 @@ void LLViewerFetchedTexture::destroySavedRawImage() clearCallbackEntryList(); - mSavedRawImage = NULL; - mForceToSaveRawImage = FALSE; - mSaveRawImage = FALSE; - mSavedRawDiscardLevel = -1; - mDesiredSavedRawDiscardLevel = -1; - mLastReferencedSavedRawImageTime = 0.0f; - mKeptSavedRawImageTime = 0.f; + mSavedRawImage = NULL ; + mForceToSaveRawImage = FALSE ; + mSaveRawImage = FALSE ; + mSavedRawDiscardLevel = -1 ; + mDesiredSavedRawDiscardLevel = -1 ; + mLastReferencedSavedRawImageTime = 0.0f ; + mKeptSavedRawImageTime = 0.f ; + + if(mAuxRawImage.notNull()) + { + sAuxCount--; + mAuxRawImage = NULL; + } } LLImageRaw* LLViewerFetchedTexture::getSavedRawImage() diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index b12b988513..307204da60 100755 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -34,6 +34,7 @@ #include "llgltypes.h" #include "llrender.h" #include "llmetricperformancetester.h" +#include "httpcommon.h" #include <map> #include <list> @@ -41,6 +42,7 @@ extern const S32Megabytes gMinVideoRam; extern const S32Megabytes gMaxVideoRam; +class LLFace; class LLImageGL ; class LLImageRaw; class LLViewerObject; @@ -97,6 +99,7 @@ public: DYNAMIC_TEXTURE, FETCHED_TEXTURE, LOD_TEXTURE, + ATLAS_TEXTURE, INVALID_TEXTURE_TYPE }; @@ -118,7 +121,7 @@ public: LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ; virtual S8 getType() const; - virtual BOOL isMissingAsset()const ; + virtual BOOL isMissingAsset() const ; virtual void dump(); // debug info to LL_INFOS() /*virtual*/ bool bindDefaultImage(const S32 stage = 0) ; @@ -244,6 +247,8 @@ enum FTType FTT_LOCAL_FILE // fetch directly from a local file. }; +const std::string& fttype_to_string(const FTType& fttype); + // //textures are managed in gTextureList. //raw image data is fetched from remote or local cache @@ -340,8 +345,8 @@ public: // more data. /*virtual*/ void setKnownDrawSize(S32 width, S32 height); - void setIsMissingAsset(); - /*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; } + void setIsMissingAsset(BOOL is_missing = true); + /*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; } // returns dimensions of original image for local files (before power of two scaling) // and returns 0 for all asset system images @@ -383,6 +388,7 @@ public: BOOL isCachedRawImageReady() const {return mCachedRawImageReady ;} BOOL isRawImageValid()const { return mIsRawImageValid ; } void forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ; + void forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f); /*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ; void destroySavedRawImage() ; LLImageRaw* getSavedRawImage() ; @@ -411,10 +417,16 @@ private: void saveRawImage() ; void setCachedRawImage() ; + //for atlas + void resetFaceAtlas() ; + void invalidateAtlas(BOOL rebuild_geom) ; + BOOL insertToAtlas() ; + private: BOOL mFullyLoaded; BOOL mInDebug; BOOL mInFastCacheList; + BOOL mForceCallbackFetch; protected: std::string mLocalFileName; @@ -442,11 +454,13 @@ protected: S8 mMinDesiredDiscardLevel; // The minimum discard level we'd like to have S8 mNeedsAux; // We need to decode the auxiliary channels + S8 mHasAux; // We have aux channels S8 mDecodingAux; // Are we decoding high components S8 mIsRawImageValid; S8 mHasFetcher; // We've made a fecth request S8 mIsFetching; // Fetch request is active - bool mCanUseHTTP ; //This texture can be fetched through http if true. + bool mCanUseHTTP; //This texture can be fetched through http if true. + LLCore::HttpStatus mLastHttpGetStatus; // Result of the most recently completed http request for this texture. FTType mFTType; // What category of image is this - map tile, server bake, etc? mutable S8 mIsMissingAsset; // True if we know that there is no image asset with this image id in the database. diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index a544cc81da..7de82a4710 100644..100755 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -73,14 +73,16 @@ private: static std::string asset_id_to_filename(const LLUUID &asset_id); LLViewerWearable::LLViewerWearable(const LLTransactionID& transaction_id) : - LLWearable() + LLWearable(), + mVolatile(FALSE) { mTransactionID = transaction_id; mAssetID = mTransactionID.makeAssetID(gAgent.getSecureSessionID()); } LLViewerWearable::LLViewerWearable(const LLAssetID& asset_id) : - LLWearable() + LLWearable(), + mVolatile(FALSE) { mAssetID = asset_id; mTransactionID.setNull(); @@ -265,7 +267,7 @@ void LLViewerWearable::setParamsToDefaults() { if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->isTweakable() ) ) { - setVisualParamWeight(param->getID(),param->getDefaultWeight(), FALSE); + setVisualParamWeight(param->getID(),param->getDefaultWeight()); } } } @@ -321,16 +323,6 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp) if (!viewer_avatar->isValid()) return; -#if 0 - // FIXME DRANO - kludgy way to avoid overwriting avatar state from wearables. - // Ideally would avoid calling this func in the first place. - if (viewer_avatar->isUsingServerBakes() && - !viewer_avatar->isUsingLocalAppearance()) - { - return; - } -#endif - ESex old_sex = avatarp->getSex(); LLWearable::writeToAvatar(avatarp); @@ -360,19 +352,14 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp) ESex new_sex = avatarp->getSex(); if( old_sex != new_sex ) { - viewer_avatar->updateSexDependentLayerSets( FALSE ); + viewer_avatar->updateSexDependentLayerSets(); } - -// if( upload_bake ) -// { -// gAgent.sendAgentSetAppearance(); -// } } // Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values. // static -void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ) +void LLViewerWearable::removeFromAvatar( LLWearableType::EType type) { if (!isAgentAvatarValid()) return; @@ -391,7 +378,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload if( (((LLViewerVisualParam*)param)->getWearableType() == type) && (param->isTweakable() ) ) { S32 param_id = param->getID(); - gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight(), upload_bake ); + gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight()); } } @@ -401,12 +388,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload } gAgentAvatarp->updateVisualParams(); - gAgentAvatarp->wearableUpdated(type, FALSE); - -// if( upload_bake ) -// { -// gAgent.sendAgentSetAppearance(); -// } + gAgentAvatarp->wearableUpdated(type); } // Does not copy mAssetID. @@ -479,13 +461,6 @@ void LLViewerWearable::setItemID(const LLUUID& item_id) void LLViewerWearable::revertValues() { -#if 0 - // DRANO avoid overwrite when not in local appearance - if (isAgentAvatarValid() && gAgentAvatarp->isUsingServerBakes() && !gAgentAvatarp->isUsingLocalAppearance()) - { - return; - } -#endif LLWearable::revertValues(); @@ -523,13 +498,6 @@ void LLViewerWearable::refreshName() } } -// virtual -void LLViewerWearable::addToBakedTextureHash(LLMD5& hash) const -{ - LLUUID asset_id = getAssetID(); - hash.update((const unsigned char*)asset_id.mData, UUID_BYTES); -} - struct LLWearableSaveData { LLWearableType::EType mType; diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h index 8f49e3c4e2..62cd5e21ad 100644..100755 --- a/indra/newview/llviewerwearable.h +++ b/indra/newview/llviewerwearable.h @@ -62,13 +62,15 @@ public: BOOL isOldVersion() const; /*virtual*/ void writeToAvatar(LLAvatarAppearance *avatarp); - void removeFromAvatar( BOOL upload_bake ) { LLViewerWearable::removeFromAvatar( mType, upload_bake ); } - static void removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ); + void removeFromAvatar() { LLViewerWearable::removeFromAvatar( mType); } + static void removeFromAvatar( LLWearableType::EType type); /*virtual*/ EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp ); void setParamsToDefaults(); void setTexturesToDefaults(); + void setVolatile(BOOL is_volatile) { mVolatile = is_volatile; } // TRUE when doing preview renders, some updates will be suppressed. + BOOL getVolatile() { return mVolatile; } /*virtual*/ LLUUID getDefaultTextureImageID(LLAvatarAppearanceDefines::ETextureIndex index) const; @@ -89,14 +91,14 @@ public: // the wearable was worn. make sure the name of the wearable object matches the LLViewerInventoryItem, // not the wearable asset itself. void refreshName(); - - // Update the baked texture hash. - /*virtual*/void addToBakedTextureHash(LLMD5& hash) const; + /*virtual*/void addToBakedTextureHash(LLMD5& hash) const {} protected: LLAssetID mAssetID; LLTransactionID mTransactionID; + BOOL mVolatile; // True when rendering preview images. Can suppress some updates. + LLUUID mItemID; // ID of the inventory item in the agent's inventory }; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index aa75bae712..d052906bee 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -261,7 +261,7 @@ std::string LLViewerWindow::sMovieBaseName; LLTrace::SampleStatHandle<> LLViewerWindow::sMouseVelocityStat("Mouse Velocity"); -class RecordToChatConsole : public LLError::Recorder, public LLSingleton<RecordToChatConsole> +class RecordToChatConsoleRecorder : public LLError::Recorder { public: virtual void recordMessage(LLError::ELevel level, @@ -285,6 +285,22 @@ public: } }; +class RecordToChatConsole : public LLSingleton<RecordToChatConsole> +{ +public: + RecordToChatConsole() + : LLSingleton<RecordToChatConsole>(), + mRecorder(new RecordToChatConsoleRecorder()) + { + } + + void startRecorder() { LLError::addRecorder(mRecorder); } + void stopRecorder() { LLError::removeRecorder(mRecorder); } + +private: + LLError::RecorderPtr mRecorder; +}; + //////////////////////////////////////////////////////////////////////////// // // LLDebugText @@ -443,10 +459,7 @@ public: } if (gDisplayWindInfo) { - if (gAudiop) - { - audio_text= llformat("Audio for wind: %d", gAudiop->isWindEnabled()); - } + audio_text = llformat("Audio for wind: %d", gAudiop ? gAudiop->isWindEnabled() : -1); addText(xpos, ypos, audio_text); ypos += y_inc; } if (gDisplayFOV) @@ -1889,11 +1902,11 @@ void LLViewerWindow::initBase() // optionally forward warnings to chat console/chat floater // for qa runs and dev builds #if !LL_RELEASE_FOR_DOWNLOAD - LLError::addRecorder(RecordToChatConsole::getInstance()); + RecordToChatConsole::getInstance()->startRecorder(); #else if(gSavedSettings.getBOOL("QAMode")) { - LLError::addRecorder(RecordToChatConsole::getInstance()); + RecordToChatConsole::getInstance()->startRecorder(); } #endif @@ -1910,9 +1923,7 @@ void LLViewerWindow::initBase() setProgressCancelButtonVisible(FALSE); gMenuHolder = getRootView()->getChild<LLViewerMenuHolderGL>("Menu Holder"); - LLMenuGL::sMenuContainer = gMenuHolder; - } void LLViewerWindow::initWorldUI() @@ -2026,7 +2037,7 @@ void LLViewerWindow::initWorldUI() destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); std::string url = gSavedSettings.getString("DestinationGuideURL"); url = LLWeb::expandURLSubstitutions(url, LLSD()); - destinations->navigateTo(url, "text/html"); + destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML); } LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents"); if (avatar_picker) @@ -2034,7 +2045,7 @@ void LLViewerWindow::initWorldUI() avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); std::string url = gSavedSettings.getString("AvatarPickerURL"); url = LLWeb::expandURLSubstitutions(url, LLSD()); - avatar_picker->navigateTo(url, "text/html"); + avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML); } } @@ -2042,8 +2053,7 @@ void LLViewerWindow::initWorldUI() void LLViewerWindow::shutdownViews() { // clean up warning logger - LLError::removeRecorder(RecordToChatConsole::getInstance()); - + RecordToChatConsole::getInstance()->stopRecorder(); LL_INFOS() << "Warning logger is cleaned." << LL_ENDL ; delete mDebugText; @@ -2078,6 +2088,9 @@ void LLViewerWindow::shutdownViews() // access to gMenuHolder cleanup_menus(); LL_INFOS() << "menus destroyed." << LL_ENDL ; + + view_listener_t::cleanup(); + LL_INFOS() << "view listeners destroyed." << LL_ENDL ; // Delete all child views. delete mRootView; @@ -2153,6 +2166,12 @@ LLViewerWindow::~LLViewerWindow() delete mDebugText; mDebugText = NULL; + + if (LLViewerShaderMgr::sInitialized) + { + LLViewerShaderMgr::releaseInstance(); + LLViewerShaderMgr::sInitialized = FALSE; + } } @@ -3246,6 +3265,8 @@ void LLViewerWindow::updateUI() updateLayout(); + saveLastMouse(mCurrentMousePoint); + // cleanup unused selections when no modal dialogs are open if (LLModalDialog::activeCount() == 0) { diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 04f64a4997..9f42776d78 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -109,7 +109,7 @@ extern F32 SPEED_ADJUST_MAX; extern F32 SPEED_ADJUST_MAX_SEC; extern F32 ANIM_SPEED_MAX; extern F32 ANIM_SPEED_MIN; - +extern U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG; // #define OUTPUT_BREAST_DATA @@ -713,7 +713,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mLastRezzedStatus(-1), mIsEditingAppearance(FALSE), mUseLocalAppearance(FALSE), - mUseServerBakes(FALSE), // FIXME DRANO consider using boost::optional, defaulting to unknown. mLastUpdateRequestCOFVersion(-1), mLastUpdateReceivedCOFVersion(-1) { @@ -723,7 +722,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim ); - LL_DEBUGS() << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL; + LL_DEBUGS("Avatar") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL; mPelvisp = NULL; @@ -830,8 +829,8 @@ LLVOAvatar::~LLVOAvatar() } logPendingPhases(); - - LL_DEBUGS() << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << LL_ENDL; + + LL_DEBUGS("Avatar") << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << LL_ENDL; std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer()); mAttachmentPoints.clear(); @@ -1085,7 +1084,7 @@ void LLVOAvatar::restoreGL() gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); for (U32 i = 0; i < gAgentAvatarp->mBakedTextureDatas.size(); i++) { - gAgentAvatarp->invalidateComposite(gAgentAvatarp->getTexLayerSet(i), FALSE); + gAgentAvatarp->invalidateComposite(gAgentAvatarp->getTexLayerSet(i)); } gAgentAvatarp->updateMeshTextures(); } @@ -1252,6 +1251,7 @@ LLTexLayerSet* LLVOAvatar::createTexLayerSet() const LLVector3 LLVOAvatar::getRenderPosition() const { + if (mDrawable.isNull() || mDrawable->getGeneration() < 0) { return getPositionAgent(); @@ -1274,6 +1274,8 @@ const LLVector3 LLVOAvatar::getRenderPosition() const { return getPosition() * mDrawable->getParent()->getRenderMatrix(); } + + } void LLVOAvatar::updateDrawable(BOOL force_damped) @@ -1309,6 +1311,8 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) mImpostorOffset = LLVector3(pos_group.getF32ptr())-getRenderPosition(); mDrawable->setPositionGroup(pos_group); } + + } void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) @@ -1986,24 +1990,23 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU // Should already exist, don't need to find it on sim or baked-texture host. result = gTextureList.findImage(uuid); } - if (!result) { const std::string url = getImageURL(te,uuid); - if (!url.empty()) - { - LL_DEBUGS("Avatar") << avString() << "from URL " << url << LL_ENDL; - result = LLViewerTextureManager::getFetchedTextureFromUrl( - url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid); - } - else - { - LL_DEBUGS("Avatar") << avString() << "from host " << uuid << LL_ENDL; - LLHost host = getObjectHost(); - result = LLViewerTextureManager::getFetchedTexture( - uuid, FTT_HOST_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); + + if (url.empty()) + { + LL_WARNS() << "unable to determine URL for te " << te << " uuid " << uuid << LL_ENDL; + return NULL; + } + LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << LL_ENDL; + result = LLViewerTextureManager::getFetchedTextureFromUrl( + url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid); + if (result->isMissingAsset()) + { + result->setIsMissingAsset(false); + } } -} return result; } @@ -2231,8 +2234,8 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) if ( mLipSyncActive ) { - if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight(), FALSE); - if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight(), FALSE); + if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight()); + if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight()); mLipSyncActive = false; LLCharacter::updateVisualParams(); @@ -2255,7 +2258,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) { LLVector3 tagPos = mRoot->getWorldPosition(); tagPos[VZ] -= mPelvisToFoot; - tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); + tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); // does not need mAvatarOffset -Nyx mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos ); } }//if ( voiceEnabled ) @@ -2395,14 +2398,10 @@ void LLVOAvatar::idleUpdateAppearanceAnimation() { if (param->isTweakable()) { - param->stopAnimating(FALSE); + param->stopAnimating(); } } updateVisualParams(); - if (isSelf()) - { - gAgent.sendAgentSetAppearance(); - } } else { @@ -2418,7 +2417,7 @@ void LLVOAvatar::idleUpdateAppearanceAnimation() { if (param->isTweakable()) { - param->animate(morph_amt, FALSE); + param->animate(morph_amt); } } } @@ -2471,7 +2470,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled) F32 ooh_weight = mOohMorph->getMinWeight() + ooh_morph_amount * (mOohMorph->getMaxWeight() - mOohMorph->getMinWeight()); - mOohMorph->setWeight( ooh_weight, FALSE ); + mOohMorph->setWeight( ooh_weight); } if( mAahMorph ) @@ -2479,7 +2478,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled) F32 aah_weight = mAahMorph->getMinWeight() + aah_morph_amount * (mAahMorph->getMaxWeight() - mAahMorph->getMinWeight()); - mAahMorph->setWeight( aah_weight, FALSE ); + mAahMorph->setWeight( aah_weight); } mLipSyncActive = true; @@ -2996,6 +2995,8 @@ void LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last) local_camera_up.normalize(); local_camera_up = local_camera_up * inv_root_rot; + + // position is based on head position, does not require mAvatarOffset here. - Nyx LLVector3 avatar_ellipsoid(mBodySize.mV[VX] * 0.4f, mBodySize.mV[VY] * 0.4f, mBodySize.mV[VZ] * NAMETAG_VERT_OFFSET_WEIGHT); @@ -3175,7 +3176,10 @@ void LLVOAvatar::forceUpdateVisualMuteSettings() // called on both your avatar and other avatars //------------------------------------------------------------------------ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) -{ +{ + // clear debug text + mDebugText.clear(); + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) { S32 central_bake_version = -1; @@ -3189,7 +3193,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) isSelf() ? (all_local_downloaded ? "L" : "l") : "-", all_baked_downloaded ? "B" : "b", mUseLocalAppearance, mIsEditingAppearance, - mUseServerBakes, central_bake_version); + 1, central_bake_version); std::string origin_string = bakedTextureOriginInfo(); debug_line += " [" + origin_string + "]"; S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion(); @@ -3689,6 +3693,9 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) //mesh vertices need to be reskinned mNeedsSkin = TRUE; + + + return TRUE; } //----------------------------------------------------------------------------- @@ -3722,9 +3729,9 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount, { mHasPelvisOffset = hasOffset; if ( mHasPelvisOffset ) - { + { //Store off last pelvis to foot value - mLastPelvisToFoot = mPelvisToFoot; + mLastPelvisToFoot = mPelvisToFoot; mPelvisOffset = offsetAmount; mLastPelvisFixup = mPelvisFixup; mPelvisFixup = pelvisFixup; @@ -3734,18 +3741,16 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount, // postPelvisSetRecalc //------------------------------------------------------------------------ void LLVOAvatar::postPelvisSetRecalc( void ) -{ - computeBodySize(); - mRoot->touch(); - mRoot->updateWorldMatrixChildren(); - dirtyMesh(); - updateHeadOffset(); +{ + mRoot->updateWorldMatrixChildren(); + computeBodySize(); + dirtyMesh(2); } //------------------------------------------------------------------------ -// pelisPoke +// setPelvisOffset //------------------------------------------------------------------------ void LLVOAvatar::setPelvisOffset( F32 pelvisFixupAmount ) -{ +{ mHasPelvisOffset = true; mLastPelvisFixup = mPelvisFixup; mPelvisFixup = pelvisFixupAmount; @@ -4285,34 +4290,6 @@ bool LLVOAvatar::allBakedTexturesCompletelyDownloaded() const return allTexturesCompletelyDownloaded(baked_ids); } -void LLVOAvatar::bakedTextureOriginCounts(S32 &sb_count, // server-bake, has origin URL. - S32 &host_count, // host-based bake, has host. - S32 &both_count, // error - both host and URL set. - S32 &neither_count) // error - neither set. -{ - sb_count = host_count = both_count = neither_count = 0; - - std::set<LLUUID> baked_ids; - collectBakedTextureUUIDs(baked_ids); - for (std::set<LLUUID>::const_iterator it = baked_ids.begin(); it != baked_ids.end(); ++it) - { - LLViewerFetchedTexture *imagep = gTextureList.findImage(*it); - bool has_url = false, has_host = false; - if (!imagep->getUrl().empty()) - { - has_url = true; - } - if (imagep->getTargetHost().isOk()) - { - has_host = true; - } - if (has_url && !has_host) sb_count++; - else if (has_host && !has_url) host_count++; - else if (has_host && has_url) both_count++; - else if (!has_host && !has_url) neither_count++; - } -} - std::string LLVOAvatar::bakedTextureOriginInfo() { std::string result; @@ -4553,19 +4530,6 @@ void LLVOAvatar::updateTextures() { const S32 boost_level = getAvatarBakedBoostLevel(); imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE); - // Spam if this is a baked texture, not set to default image, without valid host info - if (isIndexBakedTexture((ETextureIndex)texture_index) - && imagep->getID() != IMG_DEFAULT_AVATAR - && imagep->getID() != IMG_INVISIBLE - && !isUsingServerBakes() - && !imagep->getTargetHost().isOk()) - { - LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture " - << imagep->getID() << " for avatar " - << (isSelf() ? "<myself>" : getID().asString()) - << " on host " << getRegion()->getHost() << LL_ENDL; - } - addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); } } @@ -4585,7 +4549,7 @@ void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture } const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames. -const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames +const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL = S32_MAX ; //frames void LLVOAvatar::checkTextureLoading() { static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds @@ -4648,11 +4612,11 @@ const F32 ADDITIONAL_PRI = 0.5f; void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level) { //Note: - //if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames, + //if this function is not called for the last MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL frames, //the texture pipeline will stop fetching this texture. imagep->resetTextureStats(); - imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); + imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL); imagep->resetMaxVirtualSizeResetCounter() ; mMaxPixelArea = llmax(pixel_area, mMaxPixelArea); @@ -4697,22 +4661,19 @@ const std::string LLVOAvatar::getImageURL(const U8 te, const LLUUID &uuid) { llassert(isIndexBakedTexture(ETextureIndex(te))); std::string url = ""; - if (isUsingServerBakes()) + const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL(); + if (appearance_service_url.empty()) { - const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL(); - if (appearance_service_url.empty()) - { - // Probably a server-side issue if we get here: - LL_WARNS() << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << LL_ENDL; - return url; - } + // Probably a server-side issue if we get here: + LL_WARNS() << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << LL_ENDL; + return url; + } - const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); - if (texture_entry != NULL) - { - url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString(); - //LL_INFOS() << "baked texture url: " << url << LL_ENDL; - } + const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); + if (texture_entry != NULL) + { + url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString(); + //LL_INFOS() << "baked texture url: " << url << LL_ENDL; } return url; } @@ -5096,70 +5057,39 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name ) return jointp; } - -//----------------------------------------------------------------------------- -// resetJointPositions -//----------------------------------------------------------------------------- -void LLVOAvatar::resetJointPositions( void ) -{ - avatar_joint_list_t::iterator iter = mSkeleton.begin(); - avatar_joint_list_t::iterator end = mSkeleton.end(); - for (; iter != end; ++iter) - { - (*iter)->restoreOldXform(); - (*iter)->setId( LLUUID::null ); - } - mHasPelvisOffset = false; - mPelvisFixup = mLastPelvisFixup; -} -//----------------------------------------------------------------------------- -// resetSpecificJointPosition -//----------------------------------------------------------------------------- -void LLVOAvatar::resetSpecificJointPosition( const std::string& name ) -{ - LLJoint* pJoint = mRoot->findJoint( name ); - - if ( pJoint && pJoint->doesJointNeedToBeReset() ) - { - pJoint->restoreOldXform(); - pJoint->setId( LLUUID::null ); - //If we're reseting the pelvis position make sure not to apply offset - if ( name == "mPelvis" ) - { - mHasPelvisOffset = false; - } - } - else - { - LL_INFOS()<<"Did not find "<< name.c_str()<<LL_ENDL; - } -} //----------------------------------------------------------------------------- // resetJointPositionsToDefault //----------------------------------------------------------------------------- void LLVOAvatar::resetJointPositionsToDefault( void ) -{ +{ //Subsequent joints are relative to pelvis avatar_joint_list_t::iterator iter = mSkeleton.begin(); avatar_joint_list_t::iterator end = mSkeleton.end(); + + LLJoint* pJointPelvis = getJoint("mPelvis"); + for (; iter != end; ++iter) { LLJoint* pJoint = (*iter); - if ( pJoint->doesJointNeedToBeReset() ) + //Reset joints except for pelvis + if ( pJoint && pJoint != pJointPelvis && pJoint->doesJointNeedToBeReset() ) + { + pJoint->setId( LLUUID::null ); + pJoint->restoreOldXform(); + } + else + if ( pJoint && pJoint == pJointPelvis && pJoint->doesJointNeedToBeReset() ) { pJoint->setId( LLUUID::null ); - //restore joints to default positions, however skip over the pelvis - // *TODO: How does this pointer check skip over pelvis? - if ( pJoint ) - { - pJoint->restoreOldXform(); - } - } - } + pJoint->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) ); + pJoint->setJointResetFlag( false ); + } + } + //make sure we don't apply the joint offset mHasPelvisOffset = false; mPelvisFixup = mLastPelvisFixup; - postPelvisSetRecalc(); + postPelvisSetRecalc(); } //----------------------------------------------------------------------------- // getCharacterPosition() @@ -5314,7 +5244,7 @@ BOOL LLVOAvatar::loadSkeletonNode () { attachment->setOriginalPosition(info->mPosition); } - + if (info->mHasRotation) { LLQuaternion rotation; @@ -5384,7 +5314,6 @@ void LLVOAvatar::updateVisualParams() dirtyMesh(); updateHeadOffset(); } - //----------------------------------------------------------------------------- // isActive() //----------------------------------------------------------------------------- @@ -5541,11 +5470,11 @@ BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) //----------------------------------------------------------------------------- // updateSexDependentLayerSets() //----------------------------------------------------------------------------- -void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake ) +void LLVOAvatar::updateSexDependentLayerSets() { - invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); - invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake ); - invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake ); + invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet); + invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet); + invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet); } //----------------------------------------------------------------------------- @@ -5761,6 +5690,7 @@ void LLVOAvatar::lazyAttach() void LLVOAvatar::resetHUDAttachments() { + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -5813,10 +5743,10 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO ) { const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID(), pVObj ); if (pSkinData - && pSkinData->mJointNames.size() > 20 // full rig - && pSkinData->mAlternateBindMatrix.size() > 0) - { - LLVOAvatar::resetJointPositionsToDefault(); + && pSkinData->mJointNames.size() > JOINT_COUNT_REQUIRED_FOR_FULLRIG // full rig + && pSkinData->mAlternateBindMatrix.size() > 0 ) + { + LLVOAvatar::resetJointPositionsToDefault(); //Need to handle the repositioning of the cam, updating rig data etc during outfit editing //This handles the case where we detach a replacement rig. if ( gAgentCamera.cameraCustomizeAvatar() ) @@ -5835,6 +5765,7 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO ) //----------------------------------------------------------------------------- BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) { + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -5845,6 +5776,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) { mVisualComplexityStale = TRUE; cleanupAttachedMesh( viewer_object ); + attachment->removeObject(viewer_object); LL_DEBUGS() << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << LL_ENDL; return TRUE; @@ -6058,8 +5990,6 @@ BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const return FALSE; } - - LLViewerObject * LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) const { for(attachment_map_t::const_iterator attachment_points_iter = mAttachmentPoints.begin(); @@ -6083,9 +6013,8 @@ LLViewerObject * LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) cons return NULL; } - // virtual -void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result ) +void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset) { } @@ -6094,18 +6023,18 @@ void LLVOAvatar::invalidateAll() } // virtual -void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake ) +void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color) { if (global_color == mTexSkinColor) { - invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); - invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake ); - invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake ); + invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet); + invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet); + invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet); } else if (global_color == mTexHairColor) { - invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); - invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet, upload_bake ); + invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet); + invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet); // ! BACKWARDS COMPATIBILITY ! // Fix for dealing with avatars from viewers that don't bake hair. @@ -6127,7 +6056,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL else if (global_color == mTexEyeColor) { // LL_INFOS() << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << LL_ENDL; - invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet, upload_bake ); + invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet); } updateMeshTextures(); } @@ -6218,9 +6147,12 @@ void LLVOAvatar::clearPhases() void LLVOAvatar::startPhase(const std::string& phase_name) { - F32 elapsed; - bool completed; - if (getPhases().getPhaseValues(phase_name, elapsed, completed)) + F32 elapsed = 0.0; + bool completed = false; + bool found = getPhases().getPhaseValues(phase_name, elapsed, completed); + //LL_DEBUGS("Avatar") << avString() << " phase state " << phase_name + // << " found " << found << " elapsed " << elapsed << " completed " << completed << LL_ENDL; + if (found) { if (!completed) { @@ -6233,9 +6165,9 @@ void LLVOAvatar::startPhase(const std::string& phase_name) } void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check) - { - F32 elapsed; - bool completed; +{ + F32 elapsed = 0.0; + bool completed = false; if (getPhases().getPhaseValues(phase_name, elapsed, completed)) { if (!completed) @@ -6321,7 +6253,7 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse } record["grid_x"] = LLSD::Integer(grid_x); record["grid_y"] = LLSD::Integer(grid_y); - record["is_using_server_bakes"] = ((bool) isUsingServerBakes()); + record["is_using_server_bakes"] = true; record["is_self"] = isSelf(); if (isAgentAvatarValid()) @@ -6566,6 +6498,8 @@ void LLVOAvatar::updateMeshTextures() // we'll consider it loaded and use it (rather than // doing compositing). useBakedTexture( baked_img->getID() ); + mLoadedCallbacksPaused |= !isVisible(); + checkTextureLoading(); } else { @@ -6578,6 +6512,10 @@ void LLVOAvatar::updateMeshTextures() } baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ), src_callback_list, paused ); + + // this could add paused texture callbacks + mLoadedCallbacksPaused |= paused; + checkTextureLoading(); } } else if (layerset && isUsingLocalAppearance()) @@ -6724,8 +6662,6 @@ void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_com } } - - // returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise BOOL LLVOAvatar::morphMaskNeedsUpdate(LLAvatarAppearanceDefines::EBakedTextureIndex index) { @@ -6936,6 +6872,9 @@ void LLVOAvatar::onFirstTEMessageReceived() LL_DEBUGS("Avatar") << avString() << "layer_baked, setting onInitialBakedTextureLoaded as callback" << LL_ENDL; image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ), src_callback_list, paused ); + + // this could add paused texture callbacks + mLoadedCallbacksPaused |= paused; } } @@ -7008,7 +6947,7 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value) void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix, const LLAppearanceMessageContents& contents) - { +{ std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml"); const std::vector<F32>& params_for_dump = contents.mParamWeights; const LLTEContents& tec = contents.mTEContents; @@ -7035,7 +6974,8 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix, LLVisualParam* param = getFirstVisualParam(); for (S32 i = 0; i < params_for_dump.size(); i++) { - while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + while( param && ((param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) && + (param->getGroup() != VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE)) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT { param = getNextVisualParam(); } @@ -7089,7 +7029,8 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe { for( S32 i = 0; i < num_blocks; i++ ) { - while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + while( param && ((param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) && + (param->getGroup() != VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE)) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT { param = getNextVisualParam(); } @@ -7110,7 +7051,8 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe } } - const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE) + + getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT if (num_blocks != expected_tweakable_count) { LL_DEBUGS("Avatar") << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << LL_ENDL; @@ -7157,13 +7099,13 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32 { appearance_version = contents.mParamAppearanceVersion; } - if (contents.mAppearanceVersion >= 0) + else if (contents.mAppearanceVersion > 0) { appearance_version = contents.mAppearanceVersion; } - if (appearance_version < 0) // still not set, go with 0. + else // still not set, go with 1. { - appearance_version = 0; + appearance_version = 1; } LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion << " param: " << contents.mParamAppearanceVersion @@ -7201,24 +7143,21 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) LL_WARNS() << "bad appearance version info, discarding" << LL_ENDL; return; } + llassert(appearance_version > 0); + if (appearance_version > 1) + { + LL_WARNS() << "unsupported appearance version " << appearance_version << ", discarding appearance message" << LL_ENDL; + return; + } + S32 this_update_cof_version = contents.mCOFVersion; S32 last_update_request_cof_version = mLastUpdateRequestCOFVersion; - // Only now that we have result of appearance_version can we decide whether to bail out. if( isSelf() ) { LL_DEBUGS("Avatar") << "this_update_cof_version " << this_update_cof_version << " last_update_request_cof_version " << last_update_request_cof_version << " my_cof_version " << LLAppearanceMgr::instance().getCOFVersion() << LL_ENDL; - - if (getRegion() && (getRegion()->getCentralBakeVersion()==0)) - { - LL_WARNS() << avString() << "Received AvatarAppearance message for self in non-server-bake region" << LL_ENDL; - } - if( mFirstTEMessageReceived && (appearance_version == 0)) - { - return; - } } else { @@ -7227,7 +7166,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) // Check for stale update. if (isSelf() - && (appearance_version>0) && (this_update_cof_version < last_update_request_cof_version)) { LL_WARNS() << "Stale appearance update, wanted version " << last_update_request_cof_version @@ -7241,6 +7179,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) return; } + // SUNSHINE CLEANUP - is this case OK now? S32 num_params = contents.mParamWeights.size(); if (num_params <= 1) { @@ -7252,10 +7191,14 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) return; } + // No backsies zone - if we get here, the message should be valid and usable, will be processed. + + // Note: + // RequestAgentUpdateAppearanceResponder::onRequestRequested() + // assumes that cof version is only updated with server-bake + // appearance messages. mLastUpdateReceivedCOFVersion = this_update_cof_version; - setIsUsingServerBakes(appearance_version > 0); - applyParsedTEMessage(contents.mTEContents); // prevent the overwriting of valid baked textures with invalid baked textures @@ -7265,9 +7208,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) && mBakedTextureDatas[baked_index].mLastTextureID != IMG_DEFAULT && baked_index != BAKED_SKIRT) { + LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << LL_ENDL; setTEImage(mBakedTextureDatas[baked_index].mTextureIndex, LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); } + else + { + LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using texture id " + << getTE(mBakedTextureDatas[baked_index].mTextureIndex)->getID() << LL_ENDL; + } } // runway - was @@ -7293,32 +7242,38 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) LL_DEBUGS("Avatar") << avString() << " handle visual params, num_params " << num_params << LL_ENDL; BOOL params_changed = FALSE; BOOL interp_params = FALSE; + S32 params_changed_count = 0; for( S32 i = 0; i < num_params; i++ ) { LLVisualParam* param = contents.mParams[i]; F32 newWeight = contents.mParamWeights[i]; - if (is_first_appearance_message || (param->getWeight() != newWeight)) + if (is_first_appearance_message || (param->getWeight() != newWeight)) + { + params_changed = TRUE; + params_changed_count++; + + if(is_first_appearance_message) { - params_changed = TRUE; - if(is_first_appearance_message) - { - param->setWeight(newWeight, FALSE); - } - else - { - interp_params = TRUE; - param->setAnimationTarget(newWeight, FALSE); - } + //LL_DEBUGS("Avatar") << "param slam " << i << " " << newWeight << LL_ENDL; + param->setWeight(newWeight); } + else + { + interp_params = TRUE; + param->setAnimationTarget(newWeight); + } + } } - const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE) + + getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT if (num_params != expected_tweakable_count) { LL_DEBUGS("Avatar") << "Number of params in AvatarAppearance msg (" << num_params << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << LL_ENDL; } + LL_DEBUGS("Avatar") << "Changed " << params_changed_count << " params" << LL_ENDL; if (params_changed) { if (interp_params) @@ -7330,7 +7285,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) ESex new_sex = getSex(); if( old_sex != new_sex ) { - updateSexDependentLayerSets( FALSE ); + updateSexDependentLayerSets(); } } @@ -7368,7 +7323,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) } updateMeshTextures(); - //if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end"); } @@ -7553,7 +7507,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id ) LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 ); if (id == image_baked->getID()) { - LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL; + //LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL; mBakedTextureDatas[i].mIsLoaded = true; mBakedTextureDatas[i].mLastTextureID = id; mBakedTextureDatas[i].mIsUsed = true; @@ -7626,6 +7580,15 @@ std::string get_sequential_numbered_file_name(const std::string& prefix, return outfilename; } +void dump_sequential_xml(const std::string outprefix, const LLSD& content) +{ + std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml"); + std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); + std::ofstream ofs(fullpath.c_str(), std::ios_base::out); + ofs << LLSDOStreamer<LLSDXMLFormatter>(content, LLSDFormatter::OPTIONS_PRETTY); + LL_DEBUGS("Avatar") << "results saved to: " << fullpath << LL_ENDL; +} + void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_wearables ) { std::string outprefix(prefix); @@ -7634,10 +7597,6 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara outprefix = getFullname() + (isSelf()?"_s":"_o"); } if (outprefix.empty()) -{ - outprefix = getFullname() + (isSelf()?"_s":"_o"); - } - if (outprefix.empty()) { outprefix = std::string("new_archetype"); } @@ -7704,6 +7663,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara for (U8 te = 0; te < TEX_NUM_INDICES; te++) { + { // MULTIPLE_WEARABLES: extend to multiple wearables? LLViewerTexture* te_image = getImage((ETextureIndex)te, 0); if( te_image ) @@ -7715,6 +7675,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara } } + } apr_file_printf( file, "\t</archetype>\n" ); apr_file_printf( file, "\n</linden_genepool>\n" ); @@ -7837,41 +7798,6 @@ void LLVOAvatar::startAppearanceAnimation() } // virtual -void LLVOAvatar::bodySizeChanged() -{ - if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF()) - { // notify simulator of change in size - // but not if we are in the middle of updating appearance - gAgent.sendAgentSetAppearance(); -} -} - -BOOL LLVOAvatar::isUsingServerBakes() const -{ -#if 1 - // Sanity check - visual param for appearance version should match mUseServerBakes - LLVisualParam* appearance_version_param = getVisualParam(11000); - llassert(appearance_version_param); - F32 wt = appearance_version_param->getWeight(); - F32 expect_wt = mUseServerBakes ? 1.0 : 0.0; - if (!is_approx_equal(wt,expect_wt)) -{ - LL_WARNS() << "wt " << wt << " differs from expected " << expect_wt << LL_ENDL; - } -#endif - - return mUseServerBakes; - } - -void LLVOAvatar::setIsUsingServerBakes(BOOL newval) - { - mUseServerBakes = newval; - LLVisualParam* appearance_version_param = getVisualParam(11000); - llassert(appearance_version_param); - appearance_version_param->setWeight(newval ? 1.0 : 0.0, false); - } - -// virtual void LLVOAvatar::removeMissingBakedTextures() { } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 9d0391b42c..42ff7bff92 100755 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -199,9 +199,7 @@ public: virtual LLJoint* getJoint(const std::string &name); - void resetJointPositions( void ); void resetJointPositionsToDefault( void ); - void resetSpecificJointPosition( const std::string& name ); /*virtual*/ const LLUUID& getID() const; /*virtual*/ void addDebugText(const std::string& text); @@ -210,7 +208,7 @@ public: /*virtual*/ F32 getPixelArea() const; /*virtual*/ LLVector3d getPosGlobalFromAgent(const LLVector3 &position); /*virtual*/ LLVector3 getPosAgentFromGlobal(const LLVector3d &position); - virtual void updateVisualParams(); + virtual void updateVisualParams(); /** Inherited @@ -442,7 +440,7 @@ public: // Global colors //-------------------------------------------------------------------- public: - /*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake); + /*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color); //-------------------------------------------------------------------- // Visibility @@ -602,7 +600,7 @@ protected: // Composites //-------------------------------------------------------------------- public: - virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result); + virtual void invalidateComposite(LLTexLayerSet* layerset); virtual void invalidateAll(); virtual void setCompositeUpdatesEnabled(bool b) {} virtual void setCompositeUpdatesEnabled(U32 index, bool b) {} @@ -639,7 +637,7 @@ private: public: void debugColorizeSubMeshes(U32 i, const LLColor4& color); virtual void updateMeshTextures(); - void updateSexDependentLayerSets(BOOL upload_bake); + void updateSexDependentLayerSets(); virtual void dirtyMesh(); // Dirty the avatar mesh void updateMeshData(); protected: @@ -672,7 +670,6 @@ public: void processAvatarAppearance(LLMessageSystem* mesgsys); void hideSkirt(); void startAppearanceAnimation(); - /*virtual*/ void bodySizeChanged(); //-------------------------------------------------------------------- // Appearance morphing @@ -685,12 +682,6 @@ public: // editing or when waiting for a subsequent server rebake. /*virtual*/ BOOL isUsingLocalAppearance() const { return mUseLocalAppearance; } - // True if this avatar should fetch its baked textures via the new - // appearance mechanism. - BOOL isUsingServerBakes() const; - void setIsUsingServerBakes(BOOL newval); - - // True if we are currently in appearance editing mode. Often but // not always the same as isUsingLocalAppearance(). /*virtual*/ BOOL isEditingAppearance() const { return mIsEditingAppearance; } @@ -703,7 +694,6 @@ private: F32 mLastAppearanceBlendTime; BOOL mIsEditingAppearance; // flag for if we're actively in appearance editing mode BOOL mUseLocalAppearance; // flag for if we're using a local composite - BOOL mUseServerBakes; // flag for if baked textures should be fetched from baking service (false if they're temporary uploads) //-------------------------------------------------------------------- // Visibility @@ -1031,10 +1021,11 @@ protected: // Shared with LLVOAvatarSelf }; // LLVOAvatar extern const F32 SELF_ADDITIONAL_PRI; -extern const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL; +extern const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL; std::string get_sequential_numbered_file_name(const std::string& prefix, const std::string& suffix); +void dump_sequential_xml(const std::string outprefix, const LLSD& content); void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value); #endif // LL_VOAVATAR_H diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 319da1abb5..42a7c2e576 100755 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -161,8 +161,6 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id, mRegionCrossingCount(0), mInitialBakesLoaded(false) { - gAgentWearables.setAvatarObject(this); - mMotionController.mIsSelf = TRUE; LL_DEBUGS() << "Marking avatar as self " << id << LL_ENDL; @@ -188,15 +186,6 @@ bool update_avatar_rez_metrics() return false; } -bool check_for_unsupported_baked_appearance() -{ - if (!isAgentAvatarValid()) - return true; - - gAgentAvatarp->checkForUnsupportedServerBakeAppearance(); - return false; -} - void LLVOAvatarSelf::initInstance() { BOOL status = TRUE; @@ -233,7 +222,33 @@ void LLVOAvatarSelf::initInstance() //doPeriodically(output_self_av_texture_diagnostics, 30.0); doPeriodically(update_avatar_rez_metrics, 5.0); - doPeriodically(check_for_unsupported_baked_appearance, 120.0); + doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0); +} + +bool LLVOAvatarSelf::checkStuckAppearance() +{ + const F32 CONDITIONAL_UNSTICK_INTERVAL = 300.0; + const F32 UNCONDITIONAL_UNSTICK_INTERVAL = 600.0; + + if (gAgentWearables.isCOFChangeInProgress()) + { + LL_DEBUGS("Avatar") << "checking for stuck appearance" << LL_ENDL; + F32 change_time = gAgentWearables.getCOFChangeTime(); + LL_DEBUGS("Avatar") << "change in progress for " << change_time << " seconds" << LL_ENDL; + S32 active_hp = LLAppearanceMgr::instance().countActiveHoldingPatterns(); + LL_DEBUGS("Avatar") << "active holding patterns " << active_hp << " seconds" << LL_ENDL; + S32 active_copies = LLAppearanceMgr::instance().getActiveCopyOperations(); + LL_DEBUGS("Avatar") << "active copy operations " << active_copies << LL_ENDL; + + if ((change_time > CONDITIONAL_UNSTICK_INTERVAL && active_copies == 0) || + (change_time > UNCONDITIONAL_UNSTICK_INTERVAL)) + { + gAgentWearables.notifyLoadingFinished(); + } + } + + // Return false to continue running check periodically. + return LLApp::isExiting(); } // virtual @@ -644,55 +659,42 @@ LLJoint *LLVOAvatarSelf::getJoint(const std::string &name) } return LLVOAvatar::getJoint(name); } -//virtual -void LLVOAvatarSelf::resetJointPositions( void ) -{ - return LLVOAvatar::resetJointPositions(); -} // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight) { if (!which_param) { return FALSE; } LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(which_param->getID()); - return setParamWeight(param,weight,upload_bake); + return setParamWeight(param,weight); } // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight) { if (!param_name) { return FALSE; } LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(param_name); - return setParamWeight(param,weight,upload_bake); + return setParamWeight(param,weight); } // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight) { LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(index); - return setParamWeight(param,weight,upload_bake); + return setParamWeight(param,weight); } -BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight) { if (!param) { return FALSE; } -#if 0 - // FIXME DRANO - kludgy way to avoid overwriting avatar state from wearables. - if (isUsingServerBakes() && !isUsingLocalAppearance()) - { - return FALSE; - } -#endif - if (param->getCrossWearable()) { LLWearableType::EType type = (LLWearableType::EType)param->getWearableType(); @@ -702,12 +704,12 @@ BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight LLViewerWearable *wearable = gAgentWearables.getViewerWearable(type,count); if (wearable) { - wearable->setVisualParamWeight(param->getID(), weight, upload_bake); + wearable->setVisualParamWeight(param->getID(), weight); } } } - return LLCharacter::setVisualParamWeight(param,weight,upload_bake); + return LLCharacter::setVisualParamWeight(param,weight); } /*virtual*/ @@ -720,7 +722,7 @@ void LLVOAvatarSelf::updateVisualParams() void LLVOAvatarSelf::idleUpdateAppearanceAnimation() { // Animate all top-level wearable visual parameters - gAgentWearables.animateAllWearableParams(calcMorphAmount(), FALSE); + gAgentWearables.animateAllWearableParams(calcMorphAmount()); // apply wearable visual params to avatar for (U32 type = 0; type < LLWearableType::WT_COUNT; type++) @@ -762,57 +764,6 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id) } } -//virtual -U32 LLVOAvatarSelf::processUpdateMessage(LLMessageSystem *mesgsys, - void **user_data, - U32 block_num, - const EObjectUpdateType update_type, - LLDataPacker *dp) -{ - U32 retval = LLVOAvatar::processUpdateMessage(mesgsys,user_data,block_num,update_type,dp); - -#if 0 - // DRANO - it's not clear this does anything useful. If we wait - // until an appearance message has been received, we already have - // the texture ids. If we don't wait, we don't yet know where to - // look for baked textures, because we haven't received the - // appearance version data from the appearance message. This looks - // like an old optimization that's incompatible with server-side - // texture baking. - - // FIXME DRANO - skipping in the case of !mFirstAppearanceMessageReceived prevents us from trying to - // load textures before we know where they come from (ie, from baking service or not); - // unknown impact on performance. - if (mInitialBakesLoaded == false && retval == 0x0 && mFirstAppearanceMessageReceived) - { - // call update textures to force the images to be created - updateMeshTextures(); - - // unpack the texture UUIDs to the texture slots - if(mesgsys != NULL) - { - retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, (S32) block_num); - } - - // need to trigger a few operations to get the avatar to use the new bakes - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - const LLAvatarAppearanceDefines::ETextureIndex te = mBakedTextureDatas[i].mTextureIndex; - LLUUID texture_id = getTEImage(te)->getID(); - setNewBakedTexture(te, texture_id); - mInitialBakeIDs[i] = texture_id; - } - - onFirstTEMessageReceived(); - - mInitialBakesLoaded = true; - } -#endif - - return retval; -} - - void LLVOAvatarSelf::setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index) { if (te >= TEX_NUM_INDICES) @@ -864,13 +815,9 @@ void LLVOAvatarSelf::removeMissingBakedTextures() { LLViewerTexLayerSet *layerset = getTexLayerSet(i); layerset->setUpdatesEnabled(TRUE); - invalidateComposite(layerset, FALSE); - } - updateMeshTextures(); // may call back into this function - if (getRegion() && !getRegion()->getCentralBakeVersion()) - { - requestLayerSetUploads(); + invalidateComposite(layerset); } + updateMeshTextures(); } } @@ -1039,7 +986,7 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode) // forces an update to any baked textures relevant to type. // will force an upload of the resulting bake if the second parameter is TRUE //----------------------------------------------------------------------------- -void LLVOAvatarSelf::wearableUpdated( LLWearableType::EType type, BOOL upload_result ) +void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type) { for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); @@ -1061,20 +1008,13 @@ void LLVOAvatarSelf::wearableUpdated( LLWearableType::EType type, BOOL upload_re if (layerset) { layerset->setUpdatesEnabled(true); - invalidateComposite(layerset, upload_result); + invalidateComposite(layerset); } break; } } } } - - // Physics type has no associated baked textures, but change of params needs to be sent to - // other avatars. - if (type == LLWearableType::WT_PHYSICS) - { - gAgent.sendAgentSetAppearance(); - } } //----------------------------------------------------------------------------- @@ -1486,15 +1426,6 @@ BOOL LLVOAvatarSelf::isAllLocalTextureDataFinal() const return TRUE; } -BOOL LLVOAvatarSelf::isBakedTextureFinal(const LLAvatarAppearanceDefines::EBakedTextureIndex index) const -{ - const LLViewerTexLayerSet *layerset = getLayerSet(index); - if (!layerset) return FALSE; - const LLViewerTexLayerSetBuffer *layerset_buffer = layerset->getViewerComposite(); - if (!layerset_buffer) return FALSE; - return !layerset_buffer->uploadNeeded(); -} - BOOL LLVOAvatarSelf::isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const { LLUUID id; @@ -1552,49 +1483,12 @@ BOOL LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex t return isTextureVisible(type,index); } - -//----------------------------------------------------------------------------- -// requestLayerSetUploads() -//----------------------------------------------------------------------------- -void LLVOAvatarSelf::requestLayerSetUploads() -{ - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - requestLayerSetUpload((EBakedTextureIndex)i); - } -} - -void LLVOAvatarSelf::requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i) -{ - ETextureIndex tex_index = mBakedTextureDatas[i].mTextureIndex; - const BOOL layer_baked = isTextureDefined(tex_index, gAgentWearables.getWearableCount(tex_index)); - LLViewerTexLayerSet *layerset = getLayerSet(i); - if (!layer_baked && layerset) - { - layerset->requestUpload(); - } -} - bool LLVOAvatarSelf::areTexturesCurrent() const { - return !hasPendingBakedUploads() && gAgentWearables.areWearablesLoaded(); + return gAgentWearables.areWearablesLoaded(); } -// virtual -bool LLVOAvatarSelf::hasPendingBakedUploads() const -{ - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - LLViewerTexLayerSet* layerset = getTexLayerSet(i); - if (layerset && layerset->getViewerComposite() && layerset->getViewerComposite()->uploadPending()) - { - return true; - } - } - return false; -} - -void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result ) +void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset) { LLViewerTexLayerSet *layer_set = dynamic_cast<LLViewerTexLayerSet*>(layerset); if( !layer_set || !layer_set->getUpdatesEnabled() ) @@ -1605,16 +1499,6 @@ void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_r layer_set->requestUpdate(); layer_set->invalidateMorphMasks(); - - if( upload_result && (getRegion() && !getRegion()->getCentralBakeVersion())) - { - llassert(isSelf()); - - ETextureIndex baked_te = getBakedTE( layer_set ); - setTEImage( baked_te, LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR) ); - layer_set->requestUpload(); - updateMeshTextures(); - } } void LLVOAvatarSelf::invalidateAll() @@ -1622,7 +1506,7 @@ void LLVOAvatarSelf::invalidateAll() for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { LLViewerTexLayerSet *layerset = getTexLayerSet(i); - invalidateComposite(layerset, TRUE); + invalidateComposite(layerset); } //mDebugSelfLoadTimer.reset(); } @@ -2033,7 +1917,10 @@ BOOL LLVOAvatarSelf::getIsCloud() const /*static*/ void LLVOAvatarSelf::debugOnTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) { - gAgentAvatarp->debugTimingLocalTexLoaded(success, src_vi, src, aux_src, discard_level, final, userdata); + if (gAgentAvatarp.notNull()) + { + gAgentAvatarp->debugTimingLocalTexLoaded(success, src_vi, src, aux_src, discard_level, final, userdata); + } } void LLVOAvatarSelf::debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) @@ -2217,27 +2104,9 @@ const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const return text; } - -#if 0 -// Dump avatar metrics data. -LLSD LLVOAvatarSelf::metricsData() -{ - // runway - add region info - LLSD result; - result["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus()); - result["timers"]["debug_existence"] = mDebugExistenceTimer.getElapsedTimeF32(); - result["timers"]["ruth_debug"] = mRuthDebugTimer.getElapsedTimeF32(); - result["timers"]["ruth"] = mRuthTimer.getElapsedTimeF32(); - result["timers"]["invisible"] = mInvisibleTimer.getElapsedTimeF32(); - result["timers"]["fully_loaded"] = mFullyLoadedTimer.getElapsedTimeF32(); - result["startup"] = LLStartUp::getPhases().asLLSD(); - - return result; -} -#endif - class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder { + LOG_CLASS(ViewerAppearanceChangeMetricsResponder); public: ViewerAppearanceChangeMetricsResponder( S32 expected_sequence, volatile const S32 & live_sequence, @@ -2248,32 +2117,25 @@ public: { } - virtual void completed(U32 status, - const std::string& reason, - const LLSD& content) +private: + /* virtual */ void httpSuccess() { - gPendingMetricsUploads--; // if we add retry, this should be moved to the isGoodStatus case. - if (isGoodStatus(status)) - { - LL_DEBUGS("Avatar") << "OK" << LL_ENDL; - result(content); - } - else - { - LL_WARNS("Avatar") << "Failed " << status << " reason " << reason << LL_ENDL; - errorWithContent(status,reason,content); - } - } + LL_DEBUGS("Avatar") << "OK" << LL_ENDL; - // virtual - void result(const LLSD & content) - { + gPendingMetricsUploads--; if (mLiveSequence == mExpectedSequence) { mReportingStarted = true; } } + /* virtual */ void httpFailure() + { + // if we add retry, this should be removed from the httpFailure case + LL_WARNS("Avatar") << dumpResponse() << LL_ENDL; + gPendingMetricsUploads--; + } + private: S32 mExpectedSequence; volatile const S32 & mLiveSequence; @@ -2356,11 +2218,10 @@ LLSD summarize_by_buckets(std::vector<LLSD> in_records, void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics() { - // gAgentAvatarp->stopAllPhases(); static volatile bool reporting_started(false); static volatile S32 report_sequence(0); - LLSD msg; // = metricsData(); + LLSD msg; msg["message"] = "ViewerAppearanceChangeMetrics"; msg["session_id"] = gAgentSessionID; msg["agent_id"] = gAgentID; @@ -2420,63 +2281,6 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics() } } -class CheckAgentAppearanceServiceResponder: public LLHTTPClient::Responder -{ -public: - CheckAgentAppearanceServiceResponder() - { - } - - virtual ~CheckAgentAppearanceServiceResponder() - { - } - - /* virtual */ void result(const LLSD& content) - { - LL_DEBUGS("Avatar") << "status OK" << LL_ENDL; - } - - // Error - /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - { - if (isAgentAvatarValid()) - { - LL_DEBUGS("Avatar") << "failed, will rebake [status:" - << status << "]: " << content << LL_ENDL; - forceAppearanceUpdate(); - } - } - - static void forceAppearanceUpdate() - { - // Trying to rebake immediately after crossing region boundary - // seems to be failure prone; adding a delay factor. Yes, this - // fix is ad-hoc and not guaranteed to work in all cases. - doAfterInterval(boost::bind(&LLVOAvatarSelf::forceBakeAllTextures, - gAgentAvatarp.get(), true), 5.0); - } -}; - -void LLVOAvatarSelf::checkForUnsupportedServerBakeAppearance() -{ - // Need to check only if we have a server baked appearance and are - // in a non-baking region. - if (!gAgentAvatarp->isUsingServerBakes()) - return; - if (!gAgent.getRegion() || gAgent.getRegion()->getCentralBakeVersion()!=0) - return; - - // if baked image service is unknown, need to refresh. - if (LLAppearanceMgr::instance().getAppearanceServiceURL().empty()) - { - CheckAgentAppearanceServiceResponder::forceAppearanceUpdate(); - } - // query baked image service to check status. - std::string image_url = gAgentAvatarp->getImageURL(TEX_HEAD_BAKED, - getTE(TEX_HEAD_BAKED)->getID()); - LLHTTPClient::head(image_url, new CheckAgentAppearanceServiceResponder); -} - const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const { if (canGrabBakedTexture(baked_index)) @@ -2587,7 +2391,7 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe imagep->setBoostLevel(getAvatarBoostLevel()); imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ; imagep->resetTextureStats(); - imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); + imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL); imagep->addTextureStats( desired_pixels / texel_area_ratio ); imagep->forceUpdateBindStats() ; if (imagep->getDiscardLevel() < 0) @@ -2633,82 +2437,6 @@ ETextureIndex LLVOAvatarSelf::getBakedTE( const LLViewerTexLayerSet* layerset ) return TEX_HEAD_BAKED; } - -void LLVOAvatarSelf::setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid) -{ - ETextureIndex index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(i); - setNewBakedTexture(index, uuid); -} - - -//----------------------------------------------------------------------------- -// setNewBakedTexture() -// A new baked texture has been successfully uploaded and we can start using it now. -//----------------------------------------------------------------------------- -void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid ) -{ - // Baked textures live on other sims. - LLHost target_host = getObjectHost(); - setTEImage( te, LLViewerTextureManager::getFetchedTextureFromHost( uuid, FTT_HOST_BAKE, target_host ) ); - updateMeshTextures(); - dirtyMesh(); - - LLVOAvatar::cullAvatarsByPixelArea(); - - /* switch(te) - case TEX_HEAD_BAKED: - LL_INFOS() << "New baked texture: HEAD" << LL_ENDL; */ - const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(te); - if (texture_dict->mIsBakedTexture) - { - debugBakedTextureUpload(texture_dict->mBakedTextureIndex, TRUE); // FALSE for start of upload, TRUE for finish. - LL_INFOS() << "New baked texture: " << texture_dict->mName << " UUID: " << uuid <<LL_ENDL; - } - else - { - LL_WARNS() << "New baked texture: unknown te " << te << LL_ENDL; - } - - // dumpAvatarTEs( "setNewBakedTexture() send" ); - // RN: throttle uploads - if (!hasPendingBakedUploads()) - { - gAgent.sendAgentSetAppearance(); - - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) - { - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["TIME"] = llformat("%d",(U32)mDebugSelfLoadTimer.getElapsedTimeF32()); - if (isAllLocalTextureDataFinal()) - { - LLNotificationsUtil::add("AvatarRezSelfBakedDoneNotification",args); - LL_DEBUGS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() - << "sec ]" - << avString() - << "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32() - << " SelfLoadTimer " << (U32)mDebugSelfLoadTimer.getElapsedTimeF32() - << " Notification " << "AvatarRezSelfBakedDoneNotification" - << LL_ENDL; - } - else - { - args["STATUS"] = debugDumpAllLocalTextureDataInfo(); - LLNotificationsUtil::add("AvatarRezSelfBakedUpdateNotification",args); - LL_DEBUGS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() - << "sec ]" - << avString() - << "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32() - << " SelfLoadTimer " << (U32)mDebugSelfLoadTimer.getElapsedTimeF32() - << " Notification " << "AvatarRezSelfBakedUpdateNotification" - << LL_ENDL; - } - } - - outputRezDiagnostics(); - } -} - // FIXME: This is not called consistently. Something may be broken. void LLVOAvatarSelf::outputRezDiagnostics() const { @@ -2784,89 +2512,7 @@ void LLVOAvatarSelf::reportAvatarRezTime() const // TODO: report mDebugSelfLoadTimer.getElapsedTimeF32() somehow. } -//----------------------------------------------------------------------------- -// setCachedBakedTexture() -// A baked texture id was received from a cache query, make it active -//----------------------------------------------------------------------------- -void LLVOAvatarSelf::setCachedBakedTexture( ETextureIndex te, const LLUUID& uuid ) -{ - setTETexture( te, uuid ); - - /* switch(te) - case TEX_HEAD_BAKED: - if( mHeadLayerSet ) - mHeadLayerSet->cancelUpload(); */ - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - LLViewerTexLayerSet *layerset = getTexLayerSet(i); - if ( mBakedTextureDatas[i].mTextureIndex == te && layerset) - { - if (mInitialBakeIDs[i] != LLUUID::null) - { - if (mInitialBakeIDs[i] == uuid) - { - LL_INFOS() << "baked texture correctly loaded at login! " << i << LL_ENDL; - } - else - { - LL_WARNS() << "baked texture does not match id loaded at login!" << i << LL_ENDL; - } - mInitialBakeIDs[i] = LLUUID::null; - } - layerset->cancelUpload(); - } - } -} - -// static -void LLVOAvatarSelf::processRebakeAvatarTextures(LLMessageSystem* msg, void**) -{ - LLUUID texture_id; - msg->getUUID("TextureData", "TextureID", texture_id); - if (!isAgentAvatarValid()) return; - - // If this is a texture corresponding to one of our baked entries, - // just rebake that layer set. - BOOL found = FALSE; - - /* ETextureIndex baked_texture_indices[BAKED_NUM_INDICES] = - TEX_HEAD_BAKED, - TEX_UPPER_BAKED, */ - for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); - ++iter) - { - const ETextureIndex index = iter->first; - const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; - if (texture_dict->mIsBakedTexture) - { - if (texture_id == gAgentAvatarp->getTEImage(index)->getID()) - { - LLViewerTexLayerSet* layer_set = gAgentAvatarp->getLayerSet(index); - if (layer_set) - { - LL_INFOS() << "TAT: rebake - matched entry " << (S32)index << LL_ENDL; - gAgentAvatarp->invalidateComposite(layer_set, TRUE); - found = TRUE; - add(LLStatViewer::TEX_REBAKES, 1); - } - } - } - } - - // If texture not found, rebake all entries. - if (!found) - { - gAgentAvatarp->forceBakeAllTextures(); - } - else - { - // Not sure if this is necessary, but forceBakeAllTextures() does it. - gAgentAvatarp->updateMeshTextures(); - } -} - - +// SUNSHINE CLEANUP - not clear we need any of this, may be sufficient to request server appearance in llviewermenu.cpp:handle_rebake_textures() void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug) { LL_INFOS() << "TAT: forced full rebake. " << LL_ENDL; @@ -2880,10 +2526,9 @@ void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug) if (slam_for_debug) { layer_set->setUpdatesEnabled(TRUE); - layer_set->cancelUpload(); } - invalidateComposite(layer_set, TRUE); + invalidateComposite(layer_set); add(LLStatViewer::TEX_REBAKES, 1); } else @@ -2952,6 +2597,11 @@ void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch) { if (isAgentAvatarValid()) { + if (!gAgentAvatarp->mEndCustomizeCallback.get()) + { + gAgentAvatarp->mEndCustomizeCallback = new LLUpdateAppearanceOnDestroy; + } + gAgentAvatarp->mIsEditingAppearance = true; gAgentAvatarp->mUseLocalAppearance = true; @@ -2978,12 +2628,6 @@ void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch) if (isAgentAvatarValid()) { gAgentAvatarp->mIsEditingAppearance = false; - if (gAgentAvatarp->getRegion() && !gAgentAvatarp->getRegion()->getCentralBakeVersion()) - { - // FIXME DRANO - move to sendAgentSetAppearance, make conditional on upload complete. - gAgentAvatarp->mUseLocalAppearance = false; - } - gAgentAvatarp->invalidateAll(); if (gSavedSettings.getBOOL("AppearanceCameraMovement") && !disable_camera_switch) @@ -2991,8 +2635,11 @@ void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch) gAgentCamera.changeCameraToDefault(); gAgentCamera.resetView(); } - - LLAppearanceMgr::instance().updateAppearanceFromCOF(); + + // Dereferencing the previous callback will cause + // updateAppearanceFromCOF to be called, whenever all refs + // have resolved. + gAgentAvatarp->mEndCustomizeCallback = NULL; } } diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 444175b62e..e03de9fa0b 100755 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -33,6 +33,7 @@ #include <map> struct LocalTextureData; +class LLInventoryCallback; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -87,21 +88,15 @@ public: void resetJointPositions( void ); - /*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE ); - /*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE ); - /*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE ); + /*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight); + /*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight); + /*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight); /*virtual*/ void updateVisualParams(); /*virtual*/ void idleUpdateAppearanceAnimation(); - /*virtual*/ U32 processUpdateMessage(LLMessageSystem *mesgsys, - void **user_data, - U32 block_num, - const EObjectUpdateType update_type, - LLDataPacker *dp); - private: // helper function. Passed in param is assumed to be in avatar's parameter list. - BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake = FALSE ); + BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight); @@ -129,6 +124,7 @@ public: public: /*virtual*/ BOOL updateCharacter(LLAgent &agent); /*virtual*/ void idleUpdateTractorBeam(); + bool checkStuckAppearance(); //-------------------------------------------------------------------- // Loading state @@ -185,12 +181,10 @@ public: // Loading status //-------------------------------------------------------------------- public: - /*virtual*/ bool hasPendingBakedUploads() const; S32 getLocalDiscardLevel(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const; bool areTexturesCurrent() const; BOOL isLocalTextureDataAvailable(const LLViewerTexLayerSet* layerset) const; BOOL isLocalTextureDataFinal(const LLViewerTexLayerSet* layerset) const; - BOOL isBakedTextureFinal(const LLAvatarAppearanceDefines::EBakedTextureIndex index) const; // If you want to check all textures of a given type, pass gAgentWearables.getWearableCount() for index /*virtual*/ BOOL isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const; /*virtual*/ BOOL isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, U32 index = 0) const; @@ -225,11 +219,8 @@ private: //-------------------------------------------------------------------- public: LLAvatarAppearanceDefines::ETextureIndex getBakedTE(const LLViewerTexLayerSet* layerset ) const; - void setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid); - void setNewBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i, const LLUUID& uuid); - void setCachedBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i, const LLUUID& uuid); + // SUNSHINE CLEANUP - dead? or update to just call request appearance update? void forceBakeAllTextures(bool slam_for_debug = false); - static void processRebakeAvatarTextures(LLMessageSystem* msg, void**); protected: /*virtual*/ void removeMissingBakedTextures(); @@ -237,8 +228,6 @@ protected: // Layers //-------------------------------------------------------------------- public: - void requestLayerSetUploads(); - void requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i); void requestLayerSetUpdate(LLAvatarAppearanceDefines::ETextureIndex i); LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const; LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::ETextureIndex index) const; @@ -248,7 +237,7 @@ public: // Composites //-------------------------------------------------------------------- public: - /* virtual */ void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result); + /* virtual */ void invalidateComposite(LLTexLayerSet* layerset); /* virtual */ void invalidateAll(); /* virtual */ void setCompositeUpdatesEnabled(bool b); // only works for self /* virtual */ void setCompositeUpdatesEnabled(U32 index, bool b); @@ -290,7 +279,7 @@ protected: **/ public: - void wearableUpdated(LLWearableType::EType type, BOOL upload_result); + void wearableUpdated(LLWearableType::EType type); protected: U32 getNumWearables(LLAvatarAppearanceDefines::ETextureIndex i) const; @@ -331,6 +320,7 @@ private: public: static void onCustomizeStart(bool disable_camera_switch = false); static void onCustomizeEnd(bool disable_camera_switch = false); + LLPointer<LLInventoryCallback> mEndCustomizeCallback; //-------------------------------------------------------------------- // Visibility @@ -392,7 +382,6 @@ public: const std::string debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const; // Lists out state of this particular baked texture layer const std::string debugDumpAllLocalTextureDataInfo() const; // Lists out which baked textures are at highest LOD void sendViewerAppearanceChangeMetrics(); // send data associated with completing a change. - void checkForUnsupportedServerBakeAppearance(); private: LLFrameTimer mDebugSelfLoadTimer; F32 mDebugTimeWearablesLoaded; diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 312842a70f..3c3dc33772 100755 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -55,26 +55,27 @@ const U32 DEFAULT_RETRIES_COUNT = 3; class LLVoiceCallCapResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLVoiceCallCapResponder); public: LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; +protected: // called with bad status codes - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - virtual void result(const LLSD& content); + virtual void httpFailure(); + virtual void httpSuccess(); private: LLUUID mSessionID; }; -void LLVoiceCallCapResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLVoiceCallCapResponder::httpFailure() { - LL_WARNS("Voice") << "LLVoiceCallCapResponder error [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS("Voice") << dumpResponse() << LL_ENDL; LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); if ( channelp ) { - if ( 403 == status ) + if ( HTTP_FORBIDDEN == getStatus() ) { //403 == no ability LLNotificationsUtil::add( @@ -91,12 +92,18 @@ void LLVoiceCallCapResponder::errorWithContent(U32 status, const std::string& re } } -void LLVoiceCallCapResponder::result(const LLSD& content) +void LLVoiceCallCapResponder::httpSuccess() { LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); if (channelp) { //*TODO: DEBUG SPAM + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLSD::map_const_iterator iter; for(iter = content.beginMap(); iter != content.endMap(); ++iter) { diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 09a2003ef8..9937a1c42a 100755 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -124,17 +124,19 @@ static int scale_speaker_volume(float volume) class LLVivoxVoiceAccountProvisionResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLVivoxVoiceAccountProvisionResponder); public: LLVivoxVoiceAccountProvisionResponder(int retries) { mRetries = retries; } - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +private: + /* virtual */ void httpFailure() { LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, " << ( (mRetries > 0) ? "retrying" : "too many retries (giving up)" ) - << status << "]: " << content << LL_ENDL; + << " " << dumpResponse() << LL_ENDL; if ( mRetries > 0 ) { @@ -146,14 +148,19 @@ public: } } - virtual void result(const LLSD& content) + /* virtual */ void httpSuccess() { - std::string voice_sip_uri_hostname; std::string voice_account_server_uri; - LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; + LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << dumpResponse() << LL_ENDL; + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } if(content.has("voice_sip_uri_hostname")) voice_sip_uri_hostname = content["voice_sip_uri_hostname"].asString(); @@ -166,7 +173,6 @@ public: content["password"].asString(), voice_sip_uri_hostname, voice_account_server_uri); - } private: @@ -190,33 +196,34 @@ static bool sMuteListListener_listening = false; class LLVivoxVoiceClientCapResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLVivoxVoiceClientCapResponder); public: LLVivoxVoiceClientCapResponder(LLVivoxVoiceClient::state requesting_state) : mRequestingState(requesting_state) {}; +private: // called with bad status codes - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - virtual void result(const LLSD& content); + /* virtual */ void httpFailure(); + /* virtual */ void httpSuccess(); -private: LLVivoxVoiceClient::state mRequestingState; // state }; -void LLVivoxVoiceClientCapResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLVivoxVoiceClientCapResponder::httpFailure() { - LL_WARNS("Voice") << "LLVivoxVoiceClientCapResponder error [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS("Voice") << dumpResponse() << LL_ENDL; LLVivoxVoiceClient::getInstance()->sessionTerminate(); } -void LLVivoxVoiceClientCapResponder::result(const LLSD& content) +void LLVivoxVoiceClientCapResponder::httpSuccess() { LLSD::map_const_iterator iter; - LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; + LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << dumpResponse() << LL_ENDL; std::string uri; std::string credentials; + const LLSD& content = getContent(); if ( content.has("voice_credentials") ) { LLSD voice_credentials = content["voice_credentials"]; @@ -2651,7 +2658,7 @@ void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString // Status code of 20200 means "bad password". We may want to special-case that at some point. - if ( statusCode == 401 ) + if ( statusCode == HTTP_UNAUTHORIZED ) { // Login failure which is probably caused by the delay after a user's password being updated. LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL; @@ -3153,7 +3160,7 @@ void LLVivoxVoiceClient::mediaStreamUpdatedEvent( switch(statusCode) { case 0: - case 200: + case HTTP_OK: // generic success // Don't change the saved error code (it may have been set elsewhere) break; @@ -3426,7 +3433,7 @@ void LLVivoxVoiceClient::messageEvent( LL_DEBUGS("Voice") << "Message event, session " << sessionHandle << " from " << uriString << LL_ENDL; // LL_DEBUGS("Voice") << " header " << messageHeader << ", body: \n" << messageBody << LL_ENDL; - if(messageHeader.find("text/html") != std::string::npos) + if(messageHeader.find(HTTP_CONTENT_TEXT_HTML) != std::string::npos) { std::string message; @@ -5393,9 +5400,10 @@ void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::ESta { switch(mAudioSession->mErrorStatusCode) { - case 404: // NOT_FOUND + case HTTP_NOT_FOUND: // NOT_FOUND + // *TODO: Should this be 503? case 480: // TEMPORARILY_UNAVAILABLE - case 408: // REQUEST_TIMEOUT + case HTTP_REQUEST_TIME_OUT: // REQUEST_TIMEOUT // call failed because other user was not available // treat this as an error case status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index d1108020ff..945d3711f0 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -82,7 +82,7 @@ const S32 MIN_QUIET_FRAMES_COALESCE = 30; const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; const F32 FORCE_CULL_AREA = 8.f; const F32 MAX_LOD_DISTANCE = 24.f; - +U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 20; BOOL gAnimateTextures = TRUE; //extern BOOL gHideSelectedObjects; @@ -4059,7 +4059,8 @@ U32 LLVOVolume::getPartitionType() const } LLVolumePartition::LLVolumePartition(LLViewerRegion* regionp) -: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB, regionp) +: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB, regionp), +LLVolumeGeometryManager() { mLODPeriod = 32; mDepthMask = FALSE; @@ -4070,7 +4071,8 @@ LLVolumePartition::LLVolumePartition(LLViewerRegion* regionp) } LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep, LLViewerRegion* regionp) -: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK, regionp) +: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK, regionp), +LLVolumeGeometryManager() { mDepthMask = FALSE; mLODPeriod = 32; @@ -4107,6 +4109,70 @@ bool can_batch_texture(LLFace* facep) return true; } +const static U32 MAX_FACE_COUNT = 4096U; +int32_t LLVolumeGeometryManager::sInstanceCount = 0; +LLFace** LLVolumeGeometryManager::sFullbrightFaces = NULL; +LLFace** LLVolumeGeometryManager::sBumpFaces = NULL; +LLFace** LLVolumeGeometryManager::sSimpleFaces = NULL; +LLFace** LLVolumeGeometryManager::sNormFaces = NULL; +LLFace** LLVolumeGeometryManager::sSpecFaces = NULL; +LLFace** LLVolumeGeometryManager::sNormSpecFaces = NULL; +LLFace** LLVolumeGeometryManager::sAlphaFaces = NULL; + +LLVolumeGeometryManager::LLVolumeGeometryManager() + : LLGeometryManager() +{ + llassert(sInstanceCount >= 0); + if (sInstanceCount == 0) + { + allocateFaces(MAX_FACE_COUNT); + } + + ++sInstanceCount; +} + +LLVolumeGeometryManager::~LLVolumeGeometryManager() +{ + llassert(sInstanceCount > 0); + --sInstanceCount; + + if (sInstanceCount <= 0) + { + freeFaces(); + sInstanceCount = 0; + } +} + +void LLVolumeGeometryManager::allocateFaces(U32 pMaxFaceCount) +{ + sFullbrightFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + sBumpFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + sSimpleFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + sNormFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + sSpecFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + sNormSpecFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + sAlphaFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); +} + +void LLVolumeGeometryManager::freeFaces() +{ + ll_aligned_free<64>(sFullbrightFaces); + ll_aligned_free<64>(sBumpFaces); + ll_aligned_free<64>(sSimpleFaces); + ll_aligned_free<64>(sNormFaces); + ll_aligned_free<64>(sSpecFaces); + ll_aligned_free<64>(sNormSpecFaces); + ll_aligned_free<64>(sAlphaFaces); + + sFullbrightFaces = NULL; + sBumpFaces = NULL; + sSimpleFaces = NULL; + sNormFaces = NULL; + sSpecFaces = NULL; + sNormSpecFaces = NULL; + sAlphaFaces = NULL; +} + static LLTrace::BlockTimerStatHandle FTM_REGISTER_FACE("Register Face"); void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type) @@ -4429,16 +4495,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) mFaceList.clear(); - const U32 MAX_FACE_COUNT = 4096; - - static LLFace** fullbright_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); - static LLFace** bump_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); - static LLFace** simple_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); - static LLFace** norm_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); - static LLFace** spec_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); - static LLFace** normspec_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); - static LLFace** alpha_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); - U32 fullbright_count = 0; U32 bump_count = 0; U32 simple_count = 0; @@ -4458,7 +4514,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) bool emissive = false; - + //Determine if we've received skininfo that contains an + //alternate bind matrix - if it does then apply the translational component + //to the joints of the avatar. + bool pelvisGotSet = false; { LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_FACE_LIST); @@ -4541,18 +4600,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) is_rigged = true; //get drawpool of avatar with rigged face - LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); - - //Determine if we've received skininfo that contains an - //alternate bind matrix - if it does then apply the translational component - //to the joints of the avatar. - bool pelvisGotSet = false; - + LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); + if ( pAvatarVO ) { - LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); + LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); - if ( pSkinData ) { const int bindCnt = pSkinData->mAlternateBindMatrix.size(); @@ -4560,43 +4613,42 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { const int jointCnt = pSkinData->mJointNames.size(); const F32 pelvisZOffset = pSkinData->mPelvisOffset; - bool fullRig = (jointCnt>=20) ? true : false; + bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false; if ( fullRig ) - { + { for ( int i=0; i<jointCnt; ++i ) { std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); - //LL_INFOS()<<"joint name "<<lookingForJoint.c_str()<<LL_ENDL; LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint ); if ( pJoint && pJoint->getId() != currentId ) { pJoint->setId( currentId ); const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); + //Set the joint position - pJoint->storeCurrentXform( jointPos ); + pJoint->storeCurrentXform( jointPos ); + //If joint is a pelvis then handle old/new pelvis to foot values if ( lookingForJoint == "mPelvis" ) { - pJoint->storeCurrentXform( jointPos ); if ( !pAvatarVO->hasPelvisOffset() ) { pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); - //Trigger to rebuild viewer AV pelvisGotSet = true; } } - } - } + } + } } } } } - //If we've set the pelvis to a new position we need to also rebuild some information that the - //viewer does at launch (e.g. body size etc.) - if ( pelvisGotSet ) + + //Rebuild body data if we altered joints/pelvis + if ( pelvisGotSet && pAvatarVO ) { pAvatarVO->postPelvisSetRecalc(); - } + } if (pool) { @@ -4820,7 +4872,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { //can be treated as alpha mask if (simple_count < MAX_FACE_COUNT) { - simple_faces[simple_count++] = facep; + sSimpleFaces[simple_count++] = facep; } } else @@ -4831,7 +4883,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } if (alpha_count < MAX_FACE_COUNT) { - alpha_faces[alpha_count++] = facep; + sAlphaFaces[alpha_count++] = facep; } } } @@ -4854,14 +4906,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { //has normal and specular maps (needs texcoord1, texcoord2, and tangent) if (normspec_count < MAX_FACE_COUNT) { - normspec_faces[normspec_count++] = facep; + sNormSpecFaces[normspec_count++] = facep; } } else { //has normal map (needs texcoord1 and tangent) if (norm_count < MAX_FACE_COUNT) { - norm_faces[norm_count++] = facep; + sNormFaces[norm_count++] = facep; } } } @@ -4869,14 +4921,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { //has specular map but no normal map, needs texcoord2 if (spec_count < MAX_FACE_COUNT) { - spec_faces[spec_count++] = facep; + sSpecFaces[spec_count++] = facep; } } else { //has neither specular map nor normal map, only needs texcoord0 if (simple_count < MAX_FACE_COUNT) { - simple_faces[simple_count++] = facep; + sSimpleFaces[simple_count++] = facep; } } } @@ -4884,14 +4936,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { //needs normal + tangent if (bump_count < MAX_FACE_COUNT) { - bump_faces[bump_count++] = facep; + sBumpFaces[bump_count++] = facep; } } else if (te->getShiny() || !te->getFullbright()) { //needs normal if (simple_count < MAX_FACE_COUNT) { - simple_faces[simple_count++] = facep; + sSimpleFaces[simple_count++] = facep; } } else @@ -4899,7 +4951,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) facep->setState(LLFace::FULLBRIGHT); if (fullbright_count < MAX_FACE_COUNT) { - fullbright_faces[fullbright_count++] = facep; + sFullbrightFaces[fullbright_count++] = facep; } } } @@ -4909,7 +4961,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { //needs normal + tangent if (bump_count < MAX_FACE_COUNT) { - bump_faces[bump_count++] = facep; + sBumpFaces[bump_count++] = facep; } } else if ((te->getShiny() && LLPipeline::sRenderBump) || @@ -4917,7 +4969,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { //needs normal if (simple_count < MAX_FACE_COUNT) { - simple_faces[simple_count++] = facep; + sSimpleFaces[simple_count++] = facep; } } else @@ -4925,7 +4977,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) facep->setState(LLFace::FULLBRIGHT); if (fullbright_count < MAX_FACE_COUNT) { - fullbright_faces[fullbright_count++] = facep; + sFullbrightFaces[fullbright_count++] = facep; } } } @@ -4952,7 +5004,16 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { drawablep->clearState(LLDrawable::RIGGED); } + } + + + + + + + + } group->mBufferUsage = useage; @@ -4988,13 +5049,13 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) fullbright_mask = fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX; } - genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, simple_faces, simple_count, FALSE, batch_textures, FALSE); - genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, fullbright_faces, fullbright_count, FALSE, batch_textures); - genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, alpha_faces, alpha_count, TRUE, batch_textures); - genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, bump_count, FALSE, FALSE); - genDrawInfo(group, norm_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, norm_faces, norm_count, FALSE, FALSE); - genDrawInfo(group, spec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, spec_faces, spec_count, FALSE, FALSE); - genDrawInfo(group, normspec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, normspec_faces, normspec_count, FALSE, FALSE); + genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sSimpleFaces, simple_count, FALSE, batch_textures, FALSE); + genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sFullbrightFaces, fullbright_count, FALSE, batch_textures); + genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sAlphaFaces, alpha_count, TRUE, batch_textures); + genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sBumpFaces, bump_count, FALSE, FALSE); + genDrawInfo(group, norm_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sNormFaces, norm_count, FALSE, FALSE); + genDrawInfo(group, spec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sSpecFaces, spec_count, FALSE, FALSE); + genDrawInfo(group, normspec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sNormSpecFaces, normspec_count, FALSE, FALSE); if (!LLPipeline::sDelayVBUpdate) { diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index 6085893129..b61fbbd073 100755 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -81,6 +81,7 @@ void LLWearableList::getAsset(const LLAssetID& assetID, const std::string& weara LLViewerWearable* instance = get_if_there(mList, assetID, (LLViewerWearable*)NULL ); if( instance ) { + LL_DEBUGS("Avatar") << "wearable " << assetID << " found in LLWearableList" << LL_ENDL; asset_arrived_callback( instance, userdata ); } else diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 0cf0e7b9c0..ddb7f7bfce 100755 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -67,9 +67,8 @@ public: { } + // *TODO: Check for 'application/json' content type, and parse json at the base class. /*virtual*/ void completedRaw( - U32 status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { @@ -78,9 +77,9 @@ public: strstrm << istr.rdbuf(); const std::string body = strstrm.str(); - if (status != 200) + if (getStatus() != HTTP_OK) { - LL_WARNS() << "Failed to get upload config (" << status << ")" << LL_ENDL; + LL_WARNS() << "Failed to get upload config " << dumpResponse() << LL_ENDL; LLWebProfile::reportImageUploadStatus(false); return; } @@ -128,14 +127,12 @@ class LLWebProfileResponders::PostImageRedirectResponder : public LLHTTPClient:: public: /*virtual*/ void completedRaw( - U32 status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - if (status != 200) + if (getStatus() != HTTP_OK) { - LL_WARNS() << "Failed to upload image: " << status << " " << reason << LL_ENDL; + LL_WARNS() << "Failed to upload image " << dumpResponse() << LL_ENDL; LLWebProfile::reportImageUploadStatus(false); return; } @@ -158,33 +155,36 @@ class LLWebProfileResponders::PostImageResponder : public LLHTTPClient::Responde LOG_CLASS(LLWebProfileResponders::PostImageResponder); public: - /*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + /*virtual*/ void completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { // Viewer seems to fail to follow a 303 redirect on POST request // (URLRequest Error: 65, Send failed since rewinding of the data stream failed). // Handle it manually. - if (status == 303) + if (getStatus() == HTTP_SEE_OTHER) { LLSD headers = LLViewerMedia::getHeaders(); - headers["Cookie"] = LLWebProfile::getAuthCookie(); - const std::string& redir_url = content["location"]; - LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << LL_ENDL; - LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder(), headers); + headers[HTTP_OUT_HEADER_COOKIE] = LLWebProfile::getAuthCookie(); + const std::string& redir_url = getResponseHeader(HTTP_IN_HEADER_LOCATION); + if (redir_url.empty()) + { + LL_WARNS() << "Received empty redirection URL " << dumpResponse() << LL_ENDL; + LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; + LLWebProfile::reportImageUploadStatus(false); + } + else + { + LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << LL_ENDL; + LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); + } } else { - LL_WARNS() << "Unexpected POST status: " << status << " " << reason << LL_ENDL; - LL_DEBUGS("Snapshots") << "headers: [" << content << "]" << LL_ENDL; + LL_WARNS() << "Unexpected POST response " << dumpResponse() << LL_ENDL; + LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; LLWebProfile::reportImageUploadStatus(false); } } - - // Override just to suppress warnings. - /*virtual*/ void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - } }; /////////////////////////////////////////////////////////////////////////////// @@ -203,7 +203,7 @@ void LLWebProfile::uploadImage(LLPointer<LLImageFormatted> image, const std::str LL_DEBUGS("Snapshots") << "Requesting " << config_url << LL_ENDL; LLSD headers = LLViewerMedia::getHeaders(); - headers["Cookie"] = getAuthCookie(); + headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie(); LLHTTPClient::get(config_url, new LLWebProfileResponders::ConfigResponder(image), headers); } @@ -227,8 +227,8 @@ void LLWebProfile::post(LLPointer<LLImageFormatted> image, const LLSD& config, c const std::string boundary = "----------------------------0123abcdefab"; LLSD headers = LLViewerMedia::getHeaders(); - headers["Cookie"] = getAuthCookie(); - headers["Content-Type"] = "multipart/form-data; boundary=" + boundary; + headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie(); + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "multipart/form-data; boundary=" + boundary; std::ostringstream body; diff --git a/indra/newview/llwebsharing.cpp b/indra/newview/llwebsharing.cpp deleted file mode 100755 index 3a80051b9b..0000000000 --- a/indra/newview/llwebsharing.cpp +++ /dev/null @@ -1,603 +0,0 @@ -/** - * @file llwebsharing.cpp - * @author Aimee - * @brief Web Snapshot Sharing - * - * $LicenseInfo:firstyear=2010&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 "llwebsharing.h" - -#include "llagentui.h" -#include "llbufferstream.h" -#include "llhttpclient.h" -#include "llhttpstatuscodes.h" -#include "llsdserialize.h" -#include "llsdutil.h" -#include "llurl.h" -#include "llviewercontrol.h" - -#include <boost/regex.hpp> -#include <boost/algorithm/string/replace.hpp> - - - -/////////////////////////////////////////////////////////////////////////////// -// -class LLWebSharingConfigResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLWebSharingConfigResponder); -public: - /// Overrides the default LLSD parsing behaviour, to allow parsing a JSON response. - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - LLSD content; - LLBufferStream istr(channels, buffer.get()); - LLPointer<LLSDParser> parser = new LLSDNotationParser(); - - if (parser->parse(istr, content, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) - { - LL_WARNS("WebSharing") << "Failed to deserialize LLSD from JSON response. " << " [" << status << "]: " << reason << LL_ENDL; - } - else - { - completed(status, reason, content); - } - } - - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - { - LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL; - } - - virtual void result(const LLSD& content) - { - LLWebSharing::instance().receiveConfig(content); - } -}; - - - -/////////////////////////////////////////////////////////////////////////////// -// -class LLWebSharingOpenIDAuthResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLWebSharingOpenIDAuthResponder); -public: - /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - completed(status, reason, content); - } - - /* virtual */ void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - /// Left empty to override the default LLSD parsing behaviour. - } - - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - { - if (HTTP_UNAUTHORIZED == status) - { - LL_WARNS("WebSharing") << "AU account not authenticated." << LL_ENDL; - // *TODO: No account found on AU, so start the account creation process here. - } - else - { - LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL; - LLWebSharing::instance().retryOpenIDAuth(); - } - - } - - virtual void result(const LLSD& content) - { - if (content.has("set-cookie")) - { - // OpenID request succeeded and returned a session cookie. - LLWebSharing::instance().receiveSessionCookie(content["set-cookie"].asString()); - } - } -}; - - - -/////////////////////////////////////////////////////////////////////////////// -// -class LLWebSharingSecurityTokenResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLWebSharingSecurityTokenResponder); -public: - /// Overrides the default LLSD parsing behaviour, to allow parsing a JSON response. - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - LLSD content; - LLBufferStream istr(channels, buffer.get()); - LLPointer<LLSDParser> parser = new LLSDNotationParser(); - - if (parser->parse(istr, content, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) - { - LL_WARNS("WebSharing") << "Failed to deserialize LLSD from JSON response. " << " [" << status << "]: " << reason << LL_ENDL; - LLWebSharing::instance().retryOpenIDAuth(); - } - else - { - completed(status, reason, content); - } - } - - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - { - LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL; - LLWebSharing::instance().retryOpenIDAuth(); - } - - virtual void result(const LLSD& content) - { - if (content[0].has("st") && content[0].has("expires")) - { - const std::string& token = content[0]["st"].asString(); - const std::string& expires = content[0]["expires"].asString(); - if (LLWebSharing::instance().receiveSecurityToken(token, expires)) - { - // Sucessfully received a valid security token. - return; - } - } - else - { - LL_WARNS("WebSharing") << "No security token received." << LL_ENDL; - } - - LLWebSharing::instance().retryOpenIDAuth(); - } -}; - - - -/////////////////////////////////////////////////////////////////////////////// -// -class LLWebSharingUploadResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLWebSharingUploadResponder); -public: - /// Overrides the default LLSD parsing behaviour, to allow parsing a JSON response. - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { -/* - // Dump the body, for debugging. - - LLBufferStream istr1(channels, buffer.get()); - std::ostringstream ostr; - std::string body; - - while (istr1.good()) - { - char buf[1024]; - istr1.read(buf, sizeof(buf)); - body.append(buf, istr1.gcount()); - } - LL_DEBUGS("WebSharing") << body << LL_ENDL; -*/ - LLSD content; - LLBufferStream istr(channels, buffer.get()); - LLPointer<LLSDParser> parser = new LLSDNotationParser(); - - if (parser->parse(istr, content, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) - { - LL_WARNS("WebSharing") << "Failed to deserialize LLSD from JSON response. " << " [" << status << "]: " << reason << LL_ENDL; - } - else - { - completed(status, reason, content); - } - } - - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - { - LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL; - } - - virtual void result(const LLSD& content) - { - if (content[0].has("result") && content[0].has("id") && - content[0]["id"].asString() == "newMediaItem") - { - // *TODO: Upload successful, continue from here to post metadata and create AU activity. - } - else - { - LL_WARNS("WebSharing") << "Error [" << content[0]["code"].asString() - << "]: " << content[0]["message"].asString() << LL_ENDL; - } - } -}; - - - -/////////////////////////////////////////////////////////////////////////////// -// -LLWebSharing::LLWebSharing() -: mConfig(), - mSecurityToken(LLSD::emptyMap()), - mEnabled(false), - mRetries(0), - mImage(NULL), - mMetadata(LLSD::emptyMap()) -{ -} - -void LLWebSharing::init() -{ - if (!mEnabled) - { - sendConfigRequest(); - } -} - -bool LLWebSharing::shareSnapshot(LLImageJPEG* snapshot, LLSD& metadata) -{ - LL_INFOS("WebSharing") << metadata << LL_ENDL; - - if (mImage) - { - // *TODO: Handle this possibility properly, queue them up? - LL_WARNS("WebSharing") << "Snapshot upload already in progress." << LL_ENDL; - return false; - } - - mImage = snapshot; - mMetadata = metadata; - - // *TODO: Check whether we have a valid security token already and re-use it. - sendOpenIDAuthRequest(); - return true; -} - -bool LLWebSharing::setOpenIDCookie(const std::string& cookie) -{ - LL_DEBUGS("WebSharing") << "Setting OpenID cookie " << cookie << LL_ENDL; - mOpenIDCookie = cookie; - return validateConfig(); -} - -bool LLWebSharing::receiveConfig(const LLSD& config) -{ - LL_DEBUGS("WebSharing") << "Received config data: " << config << LL_ENDL; - mConfig = config; - return validateConfig(); -} - -bool LLWebSharing::receiveSessionCookie(const std::string& cookie) -{ - LL_DEBUGS("WebSharing") << "Received AU session cookie: " << cookie << LL_ENDL; - mSessionCookie = cookie; - - // Fetch a security token using the new session cookie. - LLWebSharing::instance().sendSecurityTokenRequest(); - - return (!mSessionCookie.empty()); -} - -bool LLWebSharing::receiveSecurityToken(const std::string& token, const std::string& expires) -{ - mSecurityToken["st"] = token; - mSecurityToken["expires"] = LLDate(expires); - - if (!securityTokenIsValid(mSecurityToken)) - { - LL_WARNS("WebSharing") << "Invalid security token received: \"" << token << "\" Expires: " << expires << LL_ENDL; - return false; - } - - LL_DEBUGS("WebSharing") << "Received security token: \"" << token << "\" Expires: " << expires << LL_ENDL; - mRetries = 0; - - // Continue the upload process now that we have a security token. - sendUploadRequest(); - - return true; -} - -void LLWebSharing::sendConfigRequest() -{ - std::string config_url = gSavedSettings.getString("SnapshotConfigURL"); - LL_DEBUGS("WebSharing") << "Requesting Snapshot Sharing config data from: " << config_url << LL_ENDL; - - LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "application/json"; - - LLHTTPClient::get(config_url, new LLWebSharingConfigResponder(), headers); -} - -void LLWebSharing::sendOpenIDAuthRequest() -{ - std::string auth_url = mConfig["openIdAuthUrl"]; - LL_DEBUGS("WebSharing") << "Starting OpenID Auth: " << auth_url << LL_ENDL; - - LLSD headers = LLSD::emptyMap(); - headers["Cookie"] = mOpenIDCookie; - headers["Accept"] = "*/*"; - - // Send request, successful login will trigger fetching a security token. - LLHTTPClient::get(auth_url, new LLWebSharingOpenIDAuthResponder(), headers); -} - -bool LLWebSharing::retryOpenIDAuth() -{ - if (mRetries++ >= MAX_AUTH_RETRIES) - { - LL_WARNS("WebSharing") << "Exceeded maximum number of authorization attempts, aborting." << LL_ENDL; - mRetries = 0; - return false; - } - - LL_WARNS("WebSharing") << "Authorization failed, retrying (" << mRetries << "/" << MAX_AUTH_RETRIES << ")" << LL_ENDL; - sendOpenIDAuthRequest(); - return true; -} - -void LLWebSharing::sendSecurityTokenRequest() -{ - std::string token_url = mConfig["securityTokenUrl"]; - LL_DEBUGS("WebSharing") << "Fetching security token from: " << token_url << LL_ENDL; - - LLSD headers = LLSD::emptyMap(); - headers["Cookie"] = mSessionCookie; - - headers["Accept"] = "application/json"; - headers["Content-Type"] = "application/json"; - - std::ostringstream body; - body << "{ \"gadgets\": [{ \"url\":\"" - << mConfig["gadgetSpecUrl"].asString() - << "\" }] }"; - - // postRaw() takes ownership of the buffer and releases it later. - size_t size = body.str().size(); - U8 *data = new U8[size]; - memcpy(data, body.str().data(), size); - - // Send request, receiving a valid token will trigger snapshot upload. - LLHTTPClient::postRaw(token_url, data, size, new LLWebSharingSecurityTokenResponder(), headers); -} - -void LLWebSharing::sendUploadRequest() -{ - LLUriTemplate upload_template(mConfig["openSocialRpcUrlTemplate"].asString()); - std::string upload_url(upload_template.buildURI(mSecurityToken)); - - LL_DEBUGS("WebSharing") << "Posting upload to: " << upload_url << LL_ENDL; - - static const std::string BOUNDARY("------------abcdef012345xyZ"); - - LLSD headers = LLSD::emptyMap(); - headers["Cookie"] = mSessionCookie; - - headers["Accept"] = "application/json"; - headers["Content-Type"] = "multipart/form-data; boundary=" + BOUNDARY; - - std::ostringstream body; - body << "--" << BOUNDARY << "\r\n" - << "Content-Disposition: form-data; name=\"request\"\r\n\r\n" - << "[{" - << "\"method\":\"mediaItems.create\"," - << "\"params\": {" - << "\"userId\":[\"@me\"]," - << "\"groupId\":\"@self\"," - << "\"mediaItem\": {" - << "\"mimeType\":\"image/jpeg\"," - << "\"type\":\"image\"," - << "\"url\":\"@field:image1\"" - << "}" - << "}," - << "\"id\":\"newMediaItem\"" - << "}]" - << "--" << BOUNDARY << "\r\n" - << "Content-Disposition: form-data; name=\"image1\"\r\n\r\n"; - - // Insert the image data. - // *FIX: Treating this as a string will probably screw it up ... - U8* image_data = mImage->getData(); - for (S32 i = 0; i < mImage->getDataSize(); ++i) - { - body << image_data[i]; - } - - body << "\r\n--" << BOUNDARY << "--\r\n"; - - // postRaw() takes ownership of the buffer and releases it later. - size_t size = body.str().size(); - U8 *data = new U8[size]; - memcpy(data, body.str().data(), size); - - // Send request, successful upload will trigger posting metadata. - LLHTTPClient::postRaw(upload_url, data, size, new LLWebSharingUploadResponder(), headers); -} - -bool LLWebSharing::validateConfig() -{ - // Check the OpenID Cookie has been set. - if (mOpenIDCookie.empty()) - { - mEnabled = false; - return mEnabled; - } - - if (!mConfig.isMap()) - { - mEnabled = false; - return mEnabled; - } - - // Template to match the received config against. - LLSD required(LLSD::emptyMap()); - required["gadgetSpecUrl"] = ""; - required["loginTokenUrl"] = ""; - required["openIdAuthUrl"] = ""; - required["photoPageUrlTemplate"] = ""; - required["openSocialRpcUrlTemplate"] = ""; - required["securityTokenUrl"] = ""; - required["tokenBasedLoginUrlTemplate"] = ""; - required["viewerIdUrl"] = ""; - - std::string mismatch(llsd_matches(required, mConfig)); - if (!mismatch.empty()) - { - LL_WARNS("WebSharing") << "Malformed config data response: " << mismatch << LL_ENDL; - mEnabled = false; - return mEnabled; - } - - mEnabled = true; - return mEnabled; -} - -// static -bool LLWebSharing::securityTokenIsValid(LLSD& token) -{ - return (token.has("st") && - token.has("expires") && - (token["st"].asString() != "") && - (token["expires"].asDate() > LLDate::now())); -} - - - -/////////////////////////////////////////////////////////////////////////////// -// -LLUriTemplate::LLUriTemplate(const std::string& uri_template) - : - mTemplate(uri_template) -{ -} - -std::string LLUriTemplate::buildURI(const LLSD& vars) -{ - // *TODO: Separate parsing the template from building the URI. - // Parsing only needs to happen on construction/assignnment. - - static const std::string VAR_NAME_REGEX("[[:alpha:]][[:alnum:]\\._-]*"); - // Capture var name with and without surrounding {} - static const std::string VAR_REGEX("\\{(" + VAR_NAME_REGEX + ")\\}"); - // Capture delimiter and comma separated list of var names. - static const std::string JOIN_REGEX("\\{-join\\|(&)\\|(" + VAR_NAME_REGEX + "(?:," + VAR_NAME_REGEX + ")*)\\}"); - - std::string uri = mTemplate; - boost::smatch results; - - // Validate and expand join operators : {-join|&|var1,var2,...} - - boost::regex join_regex(JOIN_REGEX); - - while (boost::regex_search(uri, results, join_regex)) - { - // Extract the list of var names from the results. - std::string delim = results[1].str(); - std::string var_list = results[2].str(); - - // Expand the list of vars into a query string with their values - std::string query = expandJoin(delim, var_list, vars); - - // Substitute the query string into the template. - uri = boost::regex_replace(uri, join_regex, query, boost::format_first_only); - } - - // Expand vars : {var1} - - boost::regex var_regex(VAR_REGEX); - - std::set<std::string> var_names; - std::string::const_iterator start = uri.begin(); - std::string::const_iterator end = uri.end(); - - // Extract the var names used. - while (boost::regex_search(start, end, results, var_regex)) - { - var_names.insert(results[1].str()); - start = results[0].second; - } - - // Replace each var with its value. - for (std::set<std::string>::const_iterator it = var_names.begin(); it != var_names.end(); ++it) - { - std::string var = *it; - if (vars.has(var)) - { - boost::replace_all(uri, "{" + var + "}", vars[var].asString()); - } - } - - return uri; -} - -std::string LLUriTemplate::expandJoin(const std::string& delim, const std::string& var_list, const LLSD& vars) -{ - std::ostringstream query; - - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep(","); - tokenizer var_names(var_list, sep); - tokenizer::const_iterator it = var_names.begin(); - - // First var does not need a delimiter - if (it != var_names.end()) - { - const std::string& name = *it; - if (vars.has(name)) - { - // URL encode the value before appending the name=value pair. - query << name << "=" << escapeURL(vars[name].asString()); - } - } - - for (++it; it != var_names.end(); ++it) - { - const std::string& name = *it; - if (vars.has(name)) - { - // URL encode the value before appending the name=value pair. - query << delim << name << "=" << escapeURL(vars[name].asString()); - } - } - - return query.str(); -} - -// static -std::string LLUriTemplate::escapeURL(const std::string& unescaped) -{ - char* escaped = curl_escape(unescaped.c_str(), unescaped.size()); - std::string result = escaped; - curl_free(escaped); - return result; -} - diff --git a/indra/newview/llwebsharing.h b/indra/newview/llwebsharing.h deleted file mode 100755 index ad9c99c224..0000000000 --- a/indra/newview/llwebsharing.h +++ /dev/null @@ -1,224 +0,0 @@ -/** - * @file llwebsharing.h - * @author Aimee - * @brief Web Snapshot Sharing - * - * $LicenseInfo:firstyear=2010&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_LLWEBSHARING_H -#define LL_LLWEBSHARING_H - -#include "llimagejpeg.h" -#include "llsingleton.h" - - - -/** - * @class LLWebSharing - * - * Manages authentication to, and interaction with, a web service allowing the - * upload of snapshot images taken within the viewer, using OpenID and the - * OpenSocial APIs. - * http://www.opensocial.org/Technical-Resources/opensocial-spec-v09/RPC-Protocol.html - */ -class LLWebSharing : public LLSingleton<LLWebSharing> -{ - LOG_CLASS(LLWebSharing); -public: - /* - * Performs initial setup, by requesting config data from the web service if - * it has not already been received. - */ - void init(); - - /* - * @return true if both the OpenID cookie and config data have been received. - */ - bool enabled() const { return mEnabled; }; - - /* - * Sets the OpenID cookie to use for login to the web service. - * - * @param cookie a string containing the OpenID cookie. - * - * @return true if both the OpenID cookie and config data have been received. - */ - bool setOpenIDCookie(const std::string& cookie); - - /* - * Receive config data used to connect to the web service. - * - * @param config an LLSD map of URL templates for the web service end-points. - * - * @return true if both the OpenID cookie and config data have been received. - * - * @see sendConfigRequest() - */ - bool receiveConfig(const LLSD& config); - - /* - * Receive the session cookie from the web service, which is the result of - * the OpenID login process. - * - * @see sendOpenIDAuthRequest() - */ - bool receiveSessionCookie(const std::string& cookie); - - /* - * Receive a security token for the upload service. - * - * @see sendSecurityTokenRequest() - */ - bool receiveSecurityToken(const std::string& token, const std::string& expires); - - /* - * Restarts the authentication process if the maximum number of retries has - * not been exceeded. - * - * @return true if retrying, false if LLWebSharing::MAX_AUTH_RETRIES has been exceeded. - */ - bool retryOpenIDAuth(); - - /* - * Post a snapshot to the upload service. - * - * @return true if accepted for upload, false if already uploading another image. - */ - bool shareSnapshot(LLImageJPEG* snapshot, LLSD& metadata); - -private: - static const S32 MAX_AUTH_RETRIES = 4; - - friend class LLSingleton<LLWebSharing>; - - LLWebSharing(); - ~LLWebSharing() {}; - - /* - * Request a map of URLs and URL templates to the web service end-points. - * - * @see receiveConfig() - */ - void sendConfigRequest(); - - /* - * Initiate the OpenID login process. - * - * @see receiveSessionCookie() - */ - void sendOpenIDAuthRequest(); - - /* - * Request a security token for the upload service. - * - * @see receiveSecurityToken() - */ - void sendSecurityTokenRequest(); - - /* - * Request a security token for the upload service. - * - * @see receiveSecurityToken() - */ - void sendUploadRequest(); - - /* - * Checks all necessary config information has been received, and sets mEnabled. - * - * @return true if both the OpenID cookie and config data have been received. - */ - bool validateConfig(); - - /* - * Checks the security token is present and has not expired. - * - * @param token an LLSD map containing the token string and the time it expires. - * - * @return true if the token is not empty and has not expired. - */ - static bool securityTokenIsValid(LLSD& token); - - std::string mOpenIDCookie; - std::string mSessionCookie; - LLSD mSecurityToken; - - LLSD mConfig; - bool mEnabled; - - LLPointer<LLImageJPEG> mImage; - LLSD mMetadata; - - S32 mRetries; -}; - -/** - * @class LLUriTemplate - * - * @brief Builds complete URIs, given URI template and a map of keys and values - * to use for substition. - * Note: This is only a partial implementation of a draft standard required - * by the web API used by LLWebSharing. - * See: http://tools.ietf.org/html/draft-gregorio-uritemplate-03 - * - * @see LLWebSharing - */ -class LLUriTemplate -{ - LOG_CLASS(LLUriTemplate); -public: - LLUriTemplate(const std::string& uri_template); - ~LLUriTemplate() {}; - - /* - * Builds a complete URI from the template. - * - * @param vars an LLSD map of keys and values for substitution. - * - * @return a string containing the complete URI. - */ - std::string buildURI(const LLSD& vars); - -private: - /* - * Builds a URL query string. - * - * @param delim a string containing the separator to use between name=value pairs. - * @param var_list a string containing a comma separated list of variable names. - * @param vars an LLSD map of keys and values for substitution. - * - * @return a URL query string. - */ - std::string expandJoin(const std::string& delim, const std::string& var_list, const LLSD& vars); - - /* - * URL escape the given string. - * LLWeb::escapeURL() only does a partial escape, so this uses curl_escape() instead. - */ - static std::string escapeURL(const std::string& unescaped); - - std::string mTemplate; -}; - - - -#endif // LL_LLWEBSHARING_H diff --git a/indra/newview/llwindebug.cpp b/indra/newview/llwindebug.cpp index 551d0be8d7..eff70ca0b2 100755 --- a/indra/newview/llwindebug.cpp +++ b/indra/newview/llwindebug.cpp @@ -45,7 +45,7 @@ public: ~LLMemoryReserve(); void reserve(); void release(); -protected: +private: unsigned char *mReserve; static const size_t MEMORY_RESERVATION_SIZE; }; @@ -53,7 +53,7 @@ protected: LLMemoryReserve::LLMemoryReserve() : mReserve(NULL) { -}; +} LLMemoryReserve::~LLMemoryReserve() { @@ -66,14 +66,19 @@ const size_t LLMemoryReserve::MEMORY_RESERVATION_SIZE = 5 * 1024 * 1024; void LLMemoryReserve::reserve() { if(NULL == mReserve) + { mReserve = new unsigned char[MEMORY_RESERVATION_SIZE]; -}; + } +} void LLMemoryReserve::release() { - delete [] mReserve; + if (NULL != mReserve) + { + delete [] mReserve; + } mReserve = NULL; -}; +} static LLMemoryReserve gEmergencyMemoryReserve; @@ -130,6 +135,11 @@ void LLWinDebug::init() } } +void LLWinDebug::cleanup () +{ + gEmergencyMemoryReserve.release(); +} + void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename) { // Temporary fix to switch out the code that writes the DMP file. diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h index 6f274c6f16..a3cbf6dc03 100755 --- a/indra/newview/llwindebug.h +++ b/indra/newview/llwindebug.h @@ -37,6 +37,7 @@ class LLWinDebug: public: static void init(); static void generateMinidump(struct _EXCEPTION_POINTERS *pExceptionInfo = NULL); + static void cleanup(); private: static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename); }; diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp index 93eba5b604..3bedfbe502 100755 --- a/indra/newview/llwlhandlers.cpp +++ b/indra/newview/llwlhandlers.cpp @@ -95,8 +95,9 @@ LLEnvironmentRequestResponder::LLEnvironmentRequestResponder() { mID = ++sCount; } -/*virtual*/ void LLEnvironmentRequestResponder::result(const LLSD& unvalidated_content) +/*virtual*/ void LLEnvironmentRequestResponder::httpSuccess() { + const LLSD& unvalidated_content = getContent(); LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL; if (mID != sCount) @@ -122,10 +123,10 @@ LLEnvironmentRequestResponder::LLEnvironmentRequestResponder() LLEnvManagerNew::getInstance()->onRegionSettingsResponse(unvalidated_content); } /*virtual*/ -void LLEnvironmentRequestResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLEnvironmentRequestResponder::httpFailure() { - LL_INFOS("WindlightCaps") << "Got an error, not using region windlight... [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... " + << dumpResponse() << LL_ENDL; LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD()); } @@ -169,8 +170,14 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) /**** * LLEnvironmentApplyResponder ****/ -/*virtual*/ void LLEnvironmentApplyResponder::result(const LLSD& content) +/*virtual*/ void LLEnvironmentApplyResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap() || !content.has("regionID")) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } if (content["regionID"].asUUID() != gAgent.getRegion()->getRegionID()) { LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently " @@ -185,7 +192,7 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) } else { - LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings! Reason from sim: " << content["fail_reason"].asString() << LL_ENDL; + LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings! " << dumpResponse() << LL_ENDL; LLSD args(LLSD::emptyMap()); args["FAIL_REASON"] = content["fail_reason"].asString(); LLNotificationsUtil::add("WLRegionApplyFail", args); @@ -193,14 +200,14 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) } } /*virtual*/ -void LLEnvironmentApplyResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLEnvironmentApplyResponder::httpFailure() { - LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! [status:" - << status << "]: " << content << LL_ENDL; + LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! " + << dumpResponse() << LL_ENDL; LLSD args(LLSD::emptyMap()); std::stringstream msg; - msg << reason << " (Code " << status << ")"; + msg << getReason() << " (Code " << getStatus() << ")"; args["FAIL_REASON"] = msg.str(); LLNotificationsUtil::add("WLRegionApplyFail", args); } diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h index 598ce6d52a..089c799da7 100755 --- a/indra/newview/llwlhandlers.h +++ b/indra/newview/llwlhandlers.h @@ -45,9 +45,9 @@ private: class LLEnvironmentRequestResponder: public LLHTTPClient::Responder { LOG_CLASS(LLEnvironmentRequestResponder); -public: - virtual void result(const LLSD& content); - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); private: friend class LLEnvironmentRequest; @@ -72,7 +72,7 @@ private: class LLEnvironmentApplyResponder: public LLHTTPClient::Responder { LOG_CLASS(LLEnvironmentApplyResponder); -public: +private: /* * Expecting reply from sim in form of: * { @@ -87,10 +87,10 @@ public: * fail_reason : string * } */ - virtual void result(const LLSD& content); + /* virtual */ void httpSuccess(); - // non-200 errors only - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + // non-2xx errors only + /* virtual */ void httpFailure(); private: friend class LLEnvironmentApply; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 1ef2cfff8a..b4e8114a5f 100755 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1149,6 +1149,8 @@ public: << sim << LL_ENDL; return; } + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from LLEstablishAgentCommunication::post. Seed cap == " + << input["body"]["seed-capability"] << LL_ENDL; regionp->setSeedCapability(input["body"]["seed-capability"]); } }; diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 8e164337b6..c12c2cc24c 100755 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -333,7 +333,7 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) This might help with bug #503 */ mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1); - mCurlRequest->slist_append("Content-Type: text/xml"); + mCurlRequest->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); if (useGzip) { diff --git a/indra/newview/roles_constants.h b/indra/newview/roles_constants.h index effd15ea72..8fd7978fa1 100755..100644 --- a/indra/newview/roles_constants.h +++ b/indra/newview/roles_constants.h @@ -53,98 +53,100 @@ enum LLRoleChangeType // KNOWN HOLES: use these for any single bit powers you need // bit 0x1 << 46 -// bit 0x1 << 49 and above +// bit 0x1 << 52 and above // These powers were removed to make group roles simpler // bit 0x1 << 41 (GP_ACCOUNTING_VIEW) // bit 0x1 << 46 (GP_PROPOSAL_VIEW) const U64 GP_NO_POWERS = 0x0; -const U64 GP_ALL_POWERS = 0xFFFFFFFFFFFFFFFFLL; +const U64 GP_ALL_POWERS = 0xFFFFffffFFFFffffLL; // Membership -const U64 GP_MEMBER_INVITE = 0x1 << 1; // Invite member -const U64 GP_MEMBER_EJECT = 0x1 << 2; // Eject member from group -const U64 GP_MEMBER_OPTIONS = 0x1 << 3; // Toggle "Open enrollment" and change "Signup Fee" -const U64 GP_MEMBER_VISIBLE_IN_DIR = 0x1LL << 47; +const U64 GP_MEMBER_INVITE = 0x1LL << 1; // Invite member +const U64 GP_MEMBER_EJECT = 0x1LL << 2; // Eject member from group +const U64 GP_MEMBER_OPTIONS = 0x1LL << 3; // Toggle "Open enrollment" and change "Signup Fee" +const U64 GP_MEMBER_VISIBLE_IN_DIR = 0x1LL << 47; // Roles -const U64 GP_ROLE_CREATE = 0x1 << 4; // Create new roles -const U64 GP_ROLE_DELETE = 0x1 << 5; // Delete roles -const U64 GP_ROLE_PROPERTIES = 0x1 << 6; // Change Role Names, Titles, and Descriptions (Of roles the user is in, only, or any role in group?) -const U64 GP_ROLE_ASSIGN_MEMBER_LIMITED = 0x1 << 7; // Assign Member to a Role that the assigner is in -const U64 GP_ROLE_ASSIGN_MEMBER = 0x1 << 8; // Assign Member to Role -const U64 GP_ROLE_REMOVE_MEMBER = 0x1 << 9; // Remove Member from Role -const U64 GP_ROLE_CHANGE_ACTIONS = 0x1 << 10; // Change actions a role can perform +const U64 GP_ROLE_CREATE = 0x1LL << 4; // Create new roles +const U64 GP_ROLE_DELETE = 0x1LL << 5; // Delete roles +const U64 GP_ROLE_PROPERTIES = 0x1LL << 6; // Change Role Names, Titles, and Descriptions (Of roles the user is in, only, or any role in group?) +const U64 GP_ROLE_ASSIGN_MEMBER_LIMITED = 0x1LL << 7; // Assign Member to a Role that the assigner is in +const U64 GP_ROLE_ASSIGN_MEMBER = 0x1LL << 8; // Assign Member to Role +const U64 GP_ROLE_REMOVE_MEMBER = 0x1LL << 9; // Remove Member from Role +const U64 GP_ROLE_CHANGE_ACTIONS = 0x1LL << 10; // Change actions a role can perform // Group Identity -const U64 GP_GROUP_CHANGE_IDENTITY = 0x1 << 11; // Charter, insignia, 'Show In Group List', 'Publish on the web', 'Mature', all 'Show Member In Group Profile' checkboxes +const U64 GP_GROUP_CHANGE_IDENTITY = 0x1LL << 11; // Charter, insignia, 'Show In Group List', 'Publish on the web', 'Mature', all 'Show Member In Group Profile' checkboxes // Parcel Management -const U64 GP_LAND_DEED = 0x1 << 12; // Deed Land and Buy Land for Group -const U64 GP_LAND_RELEASE = 0x1 << 13; // Release Land (to Gov. Linden) -const U64 GP_LAND_SET_SALE_INFO = 0x1 << 14; // Set for sale info (Toggle "For Sale", Set Price, Set Target, Toggle "Sell objects with the land") -const U64 GP_LAND_DIVIDE_JOIN = 0x1 << 15; // Divide and Join Parcels +const U64 GP_LAND_DEED = 0x1LL << 12; // Deed Land and Buy Land for Group +const U64 GP_LAND_RELEASE = 0x1LL << 13; // Release Land (to Gov. Linden) +const U64 GP_LAND_SET_SALE_INFO = 0x1LL << 14; // Set for sale info (Toggle "For Sale", Set Price, Set Target, Toggle "Sell objects with the land") +const U64 GP_LAND_DIVIDE_JOIN = 0x1LL << 15; // Divide and Join Parcels // Parcel Identity -const U64 GP_LAND_FIND_PLACES = 0x1 << 17; // Toggle "Show in Find Places" and Set Category. -const U64 GP_LAND_CHANGE_IDENTITY = 0x1 << 18; // Change Parcel Identity: Parcel Name, Parcel Description, Snapshot, 'Publish on the web', and 'Mature' checkbox -const U64 GP_LAND_SET_LANDING_POINT = 0x1 << 19; // Set Landing Point +const U64 GP_LAND_FIND_PLACES = 0x1LL << 17; // Toggle "Show in Find Places" and Set Category. +const U64 GP_LAND_CHANGE_IDENTITY = 0x1LL << 18; // Change Parcel Identity: Parcel Name, Parcel Description, Snapshot, 'Publish on the web', and 'Mature' checkbox +const U64 GP_LAND_SET_LANDING_POINT = 0x1LL << 19; // Set Landing Point // Parcel Settings -const U64 GP_LAND_CHANGE_MEDIA = 0x1 << 20; // Change Media Settings -const U64 GP_LAND_EDIT = 0x1 << 21; // Toggle Edit Land -const U64 GP_LAND_OPTIONS = 0x1 << 22; // Toggle Set Home Point, Fly, Outside Scripts, Create/Edit Objects, Landmark, and Damage checkboxes +const U64 GP_LAND_CHANGE_MEDIA = 0x1LL << 20; // Change Media Settings +const U64 GP_LAND_EDIT = 0x1LL << 21; // Toggle Edit Land +const U64 GP_LAND_OPTIONS = 0x1LL << 22; // Toggle Set Home Point, Fly, Outside Scripts, Create/Edit Objects, Landmark, and Damage checkboxes // Parcel Powers -const U64 GP_LAND_ALLOW_EDIT_LAND = 0x1 << 23; // Bypass Edit Land Restriction -const U64 GP_LAND_ALLOW_FLY = 0x1 << 24; // Bypass Fly Restriction -const U64 GP_LAND_ALLOW_CREATE = 0x1 << 25; // Bypass Create/Edit Objects Restriction -const U64 GP_LAND_ALLOW_LANDMARK = 0x1 << 26; // Bypass Landmark Restriction -const U64 GP_LAND_ALLOW_SET_HOME = 0x1 << 28; // Bypass Set Home Point Restriction -const U64 GP_LAND_ALLOW_HOLD_EVENT = 0x1LL << 41; // Allowed to hold events on group-owned land - +const U64 GP_LAND_ALLOW_EDIT_LAND = 0x1LL << 23; // Bypass Edit Land Restriction +const U64 GP_LAND_ALLOW_FLY = 0x1LL << 24; // Bypass Fly Restriction +const U64 GP_LAND_ALLOW_CREATE = 0x1LL << 25; // Bypass Create/Edit Objects Restriction +const U64 GP_LAND_ALLOW_LANDMARK = 0x1LL << 26; // Bypass Landmark Restriction +const U64 GP_LAND_ALLOW_SET_HOME = 0x1LL << 28; // Bypass Set Home Point Restriction +const U64 GP_LAND_ALLOW_HOLD_EVENT = 0x1LL << 41; // Allowed to hold events on group-owned land // Parcel Access -const U64 GP_LAND_MANAGE_ALLOWED = 0x1 << 29; // Manage Allowed List -const U64 GP_LAND_MANAGE_BANNED = 0x1 << 30; // Manage Banned List -const U64 GP_LAND_MANAGE_PASSES = 0x1LL << 31; // Change Sell Pass Settings -const U64 GP_LAND_ADMIN = 0x1LL << 32; // Eject and Freeze Users on the land +const U64 GP_LAND_MANAGE_ALLOWED = 0x1LL << 29; // Manage Allowed List +const U64 GP_LAND_MANAGE_BANNED = 0x1LL << 30; // Manage Banned List +const U64 GP_LAND_MANAGE_PASSES = 0x1LL << 31; // Change Sell Pass Settings +const U64 GP_LAND_ADMIN = 0x1LL << 32; // Eject and Freeze Users on the land // Parcel Content -const U64 GP_LAND_RETURN_GROUP_SET = 0x1LL << 33; // Return objects on parcel that are set to group -const U64 GP_LAND_RETURN_NON_GROUP = 0x1LL << 34; // Return objects on parcel that are not set to group -const U64 GP_LAND_RETURN_GROUP_OWNED= 0x1LL << 48; // Return objects on parcel that are owned by the group +const U64 GP_LAND_RETURN_GROUP_SET = 0x1LL << 33; // Return objects on parcel that are set to group +const U64 GP_LAND_RETURN_NON_GROUP = 0x1LL << 34; // Return objects on parcel that are not set to group +const U64 GP_LAND_RETURN_GROUP_OWNED = 0x1LL << 48; // Return objects on parcel that are owned by the group // Select a power-bit based on an object's relationship to a parcel. const U64 GP_LAND_RETURN = GP_LAND_RETURN_GROUP_OWNED | GP_LAND_RETURN_GROUP_SET | GP_LAND_RETURN_NON_GROUP; -const U64 GP_LAND_GARDENING = 0x1LL << 35; // Parcel Gardening - plant and move linden trees +const U64 GP_LAND_GARDENING = 0x1LL << 35; // Parcel Gardening - plant and move linden trees // Object Management -const U64 GP_OBJECT_DEED = 0x1LL << 36; // Deed Object -const U64 GP_OBJECT_MANIPULATE = 0x1LL << 38; // Manipulate Group Owned Objects (Move, Copy, Mod) -const U64 GP_OBJECT_SET_SALE = 0x1LL << 39; // Set Group Owned Object for Sale +const U64 GP_OBJECT_DEED = 0x1LL << 36; // Deed Object +const U64 GP_OBJECT_MANIPULATE = 0x1LL << 38; // Manipulate Group Owned Objects (Move, Copy, Mod) +const U64 GP_OBJECT_SET_SALE = 0x1LL << 39; // Set Group Owned Object for Sale // Accounting -const U64 GP_ACCOUNTING_ACCOUNTABLE = 0x1LL << 40; // Pay Group Liabilities and Receive Group Dividends +const U64 GP_ACCOUNTING_ACCOUNTABLE = 0x1LL << 40; // Pay Group Liabilities and Receive Group Dividends // Notices -const U64 GP_NOTICES_SEND = 0x1LL << 42; // Send Notices -const U64 GP_NOTICES_RECEIVE = 0x1LL << 43; // Receive Notices and View Notice History +const U64 GP_NOTICES_SEND = 0x1LL << 42; // Send Notices +const U64 GP_NOTICES_RECEIVE = 0x1LL << 43; // Receive Notices and View Notice History // Proposals // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856: -const U64 GP_PROPOSAL_START = 0x1LL << 44; // Start Proposal +const U64 GP_PROPOSAL_START = 0x1LL << 44; // Start Proposal // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856: -const U64 GP_PROPOSAL_VOTE = 0x1LL << 45; // Vote on Proposal +const U64 GP_PROPOSAL_VOTE = 0x1LL << 45; // Vote on Proposal // Group chat moderation related -const U64 GP_SESSION_JOIN = 0x1LL << 16; //can join session -const U64 GP_SESSION_VOICE = 0x1LL << 27; //can hear/talk -const U64 GP_SESSION_MODERATOR = 0x1LL << 37; //can mute people's session +const U64 GP_SESSION_JOIN = 0x1LL << 16; //can join session +const U64 GP_SESSION_VOICE = 0x1LL << 27; //can hear/talk +const U64 GP_SESSION_MODERATOR = 0x1LL << 37; //can mute people's session + +// Group Banning +const U64 GP_GROUP_BAN_ACCESS = 0x1LL << 51; // Allows access to ban / un-ban agents from a group. const U64 GP_DEFAULT_MEMBER = GP_ACCOUNTING_ACCOUNTABLE | GP_LAND_ALLOW_SET_HOME diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml index 11d100eeff..74d160dfae 100755 --- a/indra/newview/skins/default/xui/da/strings.xml +++ b/indra/newview/skins/default/xui/da/strings.xml @@ -1172,7 +1172,8 @@ Prøv venligst om lidt igen. <string name="InventoryNoTexture"> Du har ikke en kopi af denne tekstur i din beholdning </string> - <string name="no_transfer" value=" (ikke overdragbar)"/> + <string name="Unconstrained">Ikke låst</string> + <string name="no_transfer" value=" (ikke overdragbar)"/> <string name="no_modify" value=" (ikke redigere)"/> <string name="no_copy" value=" (ikke kopiere)"/> <string name="worn" value=" (båret)"/> diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index 4268b95370..082febd709 100755 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -1267,7 +1267,8 @@ Warten Sie kurz und versuchen Sie dann noch einmal, sich anzumelden. <string name="InventoryNoTexture"> Sie haben keine Kopie dieser Textur in Ihrem Inventar. </string> - <string name="InventoryInboxNoItems"> + <string name="Unconstrained">keines</string> + <string name="InventoryInboxNoItems"> Einkäufe aus dem Marktplatz erscheinen hier. Sie können diese dann zur Verwendung in Ihr Inventar ziehen. </string> <string name="MarketplaceURL"> diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 9668cfa526..ef2f158a86 100755 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -72,7 +72,7 @@ Second Life is brought to you by the Lindens: top_pad="10" width="435" word_wrap="true"> -Philip, Andrew, Doug, Richard, Phoenix, Ian, Mark, Robin, Dan, Char, Ryan, Eric, Jim, Lee, Jeff, Michael, Kelly, Steve, Catherine, Bub, Ramzi, Jill, Jeska, Don, Kona, Callum, Charity, Jack, Shawn, babbage, James, Lauren, Blue, Brent, Reuben, Pathfinder, Jesse, Patsy, Torley, Bo, Cyn, Jonathan, Gia, Annette, Ginsu, Harry, Lex, Runitai, Guy, Cornelius, Beth, Swiss, Thumper, Wendy, Teeple, Seth, Dee, Mia, Sally, Liana, Aura, Beez, Milo, Red, Gulliver, Marius, Joe, Jose, Dore, Justin, Nora, Morpheus, Lexie, Amber, Chris, Xan, Leyla, Walker, Sabin, Joshua, Hiromi, Tofu, Fritz, June, Jean, Ivy, Dez, Ken, Betsy, Which, Spike, Rob, Zee, Dustin, George, Claudia, del, Matthew, jane, jay, Adrian, Yool, Rika, Yoz, siobhan, Qarl, Benjamin, Beast, Everett, madhavi, Christopher, Izzy, stephany, Jeremy, sean, adreanne, Pramod, Tobin, sejong, Iridium, maurice, kj, Meta, kari, JP, bert, kyle, Jon, Socrates, Bridie, Ivan, maria, Aric, Coco, Periapse, sandy, Storrs, Lotte, Colossus, Brad, Pastrami, Zen, BigPapi, Banzai, Sardonyx, Mani, Garry, Jaime, Neuro, Samuel, Niko, CeeLo, Austin, Soft, Poppy, emma, tessa, angelo, kurz, alexa, Sue, CG, Blake, Erica, Brett, Bevis, kristen, Q, simon, Enus, MJ, laurap, Kip, Scouse, Ron, Ram, kend, Marty, Prospero, melissa, kraft, Nat, Seraph, Hamilton, Lordan, Green, miz, Ashlei, Trinity, Ekim, Echo, Charlie, Rowan, Rome, Jt, Doris, benoc, Christy, Bao, Kate, Tj, Patch, Cheah, Johan, Brandy, Angela, Oreh, Cogsworth, Lan, Mitchell, Space, Bambers, Einstein, Bender, Malbers, Matias, Maggie, Rothman, Milton, Niall, Marin, Allison, Mango, Andrea, Katt, Yi, Ambroff, Rico, Raymond, Gail, Christa, William, Dawn, Usi, Dynamike, M, Corr, Dante, Molly, kaylee, Danica, Kelv, Lil, jacob, Nya, Rodney, elsie, Blondin, Grant, Nyx, Devin, Monty, Minerva, Keira, Katie, Jenn, Makai, Clare, Joy, Cody, Gayathri, FJ, spider, Oskar, Landon, Jarv, Noelle, Al, Doc, Gray, Vir, t, Maestro, Simone, Shannon, yang, Courtney, Scott, charlene, Quixote, Susan, Zed, Amanda, Katelin, Esbee, JoRoan, Enkidu, roxie, Scarlet, Merov, Kevin, Judy, Rand, Newell, Les, Dessie, Galen, Michon, Geo, Siz, Calyle, Pete, Praveen, Callen, Sheldon, Pink, Nelson, jenelle, Terrence, Nathan, Juan, Sascha, Huseby, Karina, Kaye, Kotler, Lis, Darv, Charrell, Dakota, Kimmora, Theeba, Taka, Mae, Perry, Ducot, dana, Esther, Dough, gisele, Doten, Viale, Fisher, jessieann, ashley, Torres, delby, rountree, kurt, Slaton, Madison, Rue, Gino, Wen, Casssandra, Brodesky, Squid, Gez, Rakesh, Gecko, Ladan, Tony, Tatem, Squire, Falcon, BK, Crimp, Tiggs, Bacon, Coyot, Carmilla, Webb, Sea, Arch, Jillian, Jason, Bernard, Vogt, Peggy, dragon, Pup, xandix, Wallace, Bewest, Inoshiro, Rhett, AG, Aimee, Ghengis, Itiaes, Eli, Steffan, Epic, Grapes, Stone, Prep, Scobu, Robert, Alain, Carla, Vicky, Tia, Alec, Taras, Lisa, Oz, Ariane, Log, House, Kazu, Kim, Drofnas, Tyler, Campbell, Michele, Madeline, Nelly, Baron, Thor, Lori, Hele, Fredrik, Teddy, Pixie, Berry, Gabrielle, Alfonso, Brooke, Wolf, Ringo, Cru, Charlar, Rodvik, Gibson, Elise, Bagman, Greger, Leonidas, Jerm, Leslie, CB, Brenda, Durian, Carlo, mm, Zeeshan, Caleb, Max, Elikak, Mercille, Steph, Chase +Philip, Andrew, Doug, Richard, Phoenix, Ian, Mark, Robin, Dan, Char, Ryan, Eric, Jim, Lee, Jeff, Michael, Kelly, Steve, Catherine, Bub, Ramzi, Jill, Jeska, Don, Kona, Callum, Charity, Jack, Shawn, babbage, James, Lauren, Blue, Brent, Reuben, Pathfinder, Jesse, Patsy, Torley, Bo, Cyn, Jonathan, Gia, Annette, Ginsu, Harry, Lex, Runitai, Guy, Cornelius, Beth, Swiss, Thumper, Wendy, Teeple, Seth, Dee, Mia, Sally, Liana, Aura, Beez, Milo, Red, Gulliver, Marius, Joe, Jose, Dore, Justin, Nora, Morpheus, Lexie, Amber, Chris, Xan, Leyla, Walker, Sabin, Joshua, Hiromi, Tofu, Fritz, June, Jean, Ivy, Dez, Ken, Betsy, Which, Spike, Rob, Zee, Dustin, George, Claudia, del, Matthew, jane, jay, Adrian, Yool, Rika, Yoz, siobhan, Qarl, Benjamin, Beast, Everett, madhavi, Christopher, Izzy, stephany, Jeremy, sean, adreanne, Pramod, Tobin, sejong, Iridium, maurice, kj, Meta, kari, JP, bert, kyle, Jon, Socrates, Bridie, Ivan, maria, Aric, Coco, Periapse, sandy, Storrs, Lotte, Colossus, Brad, Pastrami, Zen, BigPapi, Banzai, Sardonyx, Mani, Garry, Jaime, Neuro, Samuel, Niko, CeeLo, Austin, Soft, Poppy, emma, tessa, angelo, kurz, alexa, Sue, CG, Blake, Erica, Brett, Bevis, kristen, Q, simon, Enus, MJ, laurap, Kip, Scouse, Ron, Ram, kend, Marty, Prospero, melissa, kraft, Nat, Seraph, Hamilton, Lordan, Green, miz, Ashlei, Trinity, Ekim, Echo, Charlie, Rowan, Rome, Jt, Doris, benoc, Christy, Bao, Kate, Tj, Patch, Cheah, Johan, Brandy, Angela, Oreh, Cogsworth, Lan, Mitchell, Space, Bambers, Einstein, Bender, Malbers, Matias, Maggie, Rothman, Milton, Niall, Marin, Allison, Mango, Andrea, Katt, Yi, Ambroff, Rico, Raymond, Gail, Christa, William, Dawn, Usi, Dynamike, M, Corr, Dante, Molly, kaylee, Danica, Kelv, Lil, jacob, Nya, Rodney, elsie, Blondin, Grant, Nyx, Devin, Monty, Minerva, Keira, Katie, Jenn, Makai, Clare, Joy, Cody, Gayathri, FJ, spider, Oskar, Landon, Jarv, Noelle, Al, Doc, Gray, Vir, t, Maestro, Simone, Shannon, yang, Courtney, Scott, charlene, Quixote, Susan, Zed, Amanda, Katelin, Esbee, JoRoan, Enkidu, roxie, Scarlet, Merov, Kevin, Judy, Rand, Newell, Les, Dessie, Galen, Michon, Geo, Siz, Calyle, Pete, Praveen, Callen, Sheldon, Pink, Nelson, jenelle, Terrence, Nathan, Juan, Sascha, Huseby, Karina, Kaye, Kotler, Lis, Darv, Charrell, Dakota, Kimmora, Theeba, Taka, Mae, Perry, Ducot, dana, Esther, Dough, gisele, Doten, Viale, Fisher, jessieann, ashley, Torres, delby, rountree, kurt, Slaton, Madison, Rue, Gino, Wen, Casssandra, Brodesky, Squid, Gez, Rakesh, Gecko, Ladan, Tony, Tatem, Squire, Falcon, BK, Crimp, Tiggs, Bacon, Coyot, Carmilla, Webb, Sea, Arch, Jillian, Jason, Bernard, Vogt, Peggy, dragon, Pup, xandix, Wallace, Bewest, Inoshiro, Rhett, AG, Aimee, Ghengis, Itiaes, Eli, Steffan, Epic, Grapes, Stone, Prep, Scobu, Robert, Alain, Carla, Vicky, Tia, Alec, Taras, Lisa, Oz, Ariane, Log, House, Kazu, Kim, Drofnas, Tyler, Campbell, Michele, Madeline, Nelly, Baron, Thor, Lori, Hele, Fredrik, Teddy, Pixie, Berry, Gabrielle, Alfonso, Brooke, Wolf, Ringo, Cru, Charlar, Rodvik, Gibson, Elise, Bagman, Greger, Leonidas, Jerm, Leslie, CB, Brenda, Durian, Carlo, mm, Zeeshan, Caleb, Max, Elikak, Mercille, Steph, Chase, Baker </text_editor> <text follows="top|left" diff --git a/indra/newview/skins/default/xui/en/floater_places.xml b/indra/newview/skins/default/xui/en/floater_places.xml index b241e265a9..31dd6d2c64 100755 --- a/indra/newview/skins/default/xui/en/floater_places.xml +++ b/indra/newview/skins/default/xui/en/floater_places.xml @@ -2,6 +2,7 @@ <floater positioning="cascading" + default_tab_group="1" legacy_header_height="18" can_resize="true" height="588" @@ -16,6 +17,7 @@ width="333"> <panel top="18" + tab_group="1" class="panel_places" name="main_panel" filename="panel_places.xml" diff --git a/indra/newview/skins/default/xui/en/floater_preview_texture.xml b/indra/newview/skins/default/xui/en/floater_preview_texture.xml index 137e278ddc..e1e7e1c8c8 100755 --- a/indra/newview/skins/default/xui/en/floater_preview_texture.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_texture.xml @@ -79,30 +79,6 @@ width="108" name="combo_aspect_ratio" tool_tip="Preview at a fixed aspect ratio"> - <combo_item name="Unconstrained" value="Unconstrained"> - Unconstrained - </combo_item> - <combo_item name="1:1" value="1:1" tool_tip="Group insignia or Real World profile"> - 1:1 - </combo_item> - <combo_item name="4:3" value="4:3" tool_tip="[SECOND_LIFE] profile"> - 4:3 - </combo_item> - <combo_item name="10:7" value="10:7" tool_tip="Classifieds and search listings, landmarks"> - 10:7 - </combo_item> - <combo_item name="3:2" value="3:2" tool_tip="About land"> - 3:2 - </combo_item> - <combo_item name="16:10" value="16:10"> - 16:10 - </combo_item> - <combo_item name="16:9" value="16:9" tool_tip="Profile picks"> - 16:9 - </combo_item> - <combo_item name="2:1" value="2:1"> - 2:1 - </combo_item> </combo_box> <button follows="right|bottom" diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index 52c4fb1613..e91eea04d1 100755 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -35,14 +35,72 @@ tear_off="true" name="Help"> <menu_item_call - label="[SECOND_LIFE] Help" - name="Second Life Help" + label="How to..." + name="How To" shortcut="F1"> <menu_item_call.on_click - function="ShowHelp" - parameter="f1_help" /> + function="Help.ToggleHowTo" + parameter="" /> </menu_item_call> - <menu_item_separator /> + <menu_item_call + label="Quickstart" + name="Quickstart"> + <menu_item_call.on_click + function="Advanced.ShowURL" + parameter="http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Quickstart/ta-p/1087919"/> + </menu_item_call> + <menu_item_separator/> + <menu_item_call + label="Knowledge Base" + name="Knowledge Base"> + <menu_item_call.on_click + function="Advanced.ShowURL" + parameter="http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-User-s-Guide/ta-p/1244857"/> + </menu_item_call> + <menu_item_call + label="Wiki" + name="Wiki"> + <menu_item_call.on_click + function="Advanced.ShowURL" + parameter="http://wiki.secondlife.com"/> + </menu_item_call> + <menu_item_call + label="Community Forums" + name="Community Forums"> + <menu_item_call.on_click + function="Advanced.ShowURL" + parameter="http://community.secondlife.com/t5/Forums/ct-p/Forums"/> + </menu_item_call> + <menu_item_call + label="Support portal" + name="Support portal"> + <menu_item_call.on_click + function="Advanced.ShowURL" + parameter="https://support.secondlife.com/"/> + </menu_item_call> + <menu_item_separator/> + <menu_item_call + label="[SECOND_LIFE] News" + name="Second Life News"> + <menu_item_call.on_click + function="Advanced.ShowURL" + parameter="http://community.secondlife.com/t5/Featured-News/bg-p/blog_feature_news"/> + </menu_item_call> + <menu_item_call + label="[SECOND_LIFE] Blogs" + name="Second Life Blogs"> + <menu_item_call.on_click + function="Advanced.ShowURL" + parameter="http://community.secondlife.com/t5/Blogs/ct-p/Blogs"/> + </menu_item_call> + <menu_item_separator/> + <menu_item_call + label="Report Bug" + name="Report Bug"> + <menu_item_call.on_click + function="Advanced.ReportBug"/> + </menu_item_call> + <menu_item_separator/> <menu_item_call label="About [APP_NAME]" name="About Second Life"> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 8045826ff5..ec20c25f14 100755 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -606,44 +606,59 @@ label="Sun" name="Sun" tear_off="true"> - <menu_item_call + <menu_item_check label="Sunrise" name="Sunrise"> - <menu_item_call.on_click + <menu_item_check.on_click function="World.EnvSettings" parameter="sunrise" /> - </menu_item_call> - <menu_item_call + <menu_item_check.on_check + function="World.EnableEnvSettings" + parameter="sunrise" /> + </menu_item_check> + <menu_item_check label="Midday" name="Noon" shortcut="control|shift|Y"> - <menu_item_call.on_click + <menu_item_check.on_click function="World.EnvSettings" parameter="noon" /> - </menu_item_call> - <menu_item_call + <menu_item_check.on_check + function="World.EnableEnvSettings" + parameter="noon" /> + </menu_item_check> + <menu_item_check label="Sunset" name="Sunset" shortcut="control|shift|N"> - <menu_item_call.on_click + <menu_item_check.on_click function="World.EnvSettings" parameter="sunset" /> - </menu_item_call> - <menu_item_call + <menu_item_check.on_check + function="World.EnableEnvSettings" + parameter="sunset" /> + </menu_item_check> + <menu_item_check label="Midnight" name="Midnight"> - <menu_item_call.on_click + <menu_item_check.on_click function="World.EnvSettings" parameter="midnight" /> - </menu_item_call> + <menu_item_check.on_check + function="World.EnableEnvSettings" + parameter="midnight" /> + </menu_item_check> <menu_item_separator/> - <menu_item_call + <menu_item_check label="Use Region Settings" name="Use Region Settings"> - <menu_item_call.on_click + <menu_item_check.on_click function="World.EnvSettings" parameter="region" /> - </menu_item_call> + <menu_item_check.on_check + function="World.EnableEnvSettings" + parameter="region" /> + </menu_item_check> </menu> @@ -1550,7 +1565,8 @@ <menu_item_check label="Highlight Transparent" name="Highlight Transparent" - shortcut="control|alt|T"> + shortcut="control|alt|T" + use_mac_ctrl="true"> <menu_item_check.on_check function="View.CheckHighlightTransparent" /> <menu_item_check.on_click @@ -3164,18 +3180,6 @@ <menu_item_call.on_click function="Advanced.PrintAgentInfo" /> </menu_item_call> - <menu_item_check - label="Region Debug Console" - name="Region Debug Console" - shortcut="control|shift|`" - use_mac_ctrl="true"> - <menu_item_check.on_check - function="Floater.Visible" - parameter="region_debug_console" /> - <menu_item_check.on_click - function="Floater.Toggle" - parameter="region_debug_console" /> - </menu_item_check> <menu_item_separator /> <menu_item_check diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 370a2af5e0..ff042e55ce 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -506,7 +506,35 @@ Add this Ability to '[ROLE_NAME]'? notext="No" yestext="Yes"/> </notification> - + + <notification + icon="alertmodal.tga" + name="AssignBanAbilityWarning" + type="alertmodal"> +You are about to add the Ability '[ACTION_NAME]' to the Role '[ROLE_NAME]'. + + *WARNING* +Any Member in a Role with this Ability will also be granted the Abilities '[ACTION_NAME_2]' and '[ACTION_NAME_3]' + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="RemoveBanAbilityWarning" + type="alertmodal"> +You are removing the Ability '[ACTION_NAME]' to the Role '[ROLE_NAME]'. + + *WARNING* +Removing this ability will NOT remove the Abilities '[ACTION_NAME_2]' and '[ACTION_NAME_3]'. + +If you no longer wish to have these abilities granted to this role, disable them immediately! + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + <notification icon="alertmodal.tga" name="EjectGroupMemberWarning" @@ -3747,6 +3775,28 @@ Leave Group? </notification> <notification + icon="aler.tga" + name="GroupDepartError" + type="alert"> +Unable to leave group: [reason]. + <tag>reason</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alert.tga" + name="GroupDepart" + type="alert"> +You have left the group [group_name]. + <tag>group_name</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification icon="alert.tga" name="ConfirmKick" type="alert"> @@ -4137,6 +4187,19 @@ Are you sure you want to teleport to <nolink>[LOCATION]</nolink>? notext="Cancel" yestext="Teleport"/> </notification> + + <notification + icon="alertmodal.tga" + name="TeleportViaSLAPP" + type="alertmodal"> +Are you sure you want to teleport to <nolink>[LOCATION]</nolink>? + <tag>confirm</tag> + <usetemplate + ignoretext="Confirm that I want to teleport via SLAPP" + name="okcancelignore" + notext="Cancel" + yestext="Teleport"/> + </notification> <notification icon="alertmodal.tga" @@ -7634,7 +7697,7 @@ Are you sure you want to share the following items: With the following Residents: -[RESIDENTS] +<nolink>[RESIDENTS]</nolink> <tag>confirm</tag> <usetemplate name="okcancelbuttons" @@ -7654,7 +7717,7 @@ Are you sure you want to share the following items: With the following Residents: -[RESIDENTS] +<nolink>[RESIDENTS]</nolink> <tag>confirm</tag> <usetemplate name="okcancelbuttons" @@ -10224,4 +10287,14 @@ Cannot create large prims that intersect other players. Please re-try when othe yestext="OK"/> </notification> + <notification + icon="alert.tga" + name="ChatHistoryIsBusyAlert" + type="alertmodal"> + Chat history file is busy with previous operation. Please try again in a few minutes or choose chat with another person. + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + </notifications> diff --git a/indra/newview/skins/default/xui/en/panel_group_bulk_ban.xml b/indra/newview/skins/default/xui/en/panel_group_bulk_ban.xml new file mode 100644 index 0000000000..43449df1fd --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_group_bulk_ban.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + height="330" + label="Ban Residents" + layout="topleft" + left="0" + name="bulk_ban_panel" + top="330" + width="210"> + <panel.string + name="loading"> + (loading...) + </panel.string> + <panel.string + name="ban_selection_too_large"> + Group bans not sent: too many Residents selected. Group bans are limited to 100 per request. + </panel.string> + <panel.string + name="already_banned"> + Group Invitations not sent: resident '[RESIDENT]' already banned. + </panel.string> + <text + type="string" + length="1" + height="54" + layout="topleft" + left="7" + name="help_text" + top="28" + word_wrap="true" + width="200"> + You can select multiple Residents to ban from your group. Click 'Open Resident Chooser' to start. + </text> + <button + height="20" + label="Open Resident Chooser" + layout="topleft" + left_delta="-2" + name="add_button" + top_delta="44" + width="200" /> + <name_list + allow_calling_card_drop="true" + column_padding="0" + height="174" + layout="topleft" + left_delta="0" + multi_select="true" + name="banned_agent_list" + tool_tip="Hold the Ctrl key and click Resident names to multi-select" + top_pad="4" + width="200" /> + <button + height="20" + label="Remove Selected from List" + layout="topleft" + left_delta="0" + name="remove_button" + tool_tip="Removes the Residents selected above from the ban list" + top_pad="4" + width="200" /> + <button + height="20" + label="Ban Residents" + layout="topleft" + left="4" + name="ban_button" + top_delta="30" + width="135" /> + <button + height="20" + label="Cancel" + layout="topleft" + left_pad="2" + name="cancel_button" + top_delta="0" + width="65" /> + <string + name="GroupBulkBan"> + Group Ban + </string> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_group_invite.xml b/indra/newview/skins/default/xui/en/panel_group_invite.xml index f47ed992ca..ebb460deb0 100755 --- a/indra/newview/skins/default/xui/en/panel_group_invite.xml +++ b/indra/newview/skins/default/xui/en/panel_group_invite.xml @@ -88,7 +88,7 @@ label="Send Invitations" layout="topleft" left="4" - name="ok_button" + name="invite_button" top="356" width="135" /> <button diff --git a/indra/newview/skins/default/xui/en/panel_group_roles.xml b/indra/newview/skins/default/xui/en/panel_group_roles.xml index 9ac5b8800e..ea619e6319 100755 --- a/indra/newview/skins/default/xui/en/panel_group_roles.xml +++ b/indra/newview/skins/default/xui/en/panel_group_roles.xml @@ -118,6 +118,13 @@ clicking on their names. left_pad="10" name="member_eject" width="100" /> + <button + height="23" + label="Ban Member(s)" + follows="top|left" + left_pad="10" + name="member_ban" + width="100" /> </panel> <panel border="false" @@ -138,454 +145,522 @@ clicking on their names. right="-5" name="show_all_button" width="100" />--> - <panel.string - name="help_text"> - Roles have a title and an allowed list of Abilities -that Members can perform. Members can belong to -one or more Roles. A group can have up to 10 Roles, -including the Everyone and Owner Roles. - </panel.string> - <panel.string - name="cant_delete_role"> - The 'Everyone' and 'Owners' Roles are special and can't be deleted. - </panel.string> - <panel.string - name="power_folder_icon" translate="false"> - Inv_FolderClosed - </panel.string> - <panel.string - name="power_all_have_icon" translate="false"> - Checkbox_On - </panel.string> - <panel.string - name="power_partial_icon" translate="false"> - Checkbox_Off - </panel.string> - <filter_editor - layout="topleft" - top="5" - left="5" - right="-5" - height="22" - search_button_visible="false" - follows="left|top|right" - label="Filter Roles" - name="filter_input" /> - <scroll_list - column_padding="0" - draw_heading="true" - draw_stripes="false" - heading_height="23" - height="132" - layout="topleft" - search_column="1" - left="0" - follows="left|top|right" - right="-1" - name="role_list" - top_pad="2" - width="310"> - <scroll_list.columns - label="Role" - name="name" - relative_width="0.45" /> - <scroll_list.columns - label="Title" - name="title" - relative_width="0.45" /> - <scroll_list.columns - label="#" - name="members" - relative_width="0.15" /> - </scroll_list> - <button - follows="top|left" - height="23" - label="New Role" - layout="topleft" - left="0" - name="role_create" - width="120" /> - <button - height="23" - follows="top|left" - label="Delete Role" - layout="topleft" - left_pad="10" - name="role_delete" - width="120" /> - </panel> - <panel - border="false" - height="303" - label="ABILITIES" - layout="topleft" - left="0" - right="-1" - help_topic="roles_actions_tab" - name="actions_sub_tab" - class="panel_group_actions_subtab" - tool_tip="You can view an Ability's Description and which Roles and Members can execute the Ability." - width="310"> - <panel.string - name="help_text"> - Abilities allow Members in Roles to do specific -things in this group. There's a broad variety of Abilities. - </panel.string> - <panel.string - name="power_folder_icon" translate="false"> - Inv_FolderClosed - </panel.string> - <panel.string - name="power_all_have_icon" translate="false"> - Checkbox_On - </panel.string> - <panel.string - name="power_partial_icon" translate="false"> - Checkbox_Off - </panel.string> - <filter_editor - layout="topleft" - top="5" - left="5" - right="-5" - height="22" - search_button_visible="false" - follows="left|top|right" - label="Filter Abilities" - name="filter_input" /> - <scroll_list - column_padding="0" - draw_stripes="true" - height="200" - follows="left|top|right" - layout="topleft" - left="0" - right="-1" - name="action_list" - search_column="2" - tool_tip="Select an Ability to view more details" - top_pad="5" - width="300"> - <scroll_list.columns - label="" - name="icon" - width="2" /> - <scroll_list.columns - label="" - name="checkbox" - width="20" /> - <scroll_list.columns - label="" - name="action" - width="270" /> - </scroll_list> - </panel> - </tab_container> + <panel.string + name="help_text"> + Roles have a title and an allowed list of Abilities + that Members can perform. Members can belong to + one or more Roles. A group can have up to 10 Roles, + including the Everyone and Owner Roles. + </panel.string> + <panel.string + name="cant_delete_role"> + The 'Everyone' and 'Owners' Roles are special and can't be deleted. + </panel.string> + <panel.string + name="power_folder_icon" translate="false"> + Inv_FolderClosed + </panel.string> + <panel.string + name="power_all_have_icon" translate="false"> + Checkbox_On + </panel.string> + <panel.string + name="power_partial_icon" translate="false"> + Checkbox_Off + </panel.string> + <filter_editor + layout="topleft" + top="5" + left="5" + right="-5" + height="22" + search_button_visible="false" + follows="left|top|right" + label="Filter Roles" + name="filter_input" /> + <scroll_list + column_padding="0" + draw_heading="true" + draw_stripes="false" + heading_height="23" + height="132" + layout="topleft" + search_column="1" + left="0" + follows="left|top|right" + right="-1" + name="role_list" + top_pad="2" + width="310"> + <scroll_list.columns + label="Role" + name="name" + relative_width="0.45" /> + <scroll_list.columns + label="Title" + name="title" + relative_width="0.45" /> + <scroll_list.columns + label="#" + name="members" + relative_width="0.15" /> + </scroll_list> + <button + follows="top|left" + height="23" + label="New Role" + layout="topleft" + left="0" + name="role_create" + width="120" /> + <button + height="23" + follows="top|left" + label="Delete Role" + layout="topleft" + left_pad="10" + name="role_delete" + width="120" /> + </panel> <panel - height="350" - background_visible="false" - bg_alpha_color="FloaterUnfocusBorderColor" + border="false" + height="303" + label="ABILITIES" layout="topleft" - follows="top|left|right" left="0" right="-1" - width="313" - mouse_opaque="false" - name="members_footer" - top="325" - visible="false"> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - top="8" - text_color="EmphasisColor" - name="static" - width="300"> - Assigned Roles - </text> - <scroll_list - draw_stripes="true" - follows="left|top|right" - height="150" - layout="topleft" - left="0" - right="-1" - name="member_assigned_roles" - top_pad="0"> - <scroll_list.columns - label="" - name="checkbox" - width="20" /> - <scroll_list.columns - label="" - name="role" - width="270" /> - </scroll_list> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - top_pad="5" - text_color="EmphasisColor" - name="static2" - width="285"> - Allowed Abilities - </text> - <scroll_list - draw_stripes="true" - follows="left|top|right" - height="150" - layout="topleft" - left="0" - right="-1" - name="member_allowed_actions" - search_column="2" - tool_tip="For details of each allowed ability see the abilities tab" - top_pad="0"> - <scroll_list.columns - label="" - name="icon" - width="2" /> - <scroll_list.columns - label="" - name="checkbox" - width="20" /> - <scroll_list.columns - label="" - name="action" - width="270" /> - </scroll_list> + help_topic="roles_actions_tab" + name="actions_sub_tab" + class="panel_group_actions_subtab" + tool_tip="You can view an Ability's Description and which Roles and Members can execute the Ability." + width="310"> + <panel.string + name="help_text"> + Abilities allow Members in Roles to do specific + things in this group. There's a broad variety of Abilities. + </panel.string> + <panel.string + name="power_folder_icon" translate="false"> + Inv_FolderClosed + </panel.string> + <panel.string + name="power_all_have_icon" translate="false"> + Checkbox_On + </panel.string> + <panel.string + name="power_partial_icon" translate="false"> + Checkbox_Off + </panel.string> + <filter_editor + layout="topleft" + top="5" + left="5" + right="-5" + height="22" + search_button_visible="false" + follows="left|top|right" + label="Filter Abilities" + name="filter_input" /> + <scroll_list + column_padding="0" + draw_stripes="true" + height="200" + follows="left|top|right" + layout="topleft" + left="0" + right="-1" + name="action_list" + search_column="2" + tool_tip="Select an Ability to view more details" + top_pad="5" + width="300"> + <scroll_list.columns + label="" + name="icon" + width="2" /> + <scroll_list.columns + label="" + name="checkbox" + width="20" /> + <scroll_list.columns + label="" + name="action" + width="270" /> + </scroll_list> </panel> <panel - height="550" - background_visible="false" - bg_alpha_color="FloaterUnfocusBorderColor" + border="false" + height="303" + label="BANNED RESIDENTS" layout="topleft" - follows="top|left|right" left="0" right="-1" - width="313" - mouse_opaque="false" - name="roles_footer" - top_delta="0" - top="209" - visible="false"> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - top="5" - name="static" - width="300"> - Role Name - </text> - <line_editor - type="string" - height="20" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - max_length_bytes="20" - name="role_name" - top_pad="0" - width="300"> - </line_editor> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - name="static3" - top_pad="5" - width="300"> - Role Title - </text> - <line_editor - type="string" - height="20" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - max_length_bytes="20" - name="role_title" - top_pad="0" - width="300"> - </line_editor> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - name="static2" - top_pad="5" - width="200"> - Description - </text> - <text_editor - type="string" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - max_length="295" - height="35" - name="role_description" - top_pad="0" - width="300" - word_wrap="true"> - </text_editor> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - text_color="EmphasisColor" - name="static4" - top_pad="5" - width="300"> - Assigned Members - </text> - <name_list - draw_stripes="true" - height="128" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - name="role_assigned_members" - top_pad="0" - width="300" /> - <check_box - height="15" - label="Reveal members" - left="5" - layout="topleft" - name="role_visible_in_list" - tool_tip="Sets whether members of this role are visible in the General tab to people outside of the group." - top_pad="4" - width="300" /> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - text_color="EmphasisColor" - name="static5" - top_pad="2" - width="300"> - Allowed Abilities - </text> - <scroll_list - draw_stripes="true" - height="140" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - name="role_allowed_actions" - search_column="2" - tool_tip="For details of each allowed ability see the abilities tab" - top_pad="0" - width="300"> - <scroll_list.columns - label="" - name="icon" - width="2" /> - <scroll_list.columns - label="" - name="checkbox" - width="20" /> - <scroll_list.columns - label="" - name="action" - width="270" /> - </scroll_list> + help_topic="roles_banlist_tab" + name="banlist_sub_tab" + class="panel_group_banlist_subtab" + tool_tip="View the banned residents from this group." + width="310"> + <panel.string + name="help_text"> + Any resident on the ban list will be unable to join the group. + </panel.string> + <name_list + column_padding="0" + draw_heading="true" + height="400" + follows="left|top|right" + layout="topleft" + left="0" + right="-1" + multi_select="true" + name="ban_list" + short_names="false" + top_pad="5"> + <name_list.columns + label="Resident" + name="name" + font.name="SANSSERIF_SMALL" + font.style="NORMAL" + relative_width="0.7" /> + <name_list.columns + label="Date Banned" + name="ban_date" + relative_width="0.3" /> + </name_list> + <button + follows="top|left" + height="23" + label="Ban Resident(s)" + layout="topleft" + left="3" + name="ban_create" + tool_tip="Ban residents from your group" + width="120" /> + <button + follows="top|left" + height="23" + label="Remove Ban(s)" + layout="topleft" + left_pad="5" + name="ban_delete" + tool_tip="Unban selected residents from your group" + width="120" /> + <button + follows="top|left" + height="23" + width="23" + image_overlay="Refresh_Off" + layout="topleft" + left_pad="5" + name="ban_refresh" + tool_tip="Refresh the ban list" + /> </panel> - <panel - height="424" - background_visible="false" - bg_alpha_color="FloaterUnfocusBorderColor" + </tab_container> + <panel + height="350" + background_visible="false" + bg_alpha_color="FloaterUnfocusBorderColor" + layout="topleft" + follows="top|left|right" + left="0" + right="-1" + width="313" + mouse_opaque="false" + name="members_footer" + top="325" + visible="false"> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + top="8" + text_color="EmphasisColor" + name="static" + width="300"> + Assigned Roles + </text> + <scroll_list + draw_stripes="true" + follows="left|top|right" + height="150" layout="topleft" - follows="top|left|right" left="0" right="-1" - width="313" - mouse_opaque="false" - name="actions_footer" - top_delta="0" - top="255" - visible="false"> - <text_editor - bg_readonly_color="Transparent" - text_readonly_color="EmphasisColor" - font="SansSerifSmall" - type="string" - enabled="false" - halign="left" - layout="topleft" + name="member_assigned_roles" + top_pad="0"> + <scroll_list.columns + label="" + name="checkbox" + width="20" /> + <scroll_list.columns + label="" + name="role" + width="270" /> + </scroll_list> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + top_pad="5" + text_color="EmphasisColor" + name="static2" + width="285"> + Allowed Abilities + </text> + <scroll_list + draw_stripes="true" follows="left|top|right" - left="0" - right="-1" - height="90" - max_length="512" - name="action_description" - top="0" - word_wrap="true"> - This Ability is 'Eject Members from this Group'. Only an Owner can eject another Owner. - </text_editor> - <text + height="150" + layout="topleft" + left="0" + right="-1" + name="member_allowed_actions" + search_column="2" + tool_tip="For details of each allowed ability see the abilities tab" + top_pad="0"> + <scroll_list.columns + label="" + name="icon" + width="2" /> + <scroll_list.columns + label="" + name="checkbox" + width="20" /> + <scroll_list.columns + label="" + name="action" + width="270" /> + </scroll_list> + </panel> + <panel + height="550" + background_visible="false" + bg_alpha_color="FloaterUnfocusBorderColor" + layout="topleft" + follows="top|left|right" + left="0" + right="-1" + width="313" + mouse_opaque="false" + name="roles_footer" + top_delta="0" + top="209" + visible="false"> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + top="5" + name="static" + width="300"> + Role Name + </text> + <line_editor + type="string" + height="20" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + max_length_bytes="20" + name="role_name" + top_pad="0" + width="300"> + </line_editor> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + name="static3" + top_pad="5" + width="300"> + Role Title + </text> + <line_editor + type="string" + height="20" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + max_length_bytes="20" + name="role_title" + top_pad="0" + width="300"> + </line_editor> + <text type="string" height="16" layout="topleft" follows="left|top" left="5" name="static2" - top_pad="1" - width="300"> - Roles with this ability - </text> - <scroll_list - height="172" - layout="topleft" - follows="left|top|right" - left="5" - right="-1" - name="action_roles" - top_pad="0" - width="300" /> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - name="static3" top_pad="5" - width="300"> - Members with this ability - </text> - <name_list - height="122" - follows="left|top|right" - layout="topleft" - left="5" - right="-1" - name="action_members" - top_pad="0" - width="300" /> - </panel> + width="200"> + Description + </text> + <text_editor + type="string" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + max_length="295" + height="35" + name="role_description" + top_pad="0" + width="300" + word_wrap="true"> + </text_editor> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + text_color="EmphasisColor" + name="static4" + top_pad="5" + width="300"> + Assigned Members + </text> + <name_list + draw_stripes="true" + height="128" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + name="role_assigned_members" + top_pad="0" + width="300" /> + <check_box + height="15" + label="Reveal members" + left="5" + layout="topleft" + name="role_visible_in_list" + tool_tip="Sets whether members of this role are visible in the General tab to people outside of the group." + top_pad="4" + width="300" /> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + text_color="EmphasisColor" + name="static5" + top_pad="2" + width="300"> + Allowed Abilities + </text> + <scroll_list + draw_stripes="true" + height="140" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + name="role_allowed_actions" + search_column="2" + tool_tip="For details of each allowed ability see the abilities tab" + top_pad="0" + width="300"> + <scroll_list.columns + label="" + name="icon" + width="2" /> + <scroll_list.columns + label="" + name="checkbox" + width="20" /> + <scroll_list.columns + label="" + name="action" + width="270" /> + </scroll_list> + </panel> + <panel + height="424" + background_visible="false" + bg_alpha_color="FloaterUnfocusBorderColor" + layout="topleft" + follows="top|left|right" + left="0" + right="-1" + width="313" + mouse_opaque="false" + name="actions_footer" + top_delta="0" + top="255" + visible="false"> + <text_editor + bg_readonly_color="Transparent" + text_readonly_color="EmphasisColor" + font="SansSerifSmall" + type="string" + enabled="false" + halign="left" + layout="topleft" + follows="left|top|right" + left="0" + right="-1" + height="90" + max_length="512" + name="action_description" + top="0" + word_wrap="true"> + This Ability is 'Eject Members from this Group'. Only an Owner can eject another Owner. + </text_editor> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + name="static2" + top_pad="1" + width="300"> + Roles with this ability + </text> + <scroll_list + height="172" + layout="topleft" + follows="left|top|right" + left="5" + right="-1" + name="action_roles" + top_pad="0" + width="300" /> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + name="static3" + top_pad="5" + width="300"> + Members with this ability + </text> + <name_list + height="122" + follows="left|top|right" + layout="topleft" + left="5" + right="-1" + name="action_members" + top_pad="0" + width="300" /> + </panel> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_places.xml b/indra/newview/skins/default/xui/en/panel_places.xml index f169dbb702..7d171490e8 100755 --- a/indra/newview/skins/default/xui/en/panel_places.xml +++ b/indra/newview/skins/default/xui/en/panel_places.xml @@ -27,6 +27,7 @@ background_visible="true" label="Filter My Places" max_length_chars="300" name="Filter" + tab_group="1" top="3" width="303" /> <tab_container @@ -39,7 +40,7 @@ background_visible="true" tab_min_width="80" tab_max_width="157" tab_height="30" - tab_group="1" + tab_group="2" tab_position="top" top_pad="10" width="315" /> diff --git a/indra/newview/skins/default/xui/en/panel_region_debug.xml b/indra/newview/skins/default/xui/en/panel_region_debug.xml index 81b2281adb..fea5f1b19f 100755 --- a/indra/newview/skins/default/xui/en/panel_region_debug.xml +++ b/indra/newview/skins/default/xui/en/panel_region_debug.xml @@ -201,4 +201,14 @@ tool_tip="Cancel region restart" top_delta="0" width="150" /> + <button + follows="left|top" + height="20" + label="Region Debug Console" + layout="topleft" + left="10" + name="region_debug_console_btn" + tool_tip="Open Region Debug Console" + top_pad="5" + width="150" /> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_region_general.xml b/indra/newview/skins/default/xui/en/panel_region_general.xml index 44c84e69a1..489d286e67 100755 --- a/indra/newview/skins/default/xui/en/panel_region_general.xml +++ b/indra/newview/skins/default/xui/en/panel_region_general.xml @@ -94,11 +94,20 @@ width="80" /> <check_box height="20" + label="Block Parcel Fly Over" + layout="topleft" + left="10" + name="block_fly_over_check" + tool_tip="Extend access checks upwards to prevent flying over a parcel" + top="110" + width="90" /> + <check_box + height="20" label="Allow Damage" layout="topleft" left="10" name="allow_damage_check" - top="110" + top="130" width="80" /> <check_box height="20" @@ -106,7 +115,7 @@ layout="topleft" left="10" name="restrict_pushobject" - top="130" + top="150" width="80" /> <check_box height="20" @@ -114,7 +123,7 @@ layout="topleft" left="10" name="allow_land_resell_check" - top="150" + top="170" width="80" /> <check_box height="20" @@ -122,7 +131,7 @@ layout="topleft" left="10" name="allow_parcel_changes_check" - top="170" + top="190" width="80" /> <check_box height="20" @@ -131,7 +140,7 @@ left="10" name="block_parcel_search_check" tool_tip="Let people see this region and its parcels in search results" - top="190" + top="210" width="80" /> <spinner decimal_digits="0" @@ -145,7 +154,7 @@ max_val="100" min_val="1" name="agent_limit_spin" - top="240" + top="260" width="170" /> <spinner follows="left|top" @@ -158,7 +167,7 @@ max_val="10" min_val="1" name="object_bonus_spin" - top="260" + top="280" width="170" /> <text follows="left|top" @@ -167,7 +176,7 @@ layout="topleft" left="10" name="access_text" - top="290" + top="310" width="100"> Rating: </text> @@ -224,7 +233,7 @@ layout="topleft" left="108" name="apply_btn" - top="320" + top="340" width="100"/> <button follows="left|top" diff --git a/indra/newview/skins/default/xui/en/role_actions.xml b/indra/newview/skins/default/xui/en/role_actions.xml index 0eeccbeac5..1044cbfd2e 100755 --- a/indra/newview/skins/default/xui/en/role_actions.xml +++ b/indra/newview/skins/default/xui/en/role_actions.xml @@ -9,7 +9,10 @@ <action description="Eject Members from this Group" longdescription="Eject Members from this Group using the 'Eject' button in the Roles section > Members tab. An Owner can eject anyone except another Owner. If you're not an Owner, a Member can be ejected from a group if, and only if, they're only in the Everyone Role, and NO other Roles. To remove Members from Roles, you need to have the 'Remove Members from Roles' Ability." name="member eject" value="2" /> - <action + <action description="Manage ban list" + longdescription="Allows the group member to ban / un-ban Residents from this group." + name="allow ban" value="51" /> + <action description="Toggle 'Open Enrollment' and change 'Enrollment fee'" longdescription="Toggle 'Open Enrollment' to let new Members join without an invitation, and change the 'Enrollment fee' in the General section." name="member options" value="3" /> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 437b7310f5..0848762e22 100755 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -2267,6 +2267,7 @@ The [[MARKETPLACE_CREATE_STORE_URL] Marketplace store] is returning errors. <string name="Marketplace Error Internal Import">Error: There was a problem with this item. Try again later.</string> <string name="Open landmarks">Open landmarks</string> + <string name="Unconstrained">Unconstrained</string> <!-- use value="" because they have preceding spaces --> <string name="no_transfer" value=" (no transfer)" /> @@ -3741,6 +3742,7 @@ Abuse Report</string> <string name="LocalEstimateUSD">US$ [AMOUNT]</string> <!-- Group Profile roles and powers --> + <string name="Group Ban">Group Ban</string> <string name="Membership">Membership</string> <string name="Roles">Roles</string> <string name="Group Identity">Group Identity</string> diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index 484511a08b..2b91c542ad 100755 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -1252,7 +1252,8 @@ Intenta iniciar sesión de nuevo en unos instantes. <string name="InventoryInboxNoItems"> Aquí aparecerán algunos de los objetos que recibas, como los regalos Premium. Después puedes arrastrarlos a tu inventario. </string> - <string name="MarketplaceURL"> + <string name="Unconstrained">Sin restricciones</string> + <string name="MarketplaceURL"> https://marketplace.[MARKETPLACE_DOMAIN_NAME]/ </string> <string name="MarketplaceURL_CreateStore"> diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml index 78d846ff4f..b8721420cb 100755 --- a/indra/newview/skins/default/xui/fr/strings.xml +++ b/indra/newview/skins/default/xui/fr/strings.xml @@ -1270,7 +1270,8 @@ Veuillez réessayer de vous connecter dans une minute. <string name="InventoryInboxNoItems"> Les achats que vous avez effectués sur la Place du marché s'affichent ici. Vous pouvez alors les faire glisser vers votre inventaire afin de les utiliser. </string> - <string name="MarketplaceURL"> + <string name="Unconstrained">Sans contraintes</string> + <string name="MarketplaceURL"> https://marketplace.[MARKETPLACE_DOMAIN_NAME]/ </string> <string name="MarketplaceURL_CreateStore"> diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml index 60ed2b0929..86d7f75b83 100755 --- a/indra/newview/skins/default/xui/it/strings.xml +++ b/indra/newview/skins/default/xui/it/strings.xml @@ -1261,7 +1261,8 @@ Prova ad accedere nuovamente tra un minuto. <string name="InventoryInboxNoItems"> Gli acquissti dal mercato verranno mostrati qui. Potrai quindi trascinarli nel tuo inventario per usarli. </string> - <string name="MarketplaceURL"> + <string name="Unconstrained">Libero</string> + <string name="MarketplaceURL"> https://marketplace.[MARKETPLACE_DOMAIN_NAME]/ </string> <string name="MarketplaceURL_CreateStore"> diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml index a0f45e5a55..36966d6825 100755 --- a/indra/newview/skins/default/xui/ja/strings.xml +++ b/indra/newview/skins/default/xui/ja/strings.xml @@ -1270,7 +1270,8 @@ support@secondlife.com にお問い合わせください。 <string name="InventoryInboxNoItems"> マーケットプレイスで購入した商品はここに表示されます。その後、アイテムをインベントリにドラッグすれば、それらのアイテムを使用できます。 </string> - <string name="MarketplaceURL"> + <string name="Unconstrained">非拘束</string> + <string name="MarketplaceURL"> https://marketplace.[MARKETPLACE_DOMAIN_NAME]/ </string> <string name="MarketplaceURL_CreateStore"> diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml index f6dec8536b..f86e393646 100755 --- a/indra/newview/skins/default/xui/pl/strings.xml +++ b/indra/newview/skins/default/xui/pl/strings.xml @@ -1035,6 +1035,7 @@ <string name="InventoryNoTexture"> Nie posiadasz kopii tej tekstury w Twojej Szafie. </string> + <string name="Unconstrained">Swobodny</string> <string name="no_transfer" value=" (brak oddawania)"/> <string name="no_modify" value=" (brak modyfikowania)"/> <string name="no_copy" value=" (brak kopiowania)"/> diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml index 2eb4c0a02e..8436452228 100755 --- a/indra/newview/skins/default/xui/pt/strings.xml +++ b/indra/newview/skins/default/xui/pt/strings.xml @@ -1216,7 +1216,8 @@ Pessoas com contas gratuitas não poderão acessar o Second Life no momento para <string name="InventoryInboxNoItems"> Suas compras do Marketplace aparecerão aqui. Depois, você poderá arrastá-las para seu inventário para usá-las. </string> - <string name="MarketplaceURL"> + <string name="Unconstrained">Sem limites</string> + <string name="MarketplaceURL"> https://marketplace.[MARKETPLACE_DOMAIN_NAME]/ </string> <string name="MarketplaceURL_CreateStore"> diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml index 0f71edcee0..8faf834f8f 100755 --- a/indra/newview/skins/default/xui/ru/strings.xml +++ b/indra/newview/skins/default/xui/ru/strings.xml @@ -1267,7 +1267,8 @@ support@secondlife.com. <string name="InventoryInboxNoItems"> Здесь будут показаны ваши покупки из торгового центра. Их можно будет перетащить в ваш инвентарь для использования. </string> - <string name="MarketplaceURL"> + <string name="Unconstrained">Без ограничения</string> + <string name="MarketplaceURL"> https://marketplace.[MARKETPLACE_DOMAIN_NAME]/ </string> <string name="MarketplaceURL_CreateStore"> diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml index c4b1530b2b..31c5d2d310 100755 --- a/indra/newview/skins/default/xui/tr/strings.xml +++ b/indra/newview/skins/default/xui/tr/strings.xml @@ -1267,7 +1267,8 @@ Lütfen bir dakika içerisinde tekrar oturum açmayı deneyin. <string name="InventoryInboxNoItems"> Pazaryerinda satın aldıklarınız burada görünecektir. Bunları kullanmak için envanterinize sürükleyebilirsiniz. </string> - <string name="MarketplaceURL"> + <string name="Unconstrained">Kısıtsız</string> + <string name="MarketplaceURL"> https://marketplace.[MARKETPLACE_DOMAIN_NAME]/ </string> <string name="MarketplaceURL_CreateStore"> diff --git a/indra/newview/tests/llhttpretrypolicy_test.cpp b/indra/newview/tests/llhttpretrypolicy_test.cpp new file mode 100755 index 0000000000..25e6de46d9 --- /dev/null +++ b/indra/newview/tests/llhttpretrypolicy_test.cpp @@ -0,0 +1,328 @@ +/** + * @file llhttpretrypolicy_test.cpp + * @brief Header tests to exercise the LLHTTPRetryPolicy classes. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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 "../llhttpretrypolicy.h" +#include "lltut.h" + +namespace tut +{ +struct TestData +{ +}; + +typedef test_group<TestData> RetryPolicyTestGroup; +typedef RetryPolicyTestGroup::object RetryPolicyTestObject; +RetryPolicyTestGroup retryPolicyTestGroup("retry_policy"); + +template<> template<> +void RetryPolicyTestObject::test<1>() +{ + LLAdaptiveRetryPolicy never_retry(1.0,1.0,1.0,0); + LLSD headers; + F32 wait_seconds; + + // No retry until we've failed a try. + ensure("never retry 0", !never_retry.shouldRetry(wait_seconds)); + + // 0 retries max. + never_retry.onFailure(500,headers); + ensure("never retry 1", !never_retry.shouldRetry(wait_seconds)); +} + +template<> template<> +void RetryPolicyTestObject::test<2>() +{ + LLSD headers; + F32 wait_seconds; + + // Normally only retry on server error (5xx) + LLAdaptiveRetryPolicy noRetry404(1.0,2.0,3.0,10); + noRetry404.onFailure(404,headers); + ensure("no retry on 404", !noRetry404.shouldRetry(wait_seconds)); + + // Can retry on 4xx errors if enabled by flag. + bool do_retry_4xx = true; + LLAdaptiveRetryPolicy doRetry404(1.0,2.0,3.0,10,do_retry_4xx); + doRetry404.onFailure(404,headers); + ensure("do retry on 404", doRetry404.shouldRetry(wait_seconds)); +} + +template<> template<> +void RetryPolicyTestObject::test<3>() +{ + // Should retry after 1.0, 2.0, 3.0, 3.0 seconds. + LLAdaptiveRetryPolicy basic_retry(1.0,3.0,2.0,4); + LLSD headers; + F32 wait_seconds; + bool should_retry; + U32 frac_bits = 6; + + // No retry until we've failed a try. + ensure("basic_retry 0", !basic_retry.shouldRetry(wait_seconds)); + + // Starting wait 1.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 1", should_retry); + ensure_approximately_equals("basic_retry 1", wait_seconds, 1.0F, frac_bits); + + // Double wait to 2.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 2", should_retry); + ensure_approximately_equals("basic_retry 2", wait_seconds, 2.0F, frac_bits); + + // Hit max wait of 3.0 (4.0 clamped to max 3) + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 3", should_retry); + ensure_approximately_equals("basic_retry 3", wait_seconds, 3.0F, frac_bits); + + // At max wait, should stay at 3.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 4", should_retry); + ensure_approximately_equals("basic_retry 4", wait_seconds, 3.0F, frac_bits); + + // Max retries, should fail now. + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 5", !should_retry); + + // Max retries, should fail now. + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 5", !should_retry); + + // After a success, should reset to the starting state. + basic_retry.onSuccess(); + + // No retry until we've failed a try. + ensure("basic_retry 6", !basic_retry.shouldRetry(wait_seconds)); + + // Starting wait 1.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 7", should_retry); + ensure_approximately_equals("basic_retry 7", wait_seconds, 1.0F, frac_bits); + + // Double wait to 2.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 8", should_retry); + ensure_approximately_equals("basic_retry 8", wait_seconds, 2.0F, frac_bits); +} + +// Retries should stop as soon as a non-5xx error is received. +template<> template<> +void RetryPolicyTestObject::test<4>() +{ + // Should retry after 1.0, 2.0, 3.0, 3.0 seconds. + LLAdaptiveRetryPolicy killer404(1.0,3.0,2.0,4); + LLSD headers; + F32 wait_seconds; + bool should_retry; + U32 frac_bits = 6; + + // Starting wait 1.0 + killer404.onFailure(500,headers); + should_retry = killer404.shouldRetry(wait_seconds); + ensure("killer404 1", should_retry); + ensure_approximately_equals("killer404 1", wait_seconds, 1.0F, frac_bits); + + // Double wait to 2.0 + killer404.onFailure(500,headers); + should_retry = killer404.shouldRetry(wait_seconds); + ensure("killer404 2", should_retry); + ensure_approximately_equals("killer404 2", wait_seconds, 2.0F, frac_bits); + + // Should fail on non-5xx + killer404.onFailure(404,headers); + should_retry = killer404.shouldRetry(wait_seconds); + ensure("killer404 3", !should_retry); + + // After a non-5xx, should keep failing. + killer404.onFailure(500,headers); + should_retry = killer404.shouldRetry(wait_seconds); + ensure("killer404 4", !should_retry); +} + +// Test handling of "retry-after" header. If present, this header +// value overrides the computed delay, but does not affect the +// progression of delay values. For example, if the normal +// progression of delays would be 1,2,4,8..., but the 2nd and 3rd calls +// get a retry header of 33, the pattern would become 1,33,33,8... +template<> template<> +void RetryPolicyTestObject::test<5>() +{ + LLAdaptiveRetryPolicy policy(1.0,25.0,2.0,6); + LLSD headers_with_retry; + headers_with_retry[HTTP_IN_HEADER_RETRY_AFTER] = "666"; + LLSD headers_without_retry; + F32 wait_seconds; + bool should_retry; + U32 frac_bits = 6; + + policy.onFailure(500,headers_without_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 1", should_retry); + ensure_approximately_equals("retry header 1", wait_seconds, 1.0F, frac_bits); + + policy.onFailure(500,headers_without_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 2", should_retry); + ensure_approximately_equals("retry header 2", wait_seconds, 2.0F, frac_bits); + + policy.onFailure(500,headers_with_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 3", should_retry); + // 4.0 overrides by header -> 666.0 + ensure_approximately_equals("retry header 3", wait_seconds, 666.0F, frac_bits); + + policy.onFailure(500,headers_with_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 4", should_retry); + // 8.0 overrides by header -> 666.0 + ensure_approximately_equals("retry header 4", wait_seconds, 666.0F, frac_bits); + + policy.onFailure(500,headers_without_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 5", should_retry); + ensure_approximately_equals("retry header 5", wait_seconds, 16.0F, frac_bits); + + policy.onFailure(500,headers_without_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 6", should_retry); + ensure_approximately_equals("retry header 6", wait_seconds, 25.0F, frac_bits); + + policy.onFailure(500,headers_with_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 7", !should_retry); +} + +// Test getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait), +// used by header parsing of the retry policy. +template<> template<> +void RetryPolicyTestObject::test<6>() +{ + F32 seconds_to_wait; + bool success; + + std::string str1("0"); + seconds_to_wait = F32_MAX; + success = getSecondsUntilRetryAfter(str1, seconds_to_wait); + ensure("parse 1", success); + ensure_equals("parse 1", seconds_to_wait, 0.0); + + std::string str2("999.9"); + seconds_to_wait = F32_MAX; + success = getSecondsUntilRetryAfter(str2, seconds_to_wait); + ensure("parse 2", success); + ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8); + + time_t nowseconds; + time(&nowseconds); + std::string str3 = LLDate((F64)(nowseconds+44)).asRFC1123(); + seconds_to_wait = F32_MAX; + success = getSecondsUntilRetryAfter(str3, seconds_to_wait); + std::cerr << " str3 [" << str3 << "]" << std::endl; + ensure("parse 3", success); + ensure_approximately_equals_range("parse 3", seconds_to_wait, 44.0F, 2.0F); +} + +// Test retry-after field in both llmessage and CoreHttp headers. +template<> template<> +void RetryPolicyTestObject::test<7>() +{ + std::cerr << "7 starts" << std::endl; + + LLSD sd_headers; + time_t nowseconds; + time(&nowseconds); + LLAdaptiveRetryPolicy policy(17.0,644.0,3.0,5); + F32 seconds_to_wait; + bool should_retry; + + // No retry until we've failed a try. + ensure("header 0", !policy.shouldRetry(seconds_to_wait)); + + // no retry header, use default. + policy.onFailure(500,LLSD()); + should_retry = policy.shouldRetry(seconds_to_wait); + ensure("header 1", should_retry); + ensure_approximately_equals("header 1", seconds_to_wait, 17.0F, 6); + + // retry header should override, give delay of 0 + std::string date_string = LLDate((F64)(nowseconds+7)).asRFC1123(); + sd_headers[HTTP_IN_HEADER_RETRY_AFTER] = date_string; + policy.onFailure(503,sd_headers); + should_retry = policy.shouldRetry(seconds_to_wait); + ensure("header 2", should_retry); + ensure_approximately_equals_range("header 2", seconds_to_wait, 7.0F, 2.0F); + + LLCore::HttpResponse *response; + LLCore::HttpHeaders *headers; + + response = new LLCore::HttpResponse(); + headers = new LLCore::HttpHeaders(); + response->setStatus(503); + response->setHeaders(headers); + headers->append(HTTP_IN_HEADER_RETRY_AFTER, std::string("600")); + policy.onFailure(response); + should_retry = policy.shouldRetry(seconds_to_wait); + ensure("header 3",should_retry); + ensure_approximately_equals("header 3", seconds_to_wait, 600.0F, 6); + response->release(); + + response = new LLCore::HttpResponse(); + headers = new LLCore::HttpHeaders(); + response->setStatus(503); + response->setHeaders(headers); + time(&nowseconds); + date_string = LLDate((F64)(nowseconds+77)).asRFC1123(); + std::cerr << "date_string [" << date_string << "]" << std::endl; + headers->append(HTTP_IN_HEADER_RETRY_AFTER,date_string); + policy.onFailure(response); + should_retry = policy.shouldRetry(seconds_to_wait); + ensure("header 4",should_retry); + ensure_approximately_equals_range("header 4", seconds_to_wait, 77.0F, 2.0F); + response->release(); + + // Timeout should be clamped at max. + policy.onFailure(500,LLSD()); + should_retry = policy.shouldRetry(seconds_to_wait); + ensure("header 5", should_retry); + ensure_approximately_equals("header 5", seconds_to_wait, 644.0F, 6); + + // No more retries. + policy.onFailure(500,LLSD()); + should_retry = policy.shouldRetry(seconds_to_wait); + ensure("header 6", !should_retry); +} + +} + diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp index 3e55336f2d..6f57daf151 100755 --- a/indra/newview/tests/llmediadataclient_test.cpp +++ b/indra/newview/tests/llmediadataclient_test.cpp @@ -33,7 +33,7 @@ #include "llsdserialize.h" #include "llsdutil.h" #include "llerrorcontrol.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h" #include "../llmediadataclient.h" #include "../llvovolume.h" @@ -129,7 +129,7 @@ void LLHTTPClient::post( { LLSD content; content["reason"] = "fake reason"; - responder->errorWithContent(HTTP_SERVICE_UNAVAILABLE, "fake reason", content); + responder->failureResult(HTTP_SERVICE_UNAVAILABLE, "fake reason", content); return; } else if (url == FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR) @@ -137,8 +137,8 @@ void LLHTTPClient::post( LLSD error; error["code"] = LLObjectMediaNavigateClient::ERROR_PERMISSION_DENIED_CODE; result["error"] = error; - } - responder->result(result); + } + responder->successResult(result); } const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index ed66066b0a..c49b0350e9 100755 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -40,12 +40,14 @@ namespace { LLCurl::Responder::Responder() { } LLCurl::Responder::~Responder() { } -void LLCurl::Responder::error(U32,std::string const &) { } -void LLCurl::Responder::result(LLSD const &) { } -void LLCurl::Responder::errorWithContent(U32 status,std::string const &,LLSD const &) { } -void LLCurl::Responder::completedRaw(U32 status, std::string const &, LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { } -void LLCurl::Responder::completed(U32 status, std::string const &, LLSD const &) { } -void LLCurl::Responder::completedHeader(U32 status, std::string const &, LLSD const &) { } +void LLCurl::Responder::httpFailure() { } +void LLCurl::Responder::httpSuccess() { } +void LLCurl::Responder::httpCompleted() { } +void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content) { } +void LLCurl::Responder::successResult(const LLSD& content) { } +void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content) { } +std::string LLCurl::Responder::dumpResponse() const { return "(failure)"; } +void LLCurl::Responder::completedRaw(LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { } void LLMessageSystem::getF32(char const *,char const *,F32 &,S32) { } void LLMessageSystem::getU8(char const *,char const *,U8 &,S32) { } void LLMessageSystem::getS32(char const *,char const *,S32 &,S32) { } @@ -85,7 +87,7 @@ namespace tut virtual void setParcelID(const LLUUID& parcel_id) { } - virtual void setErrorStatus(U32 status, const std::string& reason) { } + virtual void setErrorStatus(S32 status, const std::string& reason) { } bool mProcessed; }; diff --git a/indra/newview/tests/lltranslate_test.cpp b/indra/newview/tests/lltranslate_test.cpp index 8ce56326d8..5e73dbb981 100755 --- a/indra/newview/tests/lltranslate_test.cpp +++ b/indra/newview/tests/lltranslate_test.cpp @@ -34,6 +34,8 @@ #include "lltrans.h" #include "llui.h" +#include "../../llmessage/llhttpconstants.cpp" + static const std::string GOOGLE_VALID_RESPONSE1 = "{\ \"data\": {\ @@ -300,12 +302,10 @@ std::string LLControlGroup::getString(const std::string& name) { return "dummy"; LLControlGroup::~LLControlGroup() {} LLCurl::Responder::Responder() {} -void LLCurl::Responder::completedHeader(U32, std::string const&, LLSD const&) {} -void LLCurl::Responder::completedRaw(U32, const std::string&, const LLChannelDescriptors&, const LLIOPipe::buffer_ptr_t& buffer) {} -void LLCurl::Responder::completed(U32, std::string const&, LLSD const&) {} -void LLCurl::Responder::error(U32, std::string const&) {} -void LLCurl::Responder::errorWithContent(U32, std::string const&, LLSD const&) {} -void LLCurl::Responder::result(LLSD const&) {} +void LLCurl::Responder::httpFailure() { } +void LLCurl::Responder::httpSuccess() { } +void LLCurl::Responder::httpCompleted() { } +void LLCurl::Responder::completedRaw(LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { } LLCurl::Responder::~Responder() {} void LLHTTPClient::get(const std::string&, const LLSD&, ResponderPtr, const LLSD&, const F32, bool) {} |