diff --git a/autobuild.xml b/autobuild.xml
index 8642d74b0f..c519579637 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -462,9 +462,11 @@
archive
name
darwin64
@@ -474,9 +476,11 @@
archive
name
windows64
@@ -489,7 +493,7 @@
copyright
Copyright 2017-2019 Miles Johnson.
version
- 6.1.0.579438
+ 6.1.0.5413f58
name
emoji_shortcodes
canonical_repo
@@ -955,54 +959,6 @@
description
Havok source code for libs and demos
- icu4c
-
jpegencoderbasic
platforms
@@ -1668,6 +1624,18 @@
name
linux64
+ windows64
+
+ archive
+
+ hash
+ 2e5f1f7046a49d8b0bc295aa878116bc
+ url
+ http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/60043/564063/llphysicsextensions_stub-1.0.542456-windows-542456.tar.bz2
+
+ name
+ windows64
+
license
internal
@@ -2739,11 +2707,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- eb1316584188dafb591f80b46b357c737f90d1a7
+ 8a04e6b3c6ff7f645219955a1389035565eb10d8
hash_algorithm
sha1
url
- https://github.com/secondlife/viewer-manager/releases/download/v3.0-08bf5ee/viewer_manager-3.0-08bf5ee-darwin64-08bf5ee.tar.zst
+ https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-darwin64-f14b5ec.tar.zst
name
darwin64
@@ -2753,11 +2721,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- f4677b0ebd9880f29c118af51ada50883dd0a1e4
+ a1e467c08ecbe6ab24fc8756a815a431a9b00f62
hash_algorithm
sha1
url
- https://github.com/secondlife/viewer-manager/releases/download/v3.0-08bf5ee/viewer_manager-3.0-08bf5ee-linux64-08bf5ee.tar.zst
+ https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-linux64-f14b5ec.tar.zst
name
linux64
@@ -2767,11 +2735,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 7426c5a1d7eb231b476625637a1f2daba0a6bc55
+ 56b613decdd36b2a17646bf3e2cfc2fed8456b8c
hash_algorithm
sha1
url
- https://github.com/secondlife/viewer-manager/releases/download/v3.0-08bf5ee/viewer_manager-3.0-08bf5ee-windows64-08bf5ee.tar.zst
+ https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-windows64-f14b5ec.tar.zst
name
windows64
@@ -2783,8 +2751,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
LICENSE
copyright
Copyright (c) 2000-2012, Linden Research, Inc.
- version
- 3.0-08bf5ee
name
viewer-manager
description
@@ -2793,6 +2759,8 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
https://bitbucket.org/lindenlab/vmp-standalone
source_type
hg
+ version
+ 3.0-f14b5ec
vlc-bin
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 15aec5e282..024ca90d2f 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -245,7 +245,8 @@ Ansariel Hiller
SL-19623
SL-4126
SL-20224
- https://github.com/secondlife/viewer/issues/1051
+ SL-20524
+ secondlife/viewer#1051
Aralara Rajal
Arare Chantilly
CHUIBUG-191
@@ -389,6 +390,7 @@ Chaser Zaks
BUG-225599
BUG-227485
SL-16874
+ SL-20442
Cherry Cheevers
ChickyBabes Zuzu
Chorazin Allen
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index da7e4be464..df05032172 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -30,7 +30,6 @@ set(cmake_SOURCE_FILES
GoogleMock.cmake
Havok.cmake
Hunspell.cmake
- ICU4C.cmake
JsonCpp.cmake
LLAddBuildTest.cmake
LLAppearance.cmake
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 262cd5813d..7938d4f54b 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -50,7 +50,7 @@ if(WINDOWS)
endif (ADDRESS_SIZE EQUAL 64)
#*******************************
- # Misc shared libs
+ # Misc shared libs
set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
set(release_files
@@ -62,15 +62,6 @@ if(WINDOWS)
uriparser.dll
)
- # ICU4C (same filenames for 32 and 64 bit builds)
- set(release_files ${release_files} icudt48.dll)
- set(release_files ${release_files} icuin48.dll)
- set(release_files ${release_files} icuio48.dll)
- set(release_files ${release_files} icule48.dll)
- set(release_files ${release_files} iculx48.dll)
- set(release_files ${release_files} icutu48.dll)
- set(release_files ${release_files} icuuc48.dll)
-
# OpenSSL
if(ADDRESS_SIZE EQUAL 64)
set(release_files ${release_files} libcrypto-1_1-x64.dll)
diff --git a/indra/cmake/ICU4C.cmake b/indra/cmake/ICU4C.cmake
deleted file mode 100644
index 7b27665483..0000000000
--- a/indra/cmake/ICU4C.cmake
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-
-include_guard()
-
-add_library( ll::icu4c INTERFACE IMPORTED )
-
-
-use_system_binary(icu4c)
-use_prebuilt_binary(icu4c)
-if (WINDOWS)
- target_link_libraries( ll::icu4c INTERFACE icuuc)
-elseif(DARWIN)
- target_link_libraries( ll::icu4c INTERFACE icuuc)
-#elseif(LINUX)
-## target_link_libraries( ll::icu4c INTERFACE )
-else()
- message(FATAL_ERROR "Invalid platform")
-endif()
-
-target_include_directories( ll::icu4c SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/unicode )
-
-use_prebuilt_binary(dictionaries)
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index ff222c0e89..d73be024cf 100644
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -494,70 +494,45 @@ void LLAvatarAppearance::computeBodySize()
mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale();
mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition();
- LLVector3 pelvis_scale = mPelvisp->getScale();
-
- // some of the joints have not been cached
- LLVector3 skull = mSkullp->getPosition();
- //LLVector3 skull_scale = mSkullp->getScale();
-
- LLVector3 neck = mNeckp->getPosition();
- LLVector3 neck_scale = mNeckp->getScale();
-
- LLVector3 chest = mChestp->getPosition();
- LLVector3 chest_scale = mChestp->getScale();
-
- // the rest of the joints have been cached
- LLVector3 head = mHeadp->getPosition();
- LLVector3 head_scale = mHeadp->getScale();
-
- LLVector3 torso = mTorsop->getPosition();
- LLVector3 torso_scale = mTorsop->getScale();
-
- LLVector3 hip = mHipLeftp->getPosition();
- LLVector3 hip_scale = mHipLeftp->getScale();
-
- LLVector3 knee = mKneeLeftp->getPosition();
- LLVector3 knee_scale = mKneeLeftp->getScale();
-
- LLVector3 ankle = mAnkleLeftp->getPosition();
- LLVector3 ankle_scale = mAnkleLeftp->getScale();
-
- LLVector3 foot = mFootLeftp->getPosition();
-
+ F32 old_height = mBodySize.mV[VZ];
F32 old_offset = mAvatarOffset.mV[VZ];
- mAvatarOffset.mV[VZ] = getVisualParamWeight(AVATAR_HOVER);
+ // TODO: Measure the real depth and width
+ mPelvisToFoot = computePelvisToFoot();
+ F32 new_height = computeBodyHeight();
+ mBodySize.set(DEFAULT_AGENT_DEPTH, DEFAULT_AGENT_WIDTH, new_height);
+ F32 new_offset = getVisualParamWeight(AVATAR_HOVER);
+ mAvatarOffset.set(0, 0, new_offset);
- mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] -
- knee.mV[VZ] * hip_scale.mV[VZ] -
- ankle.mV[VZ] * knee_scale.mV[VZ] -
- foot.mV[VZ] * ankle_scale.mV[VZ];
-
- LLVector3 new_body_size;
- new_body_size.mV[VZ] = mPelvisToFoot +
- // the sqrt(2) correction below is an approximate
- // correction to get to the top of the head
- F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) +
- head.mV[VZ] * neck_scale.mV[VZ] +
- neck.mV[VZ] * chest_scale.mV[VZ] +
- chest.mV[VZ] * torso_scale.mV[VZ] +
- torso.mV[VZ] * pelvis_scale.mV[VZ];
-
- // TODO -- measure the real depth and width
- new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH;
- new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH;
-
- mAvatarOffset.mV[VX] = 0.0f;
- mAvatarOffset.mV[VY] = 0.0f;
-
- if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ])
+ if (mBodySize.mV[VZ] != old_height || new_offset != old_offset)
{
- mBodySize = new_body_size;
-
compareJointStateMaps(mLastBodySizeState, mCurrBodySizeState);
}
}
+F32 LLAvatarAppearance::computeBodyHeight()
+{
+ F32 result = mPelvisToFoot +
+ // all these relative positions usually are positive
+ mPelvisp->getScale().mV[VZ] * mTorsop->getPosition().mV[VZ] +
+ mTorsop->getScale().mV[VZ] * mChestp->getPosition().mV[VZ] +
+ mChestp->getScale().mV[VZ] * mNeckp->getPosition().mV[VZ] +
+ mNeckp->getScale().mV[VZ] * mHeadp->getPosition().mV[VZ] +
+ mHeadp->getScale().mV[VZ] * mSkullp->getPosition().mV[VZ] * 2;
+ return result;
+}
+
+F32 LLAvatarAppearance::computePelvisToFoot()
+{
+ F32 result =
+ // all these relative positions usually are negative
+ mPelvisp->getScale().mV[VZ] * mHipLeftp->getPosition().mV[VZ] +
+ mHipLeftp->getScale().mV[VZ] * mKneeLeftp->getPosition().mV[VZ] +
+ mKneeLeftp->getScale().mV[VZ] * mAnkleLeftp->getPosition().mV[VZ] +
+ mAnkleLeftp->getScale().mV[VZ] * mFootLeftp->getPosition().mV[VZ] / 2;
+ return -result;
+}
+
//-----------------------------------------------------------------------------
// parseSkeletonFile()
//-----------------------------------------------------------------------------
diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h
index 435ce8bc49..9dd1ddffad 100644
--- a/indra/llappearance/llavatarappearance.h
+++ b/indra/llappearance/llavatarappearance.h
@@ -146,7 +146,9 @@ public:
joint_state_map_t mCurrBodySizeState;
void compareJointStateMaps(joint_state_map_t& last_state,
joint_state_map_t& curr_state);
- void computeBodySize();
+ void computeBodySize();
+ F32 computeBodyHeight();
+ F32 computePelvisToFoot();
public:
typedef std::vector avatar_joint_list_t;
diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp
index 9254062e29..f04bae3d62 100644
--- a/indra/llappearance/llwearable.cpp
+++ b/indra/llappearance/llwearable.cpp
@@ -550,7 +550,7 @@ void LLWearable::revertValues()
if(param)
{
F32 value = vp_pair.second;
- setVisualParamWeight(id, value);
+ param->setWeight(value);
mSavedVisualParamMap[id] = param->getWeight();
}
}
diff --git a/indra/llcharacter/llmultigesture.cpp b/indra/llcharacter/llmultigesture.cpp
index cb153ba827..e5ca051f82 100644
--- a/indra/llcharacter/llmultigesture.cpp
+++ b/indra/llcharacter/llmultigesture.cpp
@@ -42,16 +42,6 @@ const S32 GESTURE_VERSION = 2;
// LLMultiGesture
//---------------------------------------------------------------------------
LLMultiGesture::LLMultiGesture()
-: mKey(),
- mMask(),
- mName(),
- mTrigger(),
- mReplaceText(),
- mSteps(),
- mPlaying(FALSE),
- mCurrentStep(0),
- mDoneCallback(NULL),
- mCallbackData(NULL)
{
reset();
}
@@ -67,8 +57,11 @@ void LLMultiGesture::reset()
mPlaying = FALSE;
mCurrentStep = 0;
mWaitTimer.reset();
- mWaitingTimer = FALSE;
mWaitingAnimations = FALSE;
+ mWaitingKeyRelease = FALSE;
+ mWaitingTimer = FALSE;
+ mTriggeredByKey = FALSE;
+ mKeyReleased = FALSE;
mWaitingAtEnd = FALSE;
mRequestedAnimIDs.clear();
mPlayingAnimIDs.clear();
diff --git a/indra/llcharacter/llmultigesture.h b/indra/llcharacter/llmultigesture.h
index acb0bc7cb2..bc9963f2b1 100644
--- a/indra/llcharacter/llmultigesture.h
+++ b/indra/llcharacter/llmultigesture.h
@@ -59,8 +59,8 @@ protected:
const LLMultiGesture& operator=(const LLMultiGesture& rhs);
public:
- KEY mKey;
- MASK mMask;
+ KEY mKey { 0 };
+ MASK mMask { 0 };
// This name can be empty if the inventory item is not around and
// the gesture manager has not yet set the name
@@ -75,25 +75,34 @@ public:
std::vector mSteps;
// Is the gesture currently playing?
- BOOL mPlaying;
+ BOOL mPlaying { FALSE };
// "instruction pointer" for steps
- S32 mCurrentStep;
+ S32 mCurrentStep { 0 };
// We're waiting for triggered animations to stop playing
- BOOL mWaitingAnimations;
+ BOOL mWaitingAnimations { FALSE };
+
+ // We're waiting for key release
+ BOOL mWaitingKeyRelease { FALSE };
// We're waiting a fixed amount of time
- BOOL mWaitingTimer;
+ BOOL mWaitingTimer { FALSE };
+
+ // We're waiting for triggered animations to stop playing
+ BOOL mTriggeredByKey { FALSE };
+
+ // Has the key been released?
+ BOOL mKeyReleased { FALSE };
// Waiting after the last step played for all animations to complete
- BOOL mWaitingAtEnd;
+ BOOL mWaitingAtEnd { FALSE };
// Timer for waiting
LLFrameTimer mWaitTimer;
- void (*mDoneCallback)(LLMultiGesture* gesture, void* data);
- void* mCallbackData;
+ void (*mDoneCallback)(LLMultiGesture* gesture, void* data) { NULL };
+ void* mCallbackData { NULL };
// Animations that we requested to start
std::set mRequestedAnimIDs;
@@ -210,6 +219,7 @@ public:
const U32 WAIT_FLAG_TIME = 0x01;
const U32 WAIT_FLAG_ALL_ANIM = 0x02;
+const U32 WAIT_FLAG_KEY_RELEASE = 0x04;
class LLGestureStepWait : public LLGestureStep
{
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index c947184dc8..5f4ed2fffa 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -3,7 +3,6 @@
project(llcommon)
include(00-Common)
-include(ICU4C)
include(LLCommon)
include(bugsplat)
include(Linking)
@@ -283,7 +282,6 @@ target_link_libraries(
ll::uriparser
ll::oslibraries
ll::tracy
- ll::icu4c
)
target_include_directories(llcommon INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index a743ae1589..6512bbc392 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -30,7 +30,6 @@
#include "llerror.h"
#include "llfasttimer.h"
#include "llsd.h"
-#include
#include
#if LL_WINDOWS
@@ -758,6 +757,43 @@ std::string utf8str_showBytesUTF8(const std::string& utf8str)
return result;
}
+// Search for any emoji symbol, return true if found
+bool wstring_has_emoji(const LLWString& wstr)
+{
+ for (const llwchar& wch : wstr)
+ {
+ if (LLStringOps::isEmoji(wch))
+ return true;
+ }
+
+ return false;
+}
+
+// Cut emoji symbols if exist
+bool wstring_remove_emojis(LLWString& wstr)
+{
+ bool found = false;
+ for (size_t i = 0; i < wstr.size(); ++i)
+ {
+ if (LLStringOps::isEmoji(wstr[i]))
+ {
+ wstr.erase(i--, 1);
+ found = true;
+ }
+ }
+ return found;
+}
+
+// Cut emoji symbols if exist
+bool utf8str_remove_emojis(std::string& utf8str)
+{
+ LLWString wstr = utf8str_to_wstring(utf8str);
+ if (!wstring_remove_emojis(wstr))
+ return false;
+ utf8str = wstring_to_utf8str(wstr);
+ return true;
+}
+
#if LL_WINDOWS
unsigned int ll_wstring_default_code_page()
{
@@ -971,40 +1007,18 @@ std::string LLStringOps::sAM;
std::string LLStringOps::sPM;
// static
-bool LLStringOps::isEmoji(llwchar wch)
+bool LLStringOps::isEmoji(llwchar a)
{
- int ublock = ublock_getCode(wch);
- switch (ublock)
- {
- case UBLOCK_GENERAL_PUNCTUATION:
- case UBLOCK_LETTERLIKE_SYMBOLS:
- case UBLOCK_ARROWS:
- case UBLOCK_MISCELLANEOUS_TECHNICAL:
- case UBLOCK_ENCLOSED_ALPHANUMERICS:
- case UBLOCK_GEOMETRIC_SHAPES:
- case UBLOCK_MISCELLANEOUS_SYMBOLS:
- case UBLOCK_DINGBATS:
- case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
- case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS:
- case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS:
- case UBLOCK_EMOTICONS:
- case UBLOCK_TRANSPORT_AND_MAP_SYMBOLS:
-#if U_ICU_VERSION_MAJOR_NUM > 56
- // Boost uses ICU so we can't update it independently
- case UBLOCK_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS:
-#endif // U_ICU_VERSION_MAJOR_NUM > 56
- return true;
- default:
-#if U_ICU_VERSION_MAJOR_NUM > 56
- return false;
+#if 0 // Do not consider special characters that might have a corresponding
+ // glyph in the monochorme fallback fonts as a "genuine" emoji. HB
+ return a == 0xa9 || a == 0xae || (a >= 0x2000 && a < 0x3300) ||
+ (a >= 0x1f000 && a < 0x20000);
#else
- // See https://en.wikipedia.org/wiki/Supplemental_Symbols_and_Pictographs
- return wch >= 0x1F900 && wch <= 0x1F9FF;
-#endif // U_ICU_VERSION_MAJOR_NUM > 56
- }
+ // These are indeed "genuine" emojis, we *do want* rendered as such. HB
+ return a >= 0x1f000 && a < 0x20000;
+#endif
}
-
S32 LLStringOps::collate(const llwchar* a, const llwchar* b)
{
#if LL_WINDOWS
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 3829978ddf..6503da2e77 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -189,7 +189,8 @@ public:
static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
- static bool isEmoji(llwchar wch);
+ // Returns true when 'a' corresponds to a "genuine" emoji. HB
+ static bool isEmoji(llwchar a);
static S32 collate(const char* a, const char* b) { return strcoll(a, b); }
static S32 collate(const llwchar* a, const llwchar* b);
@@ -747,6 +748,12 @@ LL_COMMON_API llwchar utf8str_to_wchar(const std::string& utf8str, size_t offset
LL_COMMON_API std::string utf8str_showBytesUTF8(const std::string& utf8str);
+LL_COMMON_API bool wstring_has_emoji(const LLWString& wstr);
+
+LL_COMMON_API bool wstring_remove_emojis(LLWString& wstr);
+
+LL_COMMON_API bool utf8str_remove_emojis(std::string& utf8str);
+
#if LL_WINDOWS
/* @name Windows string helpers
*/
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 47868b3fca..b7ffddc023 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -1350,6 +1350,10 @@ BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile)
} while(gzeof(src) == 0);
fclose(dst);
dst = NULL;
+#if LL_WINDOWS
+ // Rename in windows needs the dstfile to not exist.
+ LLFile::remove(dstfile, ENOENT);
+#endif
if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */
retval = TRUE;
err:
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index 864315d0ff..da5b531857 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -585,8 +585,7 @@ static void bilinear_scale(const U8 *src, U32 srcW, U32 srcH, U32 srcCh, U32 src
//---------------------------------------------------------------------------
//static
-std::string LLImage::sLastErrorMessage;
-LLMutex* LLImage::sMutex = NULL;
+thread_local std::string LLImage::sLastThreadErrorMessage;
bool LLImage::sUseNewByteRange = false;
S32 LLImage::sMinimalReverseByteRangePercent = 75;
@@ -595,28 +594,24 @@ void LLImage::initClass(bool use_new_byte_range, S32 minimal_reverse_byte_range_
{
sUseNewByteRange = use_new_byte_range;
sMinimalReverseByteRangePercent = minimal_reverse_byte_range_percent;
- sMutex = new LLMutex();
}
//static
void LLImage::cleanupClass()
{
- delete sMutex;
- sMutex = NULL;
}
//static
-const std::string& LLImage::getLastError()
+const std::string& LLImage::getLastThreadError()
{
static const std::string noerr("No Error");
- return sLastErrorMessage.empty() ? noerr : sLastErrorMessage;
+ return sLastThreadErrorMessage.empty() ? noerr : sLastThreadErrorMessage;
}
//static
void LLImage::setLastError(const std::string& message)
{
- LLMutexLock m(sMutex);
- sLastErrorMessage = message;
+ sLastThreadErrorMessage = message;
}
//---------------------------------------------------------------------------
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index a5f05d4380..9b16711b85 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -96,15 +96,14 @@ public:
static void initClass(bool use_new_byte_range = false, S32 minimal_reverse_byte_range_percent = 75);
static void cleanupClass();
- static const std::string& getLastError();
+ static const std::string& getLastThreadError();
static void setLastError(const std::string& message);
static bool useNewByteRange() { return sUseNewByteRange; }
static S32 getReverseByteRangePercent() { return sMinimalReverseByteRangePercent; }
protected:
- static LLMutex* sMutex;
- static std::string sLastErrorMessage;
+ static thread_local std::string sLastThreadErrorMessage;
static bool sUseNewByteRange;
static S32 sMinimalReverseByteRangePercent;
};
diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp
index 29a86f77f6..4d081ce169 100644
--- a/indra/llimage/llimagepng.cpp
+++ b/indra/llimage/llimagepng.cpp
@@ -27,6 +27,7 @@
#include "linden_common.h"
#include "stdtypes.h"
#include "llerror.h"
+#include "llexception.h"
#include "llimage.h"
#include "llpngwrapper.h"
@@ -51,30 +52,45 @@ bool LLImagePNG::updateData()
{
resetLastError();
- // Check to make sure that this instance has been initialized with data
- if (!getData() || (0 == getDataSize()))
+ try
{
- setLastError("Uninitialized instance of LLImagePNG");
+ // Check to make sure that this instance has been initialized with data
+ if (!getData() || (0 == getDataSize()))
+ {
+ setLastError("Uninitialized instance of LLImagePNG");
+ return false;
+ }
+
+ // Decode the PNG data and extract sizing information
+ LLPngWrapper pngWrapper;
+ if (!pngWrapper.isValidPng(getData()))
+ {
+ setLastError("LLImagePNG data does not have a valid PNG header!");
+ return false;
+ }
+
+ LLPngWrapper::ImageInfo infop;
+ if (!pngWrapper.readPng(getData(), getDataSize(), NULL, &infop))
+ {
+ setLastError(pngWrapper.getErrorMessage());
+ return false;
+ }
+
+ setSize(infop.mWidth, infop.mHeight, infop.mComponents);
+ }
+ catch (const LLContinueError& msg)
+ {
+ setLastError(msg.what());
+ LOG_UNHANDLED_EXCEPTION("");
return false;
}
-
- // Decode the PNG data and extract sizing information
- LLPngWrapper pngWrapper;
- if (!pngWrapper.isValidPng(getData()))
+ catch (...)
{
- setLastError("LLImagePNG data does not have a valid PNG header!");
+ setLastError("LLImagePNG");
+ LOG_UNHANDLED_EXCEPTION("");
return false;
}
- LLPngWrapper::ImageInfo infop;
- if (! pngWrapper.readPng(getData(), getDataSize(), NULL, &infop))
- {
- setLastError(pngWrapper.getErrorMessage());
- return false;
- }
-
- setSize(infop.mWidth, infop.mHeight, infop.mComponents);
-
return true;
}
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index 553e5cd7bf..587f25dc1b 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -58,6 +58,7 @@ private:
BOOL mDecodedRaw;
BOOL mDecodedAux;
LLPointer mResponder;
+ std::string mErrorString;
};
@@ -156,6 +157,7 @@ bool ImageRequest::processRequest()
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
const F32 decode_time_slice = 0.f; //disable time slicing
bool done = true;
+ mErrorString.clear();
if (!mDecodedRaw && mFormattedImage.notNull())
{
// Decode primary channels
@@ -164,10 +166,13 @@ bool ImageRequest::processRequest()
// parse formatted header
if (!mFormattedImage->updateData())
{
+ // Pick up errors from updateData
+ mErrorString = LLImage::getLastThreadError();
return true; // done (failed)
}
if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()))
{
+ mErrorString = "Invalid image size";
return true; // done (failed)
}
if (mDiscardLevel >= 0)
@@ -181,6 +186,9 @@ bool ImageRequest::processRequest()
done = mFormattedImage->decode(mDecodedImageRaw, decode_time_slice);
// some decoders are removing data when task is complete and there were errors
mDecodedRaw = done && mDecodedImageRaw->getData();
+
+ // Pick up errors from decoding
+ mErrorString = LLImage::getLastThreadError();
}
if (done && mNeedsAux && !mDecodedAux && mFormattedImage.notNull())
{
@@ -193,6 +201,9 @@ bool ImageRequest::processRequest()
}
done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4);
mDecodedAux = done && mDecodedImageAux->getData();
+
+ // Pick up errors from decoding
+ mErrorString = LLImage::getLastThreadError();
}
return done;
@@ -204,7 +215,7 @@ void ImageRequest::finishRequest(bool completed)
if (mResponder.notNull())
{
bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux);
- mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux, mRequestId);
+ mResponder->completed(success, mErrorString, mDecodedImageRaw, mDecodedImageAux, mRequestId);
}
// Will automatically be deleted
}
diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h
index 92d70b451d..8c43a7c32c 100644
--- a/indra/llimage/llimageworker.h
+++ b/indra/llimage/llimageworker.h
@@ -39,7 +39,7 @@ public:
protected:
virtual ~Responder();
public:
- virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32 request_id) = 0;
+ virtual void completed(bool success, const std::string& error_message, LLImageRaw* raw, LLImageRaw* aux, U32 request_id) = 0;
};
public:
diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp
index 6167ba5b43..24b6d34fe2 100644
--- a/indra/llimage/llpngwrapper.cpp
+++ b/indra/llimage/llpngwrapper.cpp
@@ -216,6 +216,13 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf
releaseResources();
return (FALSE);
}
+ catch (...)
+ {
+ mErrorMessage = "LLPngWrapper";
+ releaseResources();
+ LOG_UNHANDLED_EXCEPTION("");
+ return (FALSE);
+ }
// Clean up and return
releaseResources();
diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index 1e332e0154..e14b2f25ed 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -725,7 +725,7 @@ LLSD LLSettingsSky::defaults(const LLSettingsBase::TrackPosition& position)
dfltsetting[SETTING_CLOUD_POS_DENSITY1] = LLColor4(1.0000, 0.5260, 1.0000, 0.0).getValue();
dfltsetting[SETTING_CLOUD_POS_DENSITY2] = LLColor4(1.0000, 0.5260, 1.0000, 0.0).getValue();
dfltsetting[SETTING_CLOUD_SCALE] = LLSD::Real(0.4199);
- dfltsetting[SETTING_CLOUD_SCROLL_RATE] = llsd::array(0.0f, 0.0f);
+ dfltsetting[SETTING_CLOUD_SCROLL_RATE] = llsd::array(0.2, 0.01);
dfltsetting[SETTING_CLOUD_SHADOW] = LLSD::Real(0.2699);
dfltsetting[SETTING_CLOUD_VARIANCE] = LLSD::Real(0.0);
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index 088d3d1339..1657e9324e 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -118,7 +118,7 @@ const F32 FLEXIBLE_OBJECT_DEFAULT_LENGTH = 1.0f;
const BOOL FLEXIBLE_OBJECT_DEFAULT_USING_COLLISION_SPHERE = FALSE;
const BOOL FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE = FALSE;
-const char *SCULPT_DEFAULT_TEXTURE = "be293869-d0d9-0a69-5989-ad27f1946fd4"; // old inverted texture: "7595d345-a24c-e7ef-f0bd-78793792133e";
+const LLUUID SCULPT_DEFAULT_TEXTURE("be293869-d0d9-0a69-5989-ad27f1946fd4"); // old inverted texture: "7595d345-a24c-e7ef-f0bd-78793792133e";
// Texture rotations are sent over the wire as a S16. This is used to scale the actual float
// value to a S16. Don't use 7FFF as it introduces some odd rounding with 180 since it
@@ -2086,7 +2086,7 @@ bool LLFlexibleObjectData::fromLLSD(LLSD& sd)
LLSculptParams::LLSculptParams()
{
mType = PARAMS_SCULPT;
- mSculptTexture.set(SCULPT_DEFAULT_TEXTURE);
+ mSculptTexture = SCULPT_DEFAULT_TEXTURE;
mSculptType = LL_SCULPT_TYPE_SPHERE;
}
@@ -2172,7 +2172,7 @@ void LLSculptParams::setSculptTexture(const LLUUID& texture_id, U8 sculpt_type)
U8 flags = sculpt_type & LL_SCULPT_FLAG_MASK;
if (sculpt_type != (type | flags) || type > LL_SCULPT_TYPE_MAX)
{
- mSculptTexture.set(SCULPT_DEFAULT_TEXTURE);
+ mSculptTexture = SCULPT_DEFAULT_TEXTURE;
mSculptType = LL_SCULPT_TYPE_SPHERE;
}
else
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index 6078abf67e..82881dce4e 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -89,7 +89,7 @@ extern const F32 OBJECT_REV_MIN;
extern const F32 OBJECT_REV_MAX;
extern const F32 OBJECT_REV_INC;
-extern const char *SCULPT_DEFAULT_TEXTURE;
+extern const LLUUID SCULPT_DEFAULT_TEXTURE;
//============================================================================
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index 1e5e441689..92b373c835 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -354,11 +354,10 @@ void LLFontFreetype::clearFontStreams()
}
#endif
-void LLFontFreetype::addFallbackFont(const LLPointer& fallback_font, const char_functor_t& functor)
+void LLFontFreetype::addFallbackFont(const LLPointer& fallback_font,
+ const char_functor_t& functor)
{
- // Insert functor fallbacks before generic fallbacks
- mFallbackFonts.insert((functor) ? std::find_if(mFallbackFonts.begin(), mFallbackFonts.end(), [](const fallback_font_t& fe) { return !fe.second; }) : mFallbackFonts.end(),
- std::make_pair(fallback_font, functor));
+ mFallbackFonts.emplace_back(fallback_font, functor);
}
F32 LLFontFreetype::getLineHeight() const
@@ -450,50 +449,95 @@ BOOL LLFontFreetype::hasGlyph(llwchar wch) const
LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type) const
{
- if (mFTFace == NULL)
- return FALSE;
+ if (!mFTFace)
+ {
+ return NULL;
+ }
llassert(!mIsFallback);
llassert(glyph_type < EFontGlyphType::Count);
//LL_DEBUGS() << "Adding new glyph for " << wch << " to font" << LL_ENDL;
- FT_UInt glyph_index;
-
- // Fallback fonts with a functor have precedence over everything else
- fallback_font_vector_t::const_iterator it_fallback = mFallbackFonts.cbegin();
- /* This leads to a bug SL-19831 "Check marks in the menu are less visible."
- ** Also, LLFontRegistry::createFont() says: "Fallback fonts don't render"
- for (; it_fallback != mFallbackFonts.cend() && it_fallback->second; ++it_fallback)
- {
- if (it_fallback->second(wch))
- {
- glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch);
- if (glyph_index)
- {
- return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type);
- }
- }
- }
- */
-
// Initialize char to glyph map
- glyph_index = FT_Get_Char_Index(mFTFace, wch);
+ FT_UInt glyph_index = FT_Get_Char_Index(mFTFace, wch);
if (glyph_index == 0)
{
- //LL_INFOS() << "Trying to add glyph from fallback font!" << LL_ENDL;
- for (; it_fallback != mFallbackFonts.cend(); ++it_fallback)
+ // No corresponding glyph in this font: look for a glyph in fallback
+ // fonts.
+ size_t count = mFallbackFonts.size();
+ if (LLStringOps::isEmoji(wch))
{
- glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch);
+ // This is a "genuine" emoji (in the range 0x1f000-0x20000): print
+ // it using the emoji font(s) if possible. HB
+ for (size_t i = 0; i < count; ++i)
+ {
+ const fallback_font_t& pair = mFallbackFonts[i];
+ if (!pair.second || !pair.second(wch))
+ {
+ // If this font does not have a functor, or the character
+ // does not pass the functor, reject it. Note: we keep the
+ // functor test (despite the fact we already tested for
+ // LLStringOps::isEmoji(wch) above), in case we would use
+ // different, more restrictive or partionned functors in
+ // the future with several different emoji fonts. HB
+ continue;
+ }
+ glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch);
+ if (glyph_index)
+ {
+ return addGlyphFromFont(pair.first, wch, glyph_index,
+ glyph_type);
+ }
+ }
+ }
+ // Then try and find a monochrome fallback font that could print this
+ // glyph: such fonts do *not* have a functor. We give priority to
+ // monochrome fonts for non-genuine emojis so that UI elements which
+ // used to render with them before the emojis font introduction (e.g.
+ // check marks in menus, or LSL dialogs text and buttons) do render the
+ // same way as they always did. HB
+ std::vector emoji_fonts_idx;
+ for (size_t i = 0; i < count; ++i)
+ {
+ const fallback_font_t& pair = mFallbackFonts[i];
+ if (pair.second)
+ {
+ // If this font got a functor, remember the index for later and
+ // try the next fallback font. HB
+ emoji_fonts_idx.push_back(i);
+ continue;
+ }
+ glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch);
if (glyph_index)
{
- return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type);
+ return addGlyphFromFont(pair.first, wch, glyph_index,
+ glyph_type);
+ }
+ }
+ // Everything failed so far: this character is not a genuine emoji,
+ // neither a special character known from our monochrome fallback
+ // fonts: make a last try, using the emoji font(s), but ignoring the
+ // functor to render using whatever (colorful) glyph that might be
+ // available in such fonts for this character. HB
+ for (size_t j = 0, count2 = emoji_fonts_idx.size(); j < count2; ++j)
+ {
+ const fallback_font_t& pair = mFallbackFonts[emoji_fonts_idx[j]];
+ glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch);
+ if (glyph_index)
+ {
+ return addGlyphFromFont(pair.first, wch, glyph_index,
+ glyph_type);
}
}
}
- std::pair range_it = mCharGlyphInfoMap.equal_range(wch);
+ auto range_it = mCharGlyphInfoMap.equal_range(wch);
char_glyph_info_map_t::iterator iter =
- std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; });
+ std::find_if(range_it.first, range_it.second,
+ [&glyph_type](const char_glyph_info_map_t::value_type& entry)
+ {
+ return entry.second->mGlyphType == glyph_type;
+ });
if (iter == range_it.second)
{
return addGlyphFromFont(this, wch, glyph_index, glyph_type);
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 8d0fed7829..3714bb1883 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -276,6 +276,9 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
LLColor4U colors[GLYPH_BATCH_SIZE * 4];
LLColor4U text_color(color);
+ // Preserve the transparency to render fading emojis in fading text (e.g.
+ // for the chat console)... HB
+ LLColor4U emoji_color(255, 255, 255, text_color.mV[VW]);
std::pair bitmap_entry = std::make_pair(EFontGlyphType::Grayscale, -1);
S32 glyph_count = 0;
@@ -344,7 +347,11 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
glyph_count = 0;
}
- drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, (bitmap_entry.first == EFontGlyphType::Grayscale) ? text_color : LLColor4U::white, style_to_add, shadow, drop_shadow_strength);
+ const LLColor4U& col =
+ bitmap_entry.first == EFontGlyphType::Grayscale ? text_color
+ : emoji_color;
+ drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect,
+ col, style_to_add, shadow, drop_shadow_strength);
chars_drawn++;
cur_x += fgi->mXAdvance;
@@ -1030,7 +1037,21 @@ LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name)
}
//static
-LLFontGL* LLFontGL::getFontEmoji()
+LLFontGL* LLFontGL::getFontEmojiSmall()
+{
+ static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Small", 0));
+ return fontp;;
+}
+
+//static
+LLFontGL* LLFontGL::getFontEmojiMedium()
+{
+ static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Medium", 0));
+ return fontp;;
+}
+
+//static
+LLFontGL* LLFontGL::getFontEmojiLarge()
{
static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Large", 0));
return fontp;;
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index 2e1d04a2b9..65f0a8cbfd 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -194,7 +194,9 @@ public:
static void setFontDisplay(BOOL flag) { sDisplayFont = flag; }
- static LLFontGL* getFontEmoji();
+ static LLFontGL* getFontEmojiSmall();
+ static LLFontGL* getFontEmojiMedium();
+ static LLFontGL* getFontEmojiLarge();
static LLFontGL* getFontEmojiHuge();
static LLFontGL* getFontMonospace();
static LLFontGL* getFontSansSerifSmall();
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp
index 89969acb1b..3feb989ed5 100644
--- a/indra/llui/llaccordionctrl.cpp
+++ b/indra/llui/llaccordionctrl.cpp
@@ -936,3 +936,20 @@ S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 availabl
expanded_tab_height /= num_expanded;
return expanded_tab_height;
}
+
+void LLAccordionCtrl::collapseAllTabs()
+{
+ if (mAccordionTabs.size() > 0)
+ {
+ for (size_t i = 0; i < mAccordionTabs.size(); ++i)
+ {
+ LLAccordionCtrlTab *tab = mAccordionTabs[i];
+
+ if (tab->getDisplayChildren())
+ {
+ tab->setDisplayChildren(false);
+ }
+ }
+ arrange();
+ }
+}
diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h
index 182c8cfe04..2741db24e8 100644
--- a/indra/llui/llaccordionctrl.h
+++ b/indra/llui/llaccordionctrl.h
@@ -122,6 +122,8 @@ public:
void setComparator(const LLTabComparator* comp) { mTabComparator = comp; }
void sort();
+ void collapseAllTabs();
+
/**
* Sets filter substring as a search_term for help text when there are no any visible tabs.
*/
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 8803d751d0..16b58dcc5b 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -58,10 +58,11 @@ static LLDefaultChildRegistry::Register r("button");
template class LLButton* LLView::getChild(
const std::string& name, BOOL recurse) const;
-// globals loaded from settings.xml
-S32 LLBUTTON_H_PAD = 0;
-S32 BTN_HEIGHT_SMALL= 0;
-S32 BTN_HEIGHT = 0;
+// globals
+S32 LLBUTTON_H_PAD = 4;
+S32 BTN_HEIGHT_SMALL= 23;
+S32 BTN_HEIGHT = 23;
+S32 BTN_DROP_SHADOW = 2;
LLButton::Params::Params()
: label_selected("label_selected"), // requires is_toggle true
@@ -92,8 +93,8 @@ LLButton::Params::Params()
image_overlay_disabled_color("image_overlay_disabled_color", LLColor4::white % 0.3f),
image_overlay_selected_color("image_overlay_selected_color", LLColor4::white),
flash_color("flash_color"),
- pad_right("pad_right", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")),
- pad_left("pad_left", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")),
+ pad_right("pad_right", LLBUTTON_H_PAD),
+ pad_left("pad_left", LLBUTTON_H_PAD),
pad_bottom("pad_bottom"),
click_callback("click_callback"),
mouse_down_callback("mouse_down_callback"),
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 7054074fd8..8ac42596e4 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -43,10 +43,10 @@
//
// PLEASE please use these "constants" when building your own buttons.
-// They are loaded from settings.xml at run time.
extern S32 LLBUTTON_H_PAD;
extern S32 BTN_HEIGHT_SMALL;
extern S32 BTN_HEIGHT;
+extern S32 BTN_DROP_SHADOW;
//
// Helpful functions
@@ -251,7 +251,7 @@ public:
void setFont(const LLFontGL *font)
{ mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); }
const LLFontGL* getFont() const { return mGLFont; }
-
+ const std::string& getText() const { return getCurrentLabel().getString(); }
S32 getLastDrawCharsCount() const { return mLastDrawCharsCount; }
bool labelIsTruncated() const;
diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h
index 43e887fab6..f2b61db308 100644
--- a/indra/llui/llcheckboxctrl.h
+++ b/indra/llui/llcheckboxctrl.h
@@ -117,7 +117,7 @@ public:
std::string getLabel() const;
void setFont( const LLFontGL* font ) { mFont = font; }
- const LLFontGL* getFont() { return mFont; }
+ const LLFontGL* getFont() const { return mFont; }
virtual void setControlName(const std::string& control_name, LLView* context);
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 1573ccb0d7..71dd93d07d 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -188,6 +188,8 @@ LLComboBox::~LLComboBox()
// explicitly disconect this signal, since base class destructor might fire top lost
mTopLostSignalConnection.disconnect();
mImageLoadedConnection.disconnect();
+
+ LLUI::getInstance()->removePopup(this);
}
@@ -482,8 +484,6 @@ void LLComboBox::onFocusLost()
void LLComboBox::setButtonVisible(BOOL visible)
{
- static LLUICachedControl drop_shadow_button ("DropShadowButton", 0);
-
mButton->setVisible(visible);
if (mTextEntry)
{
@@ -491,7 +491,7 @@ void LLComboBox::setButtonVisible(BOOL visible)
if (visible)
{
S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
- text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button;
+ text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW;
}
//mTextEntry->setRect(text_entry_rect);
mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
@@ -530,19 +530,18 @@ void LLComboBox::setEnabledByValue(const LLSD& value, BOOL enabled)
void LLComboBox::createLineEditor(const LLComboBox::Params& p)
{
- static LLUICachedControl drop_shadow_button ("DropShadowButton", 0);
LLRect rect = getLocalRect();
if (mAllowTextEntry)
{
S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
- S32 shadow_size = drop_shadow_button;
+ S32 shadow_size = BTN_DROP_SHADOW;
mButton->setRect(LLRect( getRect().getWidth() - llmax(8,arrow_width) - 2 * shadow_size,
rect.mTop, rect.mRight, rect.mBottom));
mButton->setTabStop(FALSE);
mButton->setHAlign(LLFontGL::HCENTER);
LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
- text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button;
+ text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW;
// clear label on button
std::string cur_label = mButton->getLabelSelected();
LLLineEditor::Params params = p.combo_editor;
@@ -1081,13 +1080,11 @@ void LLComboBox::onSetHighlight() const
void LLComboBox::imageLoaded()
{
- static LLUICachedControl drop_shadow_button("DropShadowButton", 0);
-
if (mAllowTextEntry)
{
LLRect rect = getLocalRect();
S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
- S32 shadow_size = drop_shadow_button;
+ S32 shadow_size = BTN_DROP_SHADOW;
mButton->setRect(LLRect(getRect().getWidth() - llmax(8, arrow_width) - 2 * shadow_size,
rect.mTop, rect.mRight, rect.mBottom));
if (mButton->getVisible())
@@ -1096,7 +1093,7 @@ void LLComboBox::imageLoaded()
if (mTextEntry)
{
LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
- text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * drop_shadow_button;
+ text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * BTN_DROP_SHADOW;
mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
}
}
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 96d9e31f4c..75254f80d8 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -2039,10 +2039,9 @@ void LLFloater::drawShadow(LLPanel* panel)
S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH;
S32 bottom = LLPANEL_BORDER_WIDTH;
- static LLUICachedControl shadow_offset_S32 ("DropShadowFloater", 0);
static LLUIColor shadow_color_cached = LLUIColorTable::instance().getColor("ColorDropShadow");
LLColor4 shadow_color = shadow_color_cached;
- F32 shadow_offset = (F32)shadow_offset_S32;
+ F32 shadow_offset = (F32)DROP_SHADOW_FLOATER;
if (!panel->isBackgroundOpaque())
{
@@ -2477,7 +2476,8 @@ void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent)
void LLFloaterView::restoreAll()
{
// make sure all subwindows aren't minimized
- for (auto child : *getChildList())
+ child_list_t child_list = *(getChildList());
+ for (LLView* child : child_list)
{
LLFloater* floaterp = dynamic_cast(child);
if (floaterp)
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 7fcbd5c5ec..dcc9af4c6e 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -61,6 +61,10 @@ const BOOL CLOSE_NO = FALSE;
const BOOL ADJUST_VERTICAL_YES = TRUE;
const BOOL ADJUST_VERTICAL_NO = FALSE;
+const F32 CONTEXT_CONE_IN_ALPHA = 0.f;
+const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
+const F32 CONTEXT_CONE_FADE_TIME = .08f;
+
namespace LLFloaterEnums
{
enum EOpenPositioning
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index fa6128cc25..33921cf4f0 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -220,7 +220,7 @@ LLFolderView::LLFolderView(const Params& p)
params.font(getLabelFontForStyle(LLFontGL::NORMAL));
params.max_length.bytes(DB_INV_ITEM_NAME_STR_LEN);
params.commit_callback.function(boost::bind(&LLFolderView::commitRename, this, _2));
- params.prevalidate_callback(&LLTextValidate::validateASCIIPrintableNoPipe);
+ params.prevalidator(&LLTextValidate::validateASCIIPrintableNoPipe);
params.commit_on_focus_lost(true);
params.visible(false);
mRenamer = LLUICtrlFactory::create (params);
@@ -256,7 +256,13 @@ LLFolderView::LLFolderView(const Params& p)
// Destroys the object
LLFolderView::~LLFolderView( void )
{
- closeRenamer();
+ mRenamerTopLostSignalConnection.disconnect();
+ if (mRenamer)
+ {
+ // instead of using closeRenamer remove it directly,
+ // since it might already be hidden
+ LLUI::getInstance()->removePopup(mRenamer);
+ }
// The release focus call can potentially call the
// scrollcontainer, which can potentially be called with a partly
@@ -335,9 +341,9 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height )
void LLFolderView::filter( LLFolderViewFilter& filter )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
- static LLCachedControl time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
- static LLCachedControl time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1);
- filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100));
+ const S32 TIME_VISIBLE = 10; // in milliseconds
+ const S32 TIME_INVISIBLE = 1;
+ filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? TIME_VISIBLE : TIME_INVISIBLE), 1, 100));
// Note: we filter the model, not the view
getViewModelItem()->filter(filter);
@@ -765,7 +771,7 @@ void LLFolderView::removeSelectedItems()
}
else
{
- LL_INFOS() << "Cannot delete " << item->getName() << LL_ENDL;
+ LL_DEBUGS() << "Cannot delete " << item->getName() << LL_ENDL;
return;
}
}
@@ -1072,7 +1078,10 @@ void LLFolderView::startRenamingSelectedItem( void )
mRenamer->setVisible( TRUE );
// set focus will fail unless item is visible
mRenamer->setFocus( TRUE );
- mRenamer->setTopLostCallback(boost::bind(&LLFolderView::onRenamerLost, this));
+ if (!mRenamerTopLostSignalConnection.connected())
+ {
+ mRenamerTopLostSignalConnection = mRenamer->setTopLostCallback(boost::bind(&LLFolderView::onRenamerLost, this));
+ }
LLUI::getInstance()->addPopup(mRenamer);
}
}
@@ -1598,7 +1607,11 @@ BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
void LLFolderView::deleteAllChildren()
{
- closeRenamer();
+ mRenamerTopLostSignalConnection.disconnect();
+ if (mRenamer)
+ {
+ LLUI::getInstance()->removePopup(mRenamer);
+ }
if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die();
mPopupMenuHandle.markDead();
mScrollContainer = NULL;
diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h
index 1ad7e9f58c..ca78bd3072 100644
--- a/indra/llui/llfolderview.h
+++ b/indra/llui/llfolderview.h
@@ -345,6 +345,8 @@ protected:
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar;
+ boost::signals2::connection mRenamerTopLostSignalConnection;
+
bool mForceArrange;
public:
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index 40bb6832d4..a9e1171444 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -605,15 +605,13 @@ BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask )
BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
{
- static LLCachedControl drag_and_drop_threshold(*LLUI::getInstance()->mSettingGroups["config"],"DragAndDropDistanceThreshold", 3);
-
mIsMouseOverTitle = (y > (getRect().getHeight() - mItemHeight));
if( hasMouseCapture() && isMovable() )
{
LLFolderView* root = getRoot();
- if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > drag_and_drop_threshold() * drag_and_drop_threshold()
+ if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD
&& root->getAllowDrag()
&& root->getCurSelectedItem()
&& root->startDrag())
diff --git a/indra/llui/llfolderviewmodel.cpp b/indra/llui/llfolderviewmodel.cpp
index c7ed65bdfa..d9e6567cd6 100644
--- a/indra/llui/llfolderviewmodel.cpp
+++ b/indra/llui/llfolderviewmodel.cpp
@@ -48,8 +48,8 @@ std::string LLFolderViewModelCommon::getStatusText(bool is_empty_folder)
void LLFolderViewModelCommon::filter()
{
- static LLCachedControl max_time(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
- getFilter().resetTime(llclamp(max_time(), 1, 100));
+ const S32 MAX_FILTER_TIME = 10;
+ getFilter().resetTime(MAX_FILTER_TIME);
mFolderView->getViewModelItem()->filter(getFilter());
}
diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h
index 53ae2bd97f..f02c1e3883 100644
--- a/indra/llui/llfolderviewmodel.h
+++ b/indra/llui/llfolderviewmodel.h
@@ -170,7 +170,7 @@ public:
virtual BOOL isItemMovable( void ) const = 0; // Can be moved to another folder
virtual void move( LLFolderViewModelItem* parent_listener ) = 0;
- virtual BOOL isItemRemovable( void ) const = 0; // Can be destroyed
+ virtual BOOL isItemRemovable( bool check_worn = true ) const = 0; // Can be destroyed
virtual BOOL removeItem() = 0;
virtual void removeBatch(std::vector& batch) = 0;
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index eefba0d186..6dc68b4de2 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -83,8 +83,8 @@ template class LLLineEditor* LLView::getChild(
LLLineEditor::Params::Params()
: max_length(""),
keystroke_callback("keystroke_callback"),
- prevalidate_callback("prevalidate_callback"),
- prevalidate_input_callback("prevalidate_input_callback"),
+ prevalidator("prevalidator"),
+ input_prevalidator("input_prevalidator"),
background_image("background_image"),
background_image_disabled("background_image_disabled"),
background_image_focused("background_image_focused"),
@@ -96,6 +96,7 @@ LLLineEditor::Params::Params()
commit_on_focus_lost("commit_on_focus_lost", true),
ignore_tab("ignore_tab", true),
is_password("is_password", false),
+ allow_emoji("allow_emoji", true),
cursor_color("cursor_color"),
use_bg_color("use_bg_color", false),
bg_color("bg_color"),
@@ -111,6 +112,8 @@ LLLineEditor::Params::Params()
default_text("default_text")
{
changeDefault(mouse_opaque, true);
+ addSynonym(prevalidator, "prevalidate_callback");
+ addSynonym(input_prevalidator, "prevalidate_input_callback");
addSynonym(select_on_focus, "select_all_on_focus_received");
addSynonym(border, "border");
addSynonym(label, "watermark_text");
@@ -142,6 +145,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mIgnoreArrowKeys( FALSE ),
mIgnoreTab( p.ignore_tab ),
mDrawAsterixes( p.is_password ),
+ mAllowEmoji( p.allow_emoji ),
mSpellCheck( p.spellcheck ),
mSpellCheckStart(-1),
mSpellCheckEnd(-1),
@@ -157,6 +161,8 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mUseBgColor(p.use_bg_color),
mHaveHistory(FALSE),
mReplaceNewlinesWithSpaces( TRUE ),
+ mPrevalidator(p.prevalidator()),
+ mInputPrevalidator(p.input_prevalidator()),
mLabel(p.label),
mCursorColor(p.cursor_color()),
mBgColor(p.bg_color()),
@@ -210,8 +216,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
}
mSpellCheckTimer.reset();
- setPrevalidateInput(p.prevalidate_input_callback());
- setPrevalidate(p.prevalidate_callback());
+ updateAllowingLanguageInput();
}
LLLineEditor::~LLLineEditor()
@@ -416,6 +421,11 @@ void LLLineEditor::setText(const LLStringExplicit &new_text, bool use_size_limit
all_selected = all_selected || (len == 0 && hasFocus() && mSelectAllonFocusReceived);
std::string truncated_utf8 = new_text;
+ if (!mAllowEmoji)
+ {
+ // Cut emoji symbols if exist
+ utf8str_remove_emojis(truncated_utf8);
+ }
if (use_size_limit && truncated_utf8.size() > (U32)mMaxLengthBytes)
{
truncated_utf8 = utf8str_truncate(new_text, mMaxLengthBytes);
@@ -589,13 +599,21 @@ void LLLineEditor::replaceWithSuggestion(U32 index)
{
if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) )
{
+ LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]);
+ if (!mAllowEmoji)
+ {
+ // Cut emoji symbols if exist
+ wstring_remove_emojis(suggestion);
+ }
+ if (suggestion.empty())
+ return;
+
deselect();
// Delete the misspelled word
mText.erase(it->first, it->second - it->first);
// Insert the suggestion in its place
- LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]);
mText.insert(it->first, suggestion);
setCursor(it->first + (S32)suggestion.length());
@@ -958,9 +976,11 @@ void LLLineEditor::removeChar()
}
}
-
void LLLineEditor::addChar(const llwchar uni_char)
{
+ if (!mAllowEmoji && LLStringOps::isEmoji(uni_char))
+ return;
+
llwchar new_c = uni_char;
if (hasSelection())
{
@@ -1193,11 +1213,12 @@ void LLLineEditor::cut()
deleteSelection();
// Validate new string and rollback the if needed.
- BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) );
- if( need_to_rollback )
+ BOOL need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString());
+ if (need_to_rollback)
{
rollback.doRollback( this );
LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
}
else
{
@@ -1260,6 +1281,11 @@ void LLLineEditor::pasteHelper(bool is_primary)
if (!paste.empty())
{
+ if (!mAllowEmoji)
+ {
+ wstring_remove_emojis(paste);
+ }
+
if (!prevalidateInput(paste))
return;
@@ -1321,11 +1347,12 @@ void LLLineEditor::pasteHelper(bool is_primary)
deselect();
// Validate new string and rollback the if needed.
- BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) );
- if( need_to_rollback )
+ BOOL need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString());
+ if (need_to_rollback)
{
rollback.doRollback( this );
LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
}
else
{
@@ -1568,19 +1595,27 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask )
deselect();
}
- BOOL need_to_rollback = FALSE;
+ bool prevalidator_failed = false;
// If read-only, don't allow changes
- need_to_rollback |= (mReadOnly && (mText.getString() == rollback.getText()));
+ bool need_to_rollback = mReadOnly && (mText.getString() == rollback.getText());
// Validate new string and rollback the keystroke if needed.
- need_to_rollback |= (mPrevalidateFunc && !mPrevalidateFunc(mText.getWString()));
+ if (!need_to_rollback && mPrevalidator)
+ {
+ prevalidator_failed = !mPrevalidator.validate(mText.getWString());
+ need_to_rollback |= prevalidator_failed;
+ }
if (need_to_rollback)
{
rollback.doRollback(this);
LLUI::getInstance()->reportBadKeystroke();
+ if (prevalidator_failed)
+ {
+ mPrevalidator.showLastErrorUsingTimeout();
+ }
}
// Notify owner if requested
@@ -1627,20 +1662,18 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char)
deselect();
- BOOL need_to_rollback = FALSE;
-
// Validate new string and rollback the keystroke if needed.
- need_to_rollback |= ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) );
-
- if( need_to_rollback )
+ bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString());
+ if (need_to_rollback)
{
rollback.doRollback( this );
LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
}
// Notify owner if requested
- if( !need_to_rollback && handled )
+ if (!need_to_rollback && handled)
{
// HACK! The only usage of this callback doesn't do anything with the character.
// We'll have to do something about this if something ever changes! - Doug
@@ -1683,11 +1716,12 @@ void LLLineEditor::doDelete()
}
// Validate new string and rollback the if needed.
- BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) );
- if( need_to_rollback )
+ bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString());
+ if (need_to_rollback)
{
- rollback.doRollback( this );
+ rollback.doRollback(this);
LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
}
else
{
@@ -1739,19 +1773,6 @@ void LLLineEditor::drawBackground()
}
}
-//virtual
-const std::string LLLineEditor::getToolTip() const
-{
- if (sDebugUnicode)
- {
- std::string text = getText();
- std::string tooltip = utf8str_showBytesUTF8(text);
- return tooltip;
- }
-
- return LLUICtrl::getToolTip();
-}
-
//virtual
void LLLineEditor::draw()
{
@@ -2232,7 +2253,7 @@ void LLLineEditor::setFocus( BOOL new_state )
// fine on 1.15.0.2, since all prevalidate func reject any
// non-ASCII characters. I'm not sure on future versions,
// however.
- getWindow()->allowLanguageTextInput(this, mPrevalidateFunc == NULL);
+ getWindow()->allowLanguageTextInput(this, !mPrevalidator);
}
}
@@ -2251,26 +2272,21 @@ void LLLineEditor::setRect(const LLRect& rect)
}
}
-void LLLineEditor::setPrevalidate(LLTextValidate::validate_func_t func)
+void LLLineEditor::setPrevalidate(LLTextValidate::Validator validator)
{
- mPrevalidateFunc = func;
+ mPrevalidator = validator;
updateAllowingLanguageInput();
}
-void LLLineEditor::setPrevalidateInput(LLTextValidate::validate_func_t func)
+void LLLineEditor::setPrevalidateInput(LLTextValidate::Validator validator)
{
- mPrevalidateInputFunc = func;
+ mInputPrevalidator = validator;
updateAllowingLanguageInput();
}
bool LLLineEditor::prevalidateInput(const LLWString& wstr)
{
- if (mPrevalidateInputFunc && !mPrevalidateInputFunc(wstr))
- {
- return false;
- }
-
- return true;
+ return mInputPrevalidator.validate(wstr);
}
// static
@@ -2412,7 +2428,7 @@ void LLLineEditor::updateAllowingLanguageInput()
// test app, no window available
return;
}
- if (hasFocus() && !mReadOnly && !mDrawAsterixes && mPrevalidateFunc == NULL)
+ if (hasFocus() && !mReadOnly && !mDrawAsterixes && !mPrevalidator)
{
window->allowLanguageTextInput(this, TRUE);
}
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 65afa54d04..340308535f 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -76,8 +76,8 @@ public:
Optional max_length;
Optional keystroke_callback;
- Optional prevalidate_callback;
- Optional prevalidate_input_callback;
+ Optional prevalidator;
+ Optional input_prevalidator;
Optional border;
@@ -93,6 +93,7 @@ public:
bg_image_always_focused,
show_label_focused,
is_password,
+ allow_emoji,
use_bg_color;
// colors
@@ -175,7 +176,6 @@ public:
void onSpellCheckSettingsChange();
// view overrides
- /*virtual*/ const std::string getToolTip() const override;
/*virtual*/ void draw() override;
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override;
/*virtual*/ void onFocusReceived() override;
@@ -203,7 +203,7 @@ public:
void setText(const LLStringExplicit &new_text);
- const std::string& getText() const { return mText.getString(); }
+ const std::string& getText() const override { return mText.getString(); }
LLWString getWText() const { return mText.getWString(); }
LLWString getConvertedText() const; // trimmed text with paragraphs converted to newlines
@@ -235,12 +235,13 @@ public:
const LLColor4& getReadOnlyFgColor() const { return mReadOnlyFgColor.get(); }
const LLColor4& getTentativeFgColor() const { return mTentativeFgColor.get(); }
- const LLFontGL* getFont() const { return mGLFont; }
+ const LLFontGL* getFont() const override { return mGLFont; }
void setFont(const LLFontGL* font);
void setIgnoreArrowKeys(BOOL b) { mIgnoreArrowKeys = b; }
void setIgnoreTab(BOOL b) { mIgnoreTab = b; }
void setPassDelete(BOOL b) { mPassDelete = b; }
+ void setAllowEmoji(BOOL b) { mAllowEmoji = b; }
void setDrawAsterixes(BOOL b);
// get the cursor position of the beginning/end of the prev/next word in the text
@@ -267,12 +268,12 @@ public:
void setTextPadding(S32 left, S32 right);
// Prevalidation controls which keystrokes can affect the editor
- void setPrevalidate( LLTextValidate::validate_func_t func );
+ void setPrevalidate(LLTextValidate::Validator validator);
// This method sets callback that prevents from:
// - deleting, selecting, typing, cutting, pasting characters that are not valid.
// Also callback that this method sets differs from setPrevalidate in a way that it validates just inputed
// symbols, before existing text is modified, but setPrevalidate validates line after it was modified.
- void setPrevalidateInput(LLTextValidate::validate_func_t func);
+ void setPrevalidateInput(LLTextValidate::Validator validator);
static BOOL postvalidateFloat(const std::string &str);
bool prevalidateInput(const LLWString& wstr);
@@ -374,8 +375,8 @@ protected:
std::list > mMisspellRanges;
std::vector mSuggestionList;
- LLTextValidate::validate_func_t mPrevalidateFunc;
- LLTextValidate::validate_func_t mPrevalidateInputFunc;
+ LLTextValidate::Validator mPrevalidator;
+ LLTextValidate::Validator mInputPrevalidator;
LLFrameTimer mKeystrokeTimer;
LLTimer mTripleClickTimer;
@@ -403,6 +404,7 @@ protected:
BOOL mShowImageFocused;
BOOL mShowLabelFocused;
+ bool mAllowEmoji;
bool mUseBgColor;
LLWString mPreeditWString;
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 79d0fbd1b4..8fcb558aae 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -65,8 +65,8 @@
LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL;
view_listener_t::listener_map_t view_listener_t::sListeners;
-S32 MENU_BAR_HEIGHT = 0;
-S32 MENU_BAR_WIDTH = 0;
+S32 MENU_BAR_HEIGHT = 18;
+S32 MENU_BAR_WIDTH = 410;
///============================================================================
/// Local function declarations, constants, enums, and typedefs
@@ -3234,10 +3234,9 @@ void LLMenuGL::draw( void )
}
if (mDropShadowed && !mTornOff)
{
- static LLUICachedControl drop_shadow_floater ("DropShadowFloater", 0);
static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow");
gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0,
- color_drop_shadow, drop_shadow_floater );
+ color_drop_shadow, DROP_SHADOW_FLOATER);
}
if( mBgVisible )
diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp
index b2be33b266..eac43900f6 100644
--- a/indra/llui/llmodaldialog.cpp
+++ b/indra/llui/llmodaldialog.cpp
@@ -67,6 +67,8 @@ LLModalDialog::~LLModalDialog()
{
LL_ERRS() << "Attempt to delete dialog while still in sModalStack!" << LL_ENDL;
}
+
+ LLUI::getInstance()->removePopup(this);
}
// virtual
@@ -284,10 +286,9 @@ BOOL LLModalDialog::handleKeyHere(KEY key, MASK mask )
void LLModalDialog::draw()
{
static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow");
- static LLUICachedControl shadow_lines ("DropShadowFloater", 0);
gl_drop_shadow( 0, getRect().getHeight(), getRect().getWidth(), 0,
- shadow_color, shadow_lines);
+ shadow_color, DROP_SHADOW_FLOATER);
LLFloater::draw();
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
index 5319b0d3b6..b0598b4388 100644
--- a/indra/llui/llmultisliderctrl.cpp
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -138,7 +138,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p)
params.font(p.font);
params.max_length.bytes(MAX_STRING_LENGTH);
params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit);
- params.prevalidate_callback(&LLTextValidate::validateFloat);
+ params.prevalidator(&LLTextValidate::validateFloat);
params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
mEditor = LLUICtrlFactory::create (params);
mEditor->setFocusReceivedCallback( boost::bind(LLMultiSliderCtrl::onEditorGainFocus, _1, this) );
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 875be5bc6f..2fbae73b65 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -87,6 +87,7 @@ LLNotificationForm::FormInput::FormInput()
: type("type"),
text("text"),
max_length_chars("max_length_chars"),
+ allow_emoji("allow_emoji"),
width("width", 0),
value("value")
{}
@@ -1551,6 +1552,11 @@ bool LLNotifications::loadTemplates()
// specific skin.
std::vector search_paths =
gDirUtilp->findSkinnedFilenames(LLDir::XUI, "notifications.xml", LLDir::ALL_SKINS);
+ if (search_paths.empty())
+ {
+ LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"));
+ LL_ERRS() << "Problem finding notifications.xml" << LL_ENDL;
+ }
std::string base_filename = search_paths.front();
LLXMLNodePtr root;
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 99f67c06e5..ab4f009a80 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -201,6 +201,7 @@ public:
Mandatory type;
Optional width;
Optional max_length_chars;
+ Optional allow_emoji;
Optional text;
Optional value;
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index 0073ac4ead..ea2327961a 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -81,7 +81,7 @@ public:
alt_value("alt_value", ""),
label("label"),
tool_tip("tool_tip", ""),
- font("font", LLFontGL::getFontSansSerifSmall()),
+ font("font", LLFontGL::getFontEmojiSmall()),
font_color("font_color", LLColor4::black),
color("color", LLColor4::white),
font_halign("halign", LLFontGL::LEFT)
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 5b9944d3e0..7fb732eca3 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -1810,7 +1810,7 @@ BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, MASK mask)
// display tooltip exactly over original cell, in same font
LLToolTipMgr::instance().show(LLToolTip::Params()
.message(hit_cell->getToolTip())
- .font(LLFontGL::getFontSansSerifSmall())
+ .font(LLFontGL::getFontEmojiSmall())
.pos(LLCoordGL(sticky_rect.mLeft - 5, sticky_rect.mTop + 6))
.delay_time(0.2f)
.sticky_rect(sticky_rect));
@@ -3294,7 +3294,7 @@ LLScrollListItem* LLScrollListCtrl::addSimpleElement(const std::string& value, E
item_params.value(entry_id);
item_params.columns.add()
.value(value)
- .font(LLFontGL::getFontSansSerifSmall());
+ .font(LLFontGL::getFontEmojiSmall());
return addRow(item_params, pos);
}
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index 53eb667a1d..e16ba9408e 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -167,7 +167,7 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p)
}
line_p.commit_callback.function(&LLSliderCtrl::onEditorCommit);
- line_p.prevalidate_callback(&LLTextValidate::validateFloat);
+ line_p.prevalidator(&LLTextValidate::validateFloat);
mEditor = LLUICtrlFactory::create(line_p);
mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onEditorGainFocus, _1, this ));
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 46f60508b2..78c4f3c03c 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -225,7 +225,8 @@ LLTabContainer::Params::Params()
tabs_flashing_color("tabs_flashing_color"),
tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0),
use_ellipses("use_ellipses"),
- font_halign("halign")
+ font_halign("halign"),
+ use_tab_offset("use_tab_offset", false)
{}
LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
@@ -264,7 +265,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
mTabIconCtrlPad(p.tab_icon_ctrl_pad),
mEnableTabsFlashing(p.enable_tabs_flashing),
mTabsFlashingColor(p.tabs_flashing_color),
- mUseTabEllipses(p.use_ellipses)
+ mUseTabEllipses(p.use_ellipses),
+ mUseTabOffset(p.use_tab_offset)
{
static LLUICachedControl tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0);
@@ -1023,10 +1025,9 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
}
else
{
- tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH * 3,
- tab_panel_top,
- getRect().getWidth() - LLPANEL_BORDER_WIDTH * 2,
- tab_panel_bottom );
+ S32 left_offset = mUseTabOffset ? LLPANEL_BORDER_WIDTH * 3 : LLPANEL_BORDER_WIDTH;
+ S32 right_offset = mUseTabOffset ? LLPANEL_BORDER_WIDTH * 2 : LLPANEL_BORDER_WIDTH;
+ tab_panel_rect = LLRect(left_offset, tab_panel_top, getRect().getWidth() - right_offset, tab_panel_bottom);
}
child->setFollowsAll();
child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom);
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index 0604785e7a..626255be8c 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -121,6 +121,8 @@ public:
*/
Optional tab_icon_ctrl_pad;
+ Optional use_tab_offset;
+
Params();
};
@@ -321,6 +323,8 @@ private:
S32 mTabIconCtrlPad;
bool mUseTabEllipses;
LLFrameTimer mMouseDownTimer;
+
+ bool mUseTabOffset;
};
#endif // LL_TABCONTAINER_H
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 1460bb85b6..c1eedf93a7 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -168,6 +168,7 @@ LLTextBase::Params::Params()
trusted_content("trusted_content", true),
always_show_icons("always_show_icons", false),
use_ellipses("use_ellipses", false),
+ use_emoji("use_emoji", true),
use_color("use_color", true),
parse_urls("parse_urls", false),
force_urls_external("force_urls_external", false),
@@ -227,6 +228,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
mPlainText ( p.plain_text ),
mWordWrap(p.wrap),
mUseEllipses( p.use_ellipses ),
+ mUseEmoji(p.use_emoji),
mUseColor(p.use_color),
mParseHTML(p.parse_urls),
mForceUrlsExternal(p.force_urls_external),
@@ -903,6 +905,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
}
// Insert special segments where necessary (insertSegment takes care of splitting normal text segments around them for us)
+ if (mUseEmoji)
{
LLStyleSP emoji_style;
LLEmojiDictionary* ed = LLEmojiDictionary::instanceExists() ? LLEmojiDictionary::getInstance() : NULL;
@@ -915,7 +918,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
if (!emoji_style)
{
emoji_style = new LLStyle(getStyleParams());
- emoji_style->setFont(LLFontGL::getFontEmoji());
+ emoji_style->setFont(LLFontGL::getFontEmojiLarge());
}
S32 new_seg_start = pos + text_kitty;
@@ -1286,19 +1289,6 @@ BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask)
return LLUICtrl::handleToolTip(x, y, mask);
}
-//virtual
-const std::string LLTextBase::getToolTip() const
-{
- if (sDebugUnicode)
- {
- std::string text = getText();
- std::string tooltip = utf8str_showBytesUTF8(text);
- return tooltip;
- }
-
- return LLUICtrl::getToolTip();
-}
-
//virtual
void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent)
{
@@ -2182,10 +2172,10 @@ void LLTextBase::setText(const LLStringExplicit &utf8str, const LLStyle::Params&
onValueChange(0, getLength());
}
-//virtual
-std::string LLTextBase::getText() const
+// virtual
+const std::string& LLTextBase::getText() const
{
- return getViewModel()->getValue().asString();
+ return getViewModel()->getStringValue();
}
// IDEVO - icons can be UI image names or UUID sent from
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 13fb1ff397..97507fe800 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -328,6 +328,7 @@ public:
plain_text,
wrap,
use_ellipses,
+ use_emoji,
use_color,
parse_urls,
force_urls_external,
@@ -366,7 +367,6 @@ public:
/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask) override;
// LLView interface
- /*virtual*/ const std::string getToolTip() const override;
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override;
/*virtual*/ void draw() override;
@@ -408,12 +408,15 @@ public:
virtual void onSpellCheckPerformed(){}
// used by LLTextSegment layout code
- bool getWordWrap() { return mWordWrap; }
- bool getUseEllipses() { return mUseEllipses; }
- bool getUseColor() { return mUseColor; }
+ bool getWordWrap() const { return mWordWrap; }
+ bool getUseEllipses() const { return mUseEllipses; }
+ bool getUseEmoji() const { return mUseEmoji; }
+ void setUseEmoji(bool value) { mUseEmoji = value; }
+ bool getUseColor() const { return mUseColor; }
+ void setUseColor(bool value) { mUseColor = value; }
bool truncate(); // returns true of truncation occurred
- bool isContentTrusted() {return mTrustedContent;}
+ bool isContentTrusted() const { return mTrustedContent; }
void setContentTrusted(bool trusted_content) { mTrustedContent = trusted_content; }
// TODO: move into LLTextSegment?
@@ -422,7 +425,7 @@ public:
// Text accessors
// TODO: add optional style parameter
virtual void setText(const LLStringExplicit &utf8str , const LLStyle::Params& input_params = LLStyle::Params()); // uses default style
- virtual std::string getText() const;
+ /*virtual*/ const std::string& getText() const override;
void setMaxTextLength(S32 length) { mMaxTextByteLength = length; }
S32 getMaxTextLength() { return mMaxTextByteLength; }
@@ -495,7 +498,7 @@ public:
bool scrolledToStart();
bool scrolledToEnd();
- const LLFontGL* getFont() const { return mFont; }
+ const LLFontGL* getFont() const override { return mFont; }
virtual void appendLineBreakSegment(const LLStyle::Params& style_params);
virtual void appendImageSegment(const LLStyle::Params& style_params);
@@ -716,6 +719,7 @@ protected:
bool mParseHighlights; // highlight user-defined keywords
bool mWordWrap;
bool mUseEllipses;
+ bool mUseEmoji;
bool mUseColor;
bool mTrackEnd; // if true, keeps scroll position at end of document during resize
bool mReadOnly;
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 4fd650f2da..e030861f20 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -232,7 +232,7 @@ private:
///////////////////////////////////////////////////////////////////
LLTextEditor::Params::Params()
: default_text("default_text"),
- prevalidate_callback("prevalidate_callback"),
+ prevalidator("prevalidator"),
embedded_items("embedded_items", false),
ignore_tab("ignore_tab", true),
auto_indent("auto_indent", true),
@@ -242,7 +242,8 @@ LLTextEditor::Params::Params()
show_emoji_helper("show_emoji_helper"),
enable_tooltip_paste("enable_tooltip_paste")
{
- addSynonym(prevalidate_callback, "text_type");
+ addSynonym(prevalidator, "prevalidate_callback");
+ addSynonym(prevalidator, "text_type");
}
LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
@@ -253,16 +254,17 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
mLastCmd( NULL ),
mDefaultColor( p.default_color() ),
mAutoIndent(p.auto_indent),
+ mParseOnTheFly(false),
mCommitOnFocusLost( p.commit_on_focus_lost),
mAllowEmbeddedItems( p.embedded_items ),
mMouseDownX(0),
mMouseDownY(0),
mTabsToNextField(p.ignore_tab),
- mPrevalidateFunc(p.prevalidate_callback()),
+ mPrevalidator(p.prevalidator()),
mShowContextMenu(p.show_context_menu),
mShowEmojiHelper(p.show_emoji_helper),
mEnableTooltipPaste(p.enable_tooltip_paste),
- mPassDelete(FALSE),
+ mPassDelete(false),
mKeepSelectionOnReturn(false)
{
mSourceID.generate();
@@ -278,7 +280,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
addChild( mBorder );
setText(p.default_text());
- mParseOnTheFly = TRUE;
+ mParseOnTheFly = true;
}
void LLTextEditor::initFromParams( const LLTextEditor::Params& p)
@@ -319,11 +321,13 @@ LLTextEditor::~LLTextEditor()
void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params)
{
// validate incoming text if necessary
- if (mPrevalidateFunc)
+ if (mPrevalidator)
{
- LLWString test_text = utf8str_to_wstring(utf8str);
- if (!mPrevalidateFunc(test_text))
+ if (!mPrevalidator.validate(utf8str))
{
+ LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
+
// not valid text, nothing to do
return;
}
@@ -332,9 +336,9 @@ void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Param
blockUndo();
deselect();
- mParseOnTheFly = FALSE;
+ mParseOnTheFly = false;
LLTextBase::setText(utf8str, input_params);
- mParseOnTheFly = TRUE;
+ mParseOnTheFly = true;
resetDirty();
}
@@ -609,7 +613,7 @@ void LLTextEditor::indentSelectedLines( S32 spaces )
// Disabling parsing on the fly to avoid updating text segments
// until all indentation commands are executed.
- mParseOnTheFly = FALSE;
+ mParseOnTheFly = false;
// Find each start-of-line and indent it
do
@@ -636,7 +640,7 @@ void LLTextEditor::indentSelectedLines( S32 spaces )
}
while( cur < right );
- mParseOnTheFly = TRUE;
+ mParseOnTheFly = true;
if( (right < getLength()) && (text[right] == '\n') )
{
@@ -685,7 +689,7 @@ void LLTextEditor::insertEmoji(llwchar emoji)
{
LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL;
auto styleParams = LLStyle::Params();
- styleParams.font = LLFontGL::getFontEmoji();
+ styleParams.font = LLFontGL::getFontEmojiLarge();
auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this);
insert(mCursorPos, LLWString(1, emoji), false, segment);
setCursorPos(mCursorPos + 1);
@@ -986,10 +990,12 @@ S32 LLTextEditor::execute( TextCmd* cmd )
mUndoStack.push_front(cmd);
mLastCmd = cmd;
- bool need_to_rollback = mPrevalidateFunc
- && !mPrevalidateFunc(getViewModel()->getDisplay());
+ bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(getViewModel()->getDisplay());
if (need_to_rollback)
{
+ LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
+
// get rid of this last command and clean up undo stack
undo();
@@ -1125,16 +1131,15 @@ void LLTextEditor::removeChar()
// Add a single character to the text
S32 LLTextEditor::addChar(S32 pos, llwchar wc)
{
- if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength)
+ if ((wstring_utf8_length(getWText()) + wchar_utf8_length(wc)) > mMaxTextByteLength)
{
- make_ui_sound("UISndBadKeystroke");
+ LLUI::getInstance()->reportBadKeystroke();
return 0;
}
if (mLastCmd && mLastCmd->canExtend(pos))
{
- S32 delta = 0;
- if (mPrevalidateFunc)
+ if (mPrevalidator)
{
// get a copy of current text contents
LLWString test_string(getViewModel()->getDisplay());
@@ -1142,28 +1147,31 @@ S32 LLTextEditor::addChar(S32 pos, llwchar wc)
// modify text contents as if this addChar succeeded
llassert(pos <= (S32)test_string.size());
test_string.insert(pos, 1, wc);
- if (!mPrevalidateFunc( test_string))
+ if (!mPrevalidator.validate(test_string))
{
+ LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
return 0;
}
}
+
+ S32 delta = 0;
mLastCmd->extendAndExecute(this, pos, wc, &delta);
return delta;
}
- else
- {
- return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr()));
- }
+
+ return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr()));
}
void LLTextEditor::addChar(llwchar wc)
{
- if( !getEnabled() )
+ if (!getEnabled())
{
return;
}
- if( hasSelection() )
+
+ if (hasSelection())
{
deleteSelection(TRUE);
}
@@ -1508,7 +1516,13 @@ void LLTextEditor::pastePrimary()
// paste from primary (itsprimary==true) or clipboard (itsprimary==false)
void LLTextEditor::pasteHelper(bool is_primary)
{
- mParseOnTheFly = FALSE;
+ struct BoolReset
+ {
+ BoolReset(bool& value) : mValuePtr(&value) { *mValuePtr = false; }
+ ~BoolReset() { *mValuePtr = true; }
+ bool* mValuePtr;
+ } reset(mParseOnTheFly);
+
bool can_paste_it;
if (is_primary)
{
@@ -1550,7 +1564,6 @@ void LLTextEditor::pasteHelper(bool is_primary)
deselect();
onKeyStroke();
- mParseOnTheFly = TRUE;
}
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index e965848ce1..e917f65fbd 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -54,7 +54,7 @@ public:
struct Params : public LLInitParam::Block
{
Optional default_text;
- Optional prevalidate_callback;
+ Optional prevalidator;
Optional embedded_items,
ignore_tab,
@@ -337,7 +337,7 @@ private:
LLCoordGL mLastIMEPosition; // Last position of the IME editor
keystroke_signal_t mKeystrokeSignal;
- LLTextValidate::validate_func_t mPrevalidateFunc;
+ LLTextValidate::Validator mPrevalidator;
LLHandle mContextMenuHandle;
}; // end class LLTextEditor
diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp
index 07f8ac01a1..9e27ed6232 100644
--- a/indra/llui/lltextvalidate.cpp
+++ b/indra/llui/lltextvalidate.cpp
@@ -1,25 +1,25 @@
-/**
+/**
* @file lltextvalidate.cpp
* @brief Text validation helper functions
*
* $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$
*/
@@ -29,328 +29,450 @@
#include "linden_common.h"
#include "lltextvalidate.h"
+
+#include "llnotificationsutil.h"
+#include "lltrans.h"
+
#include "llresmgr.h" // for LLLocale
namespace LLTextValidate
{
- void ValidateTextNamedFuncs::declareValues()
+
+static S32 strtol(const std::string& str) { return ::strtol(str.c_str(), NULL, 10); }
+static S32 strtol(const LLWString& str) { return ::strtol(wstring_to_utf8str(str).c_str(), NULL, 10); }
+
+static LLSD llsd(const std::string& str) { return LLSD(str); }
+static LLSD llsd(const LLWString& str) { return LLSD(wstring_to_utf8str(str)); }
+template
+LLSD llsd(CHAR ch) { return llsd(std::basic_string(1, ch)); }
+
+void ValidatorImpl::setLastErrorShowTime()
+{
+ mLastErrorShowTime = (U32Seconds)LLTimer::getTotalTime();
+}
+
+void Validator::showLastErrorUsingTimeout(U32 timeout)
+{
+ if (mImpl && (U32Seconds)LLTimer::getTotalTime() >= mImpl->getLastErrorShowTime() + timeout)
{
- declare("ascii", validateASCII);
- declare("float", validateFloat);
- declare("int", validateInt);
- declare("positive_s32", validatePositiveS32);
- declare("non_negative_s32", validateNonNegativeS32);
- declare("alpha_num", validateAlphaNum);
- declare("alpha_num_space", validateAlphaNumSpace);
- declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe);
- declare("ascii_printable_no_space", validateASCIIPrintableNoSpace);
- declare("ascii_with_newline", validateASCIIWithNewLine);
- }
-
- // Limits what characters can be used to [1234567890.-] with [-] only valid in the first position.
- // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for
- // the simple reasons that intermediate states may be invalid even if the final result is valid.
- //
- bool validateFloat(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- bool success = TRUE;
- LLWString trimmed = str;
- LLWStringUtil::trim(trimmed);
- S32 len = trimmed.length();
- if( 0 < len )
- {
- // May be a comma or period, depending on the locale
- llwchar decimal_point = (llwchar)LLResMgr::getInstance()->getDecimalPoint();
-
- S32 i = 0;
-
- // First character can be a negative sign
- if( '-' == trimmed[0] )
- {
- i++;
- }
-
- for( ; i < len; i++ )
- {
- if( (decimal_point != trimmed[i] ) && !LLStringOps::isDigit( trimmed[i] ) )
- {
- success = FALSE;
- break;
- }
- }
- }
-
- return success;
- }
-
- // Limits what characters can be used to [1234567890-] with [-] only valid in the first position.
- // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for
- // the simple reasons that intermediate states may be invalid even if the final result is valid.
- //
- bool validateInt(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- bool success = TRUE;
- LLWString trimmed = str;
- LLWStringUtil::trim(trimmed);
- S32 len = trimmed.length();
- if( 0 < len )
- {
- S32 i = 0;
-
- // First character can be a negative sign
- if( '-' == trimmed[0] )
- {
- i++;
- }
-
- for( ; i < len; i++ )
- {
- if( !LLStringOps::isDigit( trimmed[i] ) )
- {
- success = FALSE;
- break;
- }
- }
- }
-
- return success;
- }
-
- bool validatePositiveS32(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- LLWString trimmed = str;
- LLWStringUtil::trim(trimmed);
- S32 len = trimmed.length();
- bool success = TRUE;
- if(0 < len)
- {
- if(('-' == trimmed[0]) || ('0' == trimmed[0]))
- {
- success = FALSE;
- }
- S32 i = 0;
- while(success && (i < len))
- {
- if(!LLStringOps::isDigit(trimmed[i++]))
- {
- success = FALSE;
- }
- }
- }
- if (success)
- {
- S32 val = strtol(wstring_to_utf8str(trimmed).c_str(), NULL, 10);
- if (val <= 0)
- {
- success = FALSE;
- }
- }
- return success;
- }
-
- bool validateNonNegativeS32(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- LLWString trimmed = str;
- LLWStringUtil::trim(trimmed);
- S32 len = trimmed.length();
- bool success = TRUE;
- if(0 < len)
- {
- if('-' == trimmed[0])
- {
- success = FALSE;
- }
- S32 i = 0;
- while(success && (i < len))
- {
- if(!LLStringOps::isDigit(trimmed[i++]))
- {
- success = FALSE;
- }
- }
- }
- if (success)
- {
- S32 val = strtol(wstring_to_utf8str(trimmed).c_str(), NULL, 10);
- if (val < 0)
- {
- success = FALSE;
- }
- }
- return success;
- }
-
- bool validateNonNegativeS32NoSpace(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- LLWString test_str = str;
- S32 len = test_str.length();
- bool success = TRUE;
- if(0 < len)
- {
- if('-' == test_str[0])
- {
- success = FALSE;
- }
- S32 i = 0;
- while(success && (i < len))
- {
- if(!LLStringOps::isDigit(test_str[i]) || LLStringOps::isSpace(test_str[i++]))
- {
- success = FALSE;
- }
- }
- }
- if (success)
- {
- S32 val = strtol(wstring_to_utf8str(test_str).c_str(), NULL, 10);
- if (val < 0)
- {
- success = FALSE;
- }
- }
- return success;
- }
-
- bool validateAlphaNum(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- bool rv = TRUE;
- S32 len = str.length();
- if(len == 0) return rv;
- while(len--)
- {
- if( !LLStringOps::isAlnum((char)str[len]) )
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
- }
-
- bool validateAlphaNumSpace(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- bool rv = TRUE;
- S32 len = str.length();
- if(len == 0) return rv;
- while(len--)
- {
- if(!(LLStringOps::isAlnum((char)str[len]) || (' ' == str[len])))
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
- }
-
- // Used for most names of things stored on the server, due to old file-formats
- // that used the pipe (|) for multiline text storage. Examples include
- // inventory item names, parcel names, object names, etc.
- bool validateASCIIPrintableNoPipe(const LLWString &str)
- {
- bool rv = TRUE;
- S32 len = str.length();
- if(len == 0) return rv;
- while(len--)
- {
- llwchar wc = str[len];
- if (wc < 0x20
- || wc > 0x7f
- || wc == '|')
- {
- rv = FALSE;
- break;
- }
- if(!(wc == ' '
- || LLStringOps::isAlnum((char)wc)
- || LLStringOps::isPunct((char)wc) ) )
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
- }
-
-
- // Used for avatar names
- bool validateASCIIPrintableNoSpace(const LLWString &str)
- {
- bool rv = TRUE;
- S32 len = str.length();
- if(len == 0) return rv;
- while(len--)
- {
- llwchar wc = str[len];
- if (wc < 0x20
- || wc > 0x7f
- || LLStringOps::isSpace(wc))
- {
- rv = FALSE;
- break;
- }
- if( !(LLStringOps::isAlnum((char)str[len]) ||
- LLStringOps::isPunct((char)str[len]) ) )
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
- }
-
- bool validateASCII(const LLWString &str)
- {
- bool rv = TRUE;
- S32 len = str.length();
- while(len--)
- {
- if (str[len] < 0x20 || str[len] > 0x7f)
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
- }
-
- bool validateASCIINoLeadingSpace(const LLWString &str)
- {
- if (LLStringOps::isSpace(str[0]))
- {
- return FALSE;
- }
- return validateASCII(str);
- }
-
- // Used for multiline text stored on the server.
- // Example is landmark description in Places SP.
- bool validateASCIIWithNewLine(const LLWString &str)
- {
- bool rv = TRUE;
- S32 len = str.length();
- while(len--)
- {
- if ((str[len] < 0x20 && str[len] != 0xA) || str[len] > 0x7f)
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
+ mImpl->setLastErrorShowTime();
+ std::string reason = LLTrans::getString(mImpl->getLastErrorName(), mImpl->getLastErrorValues());
+ LLNotificationsUtil::add("InvalidKeystroke", LLSD().with("REASON", reason));
}
}
+
+// Limits what characters can be used to [1234567890.-] with [-] only valid in the first position.
+// Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for
+// the simple reasons that intermediate states may be invalid even if the final result is valid.
+class ValidatorFloat : public ValidatorImpl
+{
+ template
+ bool validate(const std::basic_string &str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ std::basic_string trimmed = str;
+ LLStringUtilBase::trim(trimmed);
+ S32 len = trimmed.length();
+ if (0 < len)
+ {
+ // May be a comma or period, depending on the locale
+ CHAR decimal_point = LLResMgr::getInstance()->getDecimalPoint();
+
+ S32 i = 0;
+
+ // First character can be a negative sign
+ if ('-' == trimmed.front())
+ {
+ i++;
+ }
+
+ for (; i < len; i++)
+ {
+ CHAR ch = trimmed[i];
+ if ((decimal_point != ch) && !LLStringOps::isDigit(ch))
+ {
+ return setError("Validator_ShouldBeDigitOrDot", LLSD().with("NR", i + 1).with("CH", llsd(ch)));
+ }
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate(str); }
+} validatorFloatImpl;
+Validator validateFloat(validatorFloatImpl);
+
+// Limits what characters can be used to [1234567890-] with [-] only valid in the first position.
+// Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for
+// the simple reasons that intermediate states may be invalid even if the final result is valid.
+class ValidatorInt : public ValidatorImpl
+{
+ template
+ bool validate(const std::basic_string &str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ std::basic_string trimmed = str;
+ LLStringUtilBase::trim(trimmed);
+ S32 len = trimmed.length();
+ if (0 < len)
+ {
+ S32 i = 0;
+
+ // First character can be a negative sign
+ if ('-' == trimmed.front())
+ {
+ i++;
+ }
+
+ for (; i < len; i++)
+ {
+ CHAR ch = trimmed[i];
+ if (!LLStringOps::isDigit(ch))
+ {
+ return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch)));
+ }
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate(str); }
+} validatorIntImpl;
+Validator validateInt(validatorIntImpl);
+
+class ValidatorPositiveS32 : public ValidatorImpl
+{
+ template
+ bool validate(const std::basic_string& str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ std::basic_string trimmed = str;
+ LLStringUtilBase::trim(trimmed);
+ S32 len = trimmed.length();
+ if (0 < len)
+ {
+ CHAR ch = trimmed.front();
+
+ if (('-' == ch) || ('0' == ch))
+ {
+ return setError("Validator_ShouldNotBeMinusOrZero", LLSD().with("CH", llsd(ch)));
+ }
+
+ for (S32 i = 0; i < len; ++i)
+ {
+ ch = trimmed[i];
+ if (!LLStringOps::isDigit(ch))
+ {
+ return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch)));
+ }
+ }
+ }
+
+ S32 val = strtol(trimmed);
+ if (val <= 0)
+ {
+ return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(trimmed)));
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate(str); }
+} validatorPositiveS32Impl;
+Validator validatePositiveS32(validatorPositiveS32Impl);
+
+class ValidatorNonNegativeS32 : public ValidatorImpl
+{
+ template
+ bool validate(const std::basic_string& str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ std::basic_string trimmed = str;
+ LLStringUtilBase::trim(trimmed);
+ S32 len = trimmed.length();
+ if (0 < len)
+ {
+ CHAR ch = trimmed.front();
+
+ if ('-' == ch)
+ {
+ return setError("Validator_ShouldNotBeMinus", LLSD().with("CH", llsd(ch)));
+ }
+
+ for (S32 i = 0; i < len; ++i)
+ {
+ ch = trimmed[i];
+ if (!LLStringOps::isDigit(ch))
+ {
+ return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch)));
+ }
+ }
+ }
+
+ S32 val = strtol(trimmed);
+ if (val < 0)
+ {
+ return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(trimmed)));
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate(str); }
+} validatorNonNegativeS32Impl;
+Validator validateNonNegativeS32(validatorNonNegativeS32Impl);
+
+class ValidatorNonNegativeS32NoSpace : public ValidatorImpl
+{
+ template
+ bool validate(const std::basic_string& str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ std::basic_string test_str = str;
+ S32 len = test_str.length();
+ if (0 < len)
+ {
+ CHAR ch = test_str.front();
+
+ if ('-' == ch)
+ {
+ return setError("Validator_ShouldNotBeMinus", LLSD().with("CH", llsd(ch)));
+ }
+
+ for (S32 i = 0; i < len; ++i)
+ {
+ ch = test_str[i];
+ if (!LLStringOps::isDigit(ch) || LLStringOps::isSpace(ch))
+ {
+ return setError("Validator_ShouldBeDigitNotSpace", LLSD().with("NR", i + 1).with("CH", llsd(ch)));
+ }
+ }
+ }
+
+ S32 val = strtol(test_str);
+ if (val < 0)
+ {
+ return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(test_str)));
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate(str); }
+} validatorNonNegativeS32NoSpaceImpl;
+Validator validateNonNegativeS32NoSpace(validatorNonNegativeS32NoSpaceImpl);
+
+class ValidatorAlphaNum : public ValidatorImpl
+{
+ template
+ bool validate(const std::basic_string& str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ S32 len = str.length();
+ while (len--)
+ {
+ CHAR ch = str[len];
+
+ if (!LLStringOps::isAlnum(ch))
+ {
+ return setError("Validator_ShouldBeDigitOrAlpha", LLSD().with("NR", len + 1).with("CH", llsd(ch)));
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate(str); }
+} validatorAlphaNumImpl;
+Validator validateAlphaNum(validatorAlphaNumImpl);
+
+class ValidatorAlphaNumSpace : public ValidatorImpl
+{
+ template
+ bool validate(const std::basic_string& str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ S32 len = str.length();
+ while (len--)
+ {
+ CHAR ch = str[len];
+
+ if (!LLStringOps::isAlnum(ch) && (' ' != ch))
+ {
+ return setError("Validator_ShouldBeDigitOrAlphaOrSpace", LLSD().with("NR", len + 1).with("CH", llsd(ch)));
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate(str); }
+} validatorAlphaNumSpaceImpl;
+Validator validateAlphaNumSpace(validatorAlphaNumSpaceImpl);
+
+// Used for most names of things stored on the server, due to old file-formats
+// that used the pipe (|) for multiline text storage. Examples include
+// inventory item names, parcel names, object names, etc.
+class ValidatorASCIIPrintableNoPipe : public ValidatorImpl
+{
+ template
+ bool validate(const std::basic_string& str)
+ {
+ S32 len = str.length();
+ while (len--)
+ {
+ CHAR ch = str[len];
+
+ if (ch < 0x20 || ch > 0x7f || ch == '|' ||
+ (ch != ' ' && !LLStringOps::isAlnum(ch) && !LLStringOps::isPunct(ch)))
+ {
+ return setError("Validator_ShouldBeDigitOrAlphaOrPunct", LLSD().with("NR", len + 1).with("CH", llsd(ch)));
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate(str); }
+} validatorASCIIPrintableNoPipeImpl;
+Validator validateASCIIPrintableNoPipe(validatorASCIIPrintableNoPipeImpl);
+
+// Used for avatar names
+class ValidatorASCIIPrintableNoSpace : public ValidatorImpl
+{
+ template
+ bool validate(const std::basic_string& str)
+ {
+ S32 len = str.length();
+ while (len--)
+ {
+ CHAR ch = str[len];
+
+ if (ch <= 0x20 || ch > 0x7f || LLStringOps::isSpace(ch) ||
+ (!LLStringOps::isAlnum(ch) && !LLStringOps::isPunct(ch)))
+ {
+ return setError("Validator_ShouldBeDigitOrAlphaOrPunctNotSpace", LLSD().with("NR", len + 1).with("CH", llsd(ch)));
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate(str); }
+} validatorASCIIPrintableNoSpaceImpl;
+Validator validateASCIIPrintableNoSpace(validatorASCIIPrintableNoSpaceImpl);
+
+class ValidatorASCII : public ValidatorImpl
+{
+protected:
+ template
+ bool validate(const std::basic_string& str)
+ {
+ S32 len = str.length();
+ while (len--)
+ {
+ CHAR ch = str[len];
+
+ if (ch < 0x20 || ch > 0x7f)
+ {
+ return setError("Validator_ShouldBeASCII", LLSD().with("NR", len + 1).with("CH", llsd(ch)));
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate(str); }
+} validatorASCIIImpl;
+Validator validateASCII(validatorASCIIImpl);
+
+class ValidatorASCIINoLeadingSpace : public ValidatorASCII
+{
+ template
+ bool validate(const std::basic_string& str)
+ {
+ if (LLStringOps::isSpace(str.front()))
+ {
+ return false;
+ }
+
+ return ValidatorASCII::validate(str);
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate(str); }
+} validatorASCIINoLeadingSpaceImpl;
+Validator validateASCIINoLeadingSpace(validatorASCIINoLeadingSpaceImpl);
+
+class ValidatorASCIIWithNewLine : public ValidatorImpl
+{
+ // Used for multiline text stored on the server.
+ // Example is landmark description in Places SP.
+ template
+ bool validate(const std::basic_string& str)
+ {
+ S32 len = str.length();
+ while (len--)
+ {
+ CHAR ch = str[len];
+
+ if ((ch < 0x20 && ch != 0xA) || ch > 0x7f)
+ {
+ return setError("Validator_ShouldBeNewLineOrASCII", LLSD().with("NR", len + 1).with("CH", llsd(ch)));
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate(str); }
+} validatorASCIIWithNewLineImpl;
+Validator validateASCIIWithNewLine(validatorASCIIWithNewLineImpl);
+
+void Validators::declareValues()
+{
+ declare("ascii", validateASCII);
+ declare("float", validateFloat);
+ declare("int", validateInt);
+ declare("positive_s32", validatePositiveS32);
+ declare("non_negative_s32", validateNonNegativeS32);
+ declare("alpha_num", validateAlphaNum);
+ declare("alpha_num_space", validateAlphaNumSpace);
+ declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe);
+ declare("ascii_printable_no_space", validateASCIIPrintableNoSpace);
+ declare("ascii_with_newline", validateASCIIWithNewLine);
+}
+
+} // namespace LLTextValidate
diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h
index 0dfec1b612..2c2941de7f 100644
--- a/indra/llui/lltextvalidate.h
+++ b/indra/llui/lltextvalidate.h
@@ -1,4 +1,4 @@
-/**
+/**
* @file lltextbase.h
* @author Martin Reddy
* @brief The base class of text box/editor, providing Url handling support
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2009&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$
*/
@@ -34,27 +34,68 @@
namespace LLTextValidate
{
- typedef boost::function validate_func_t;
+ class ValidatorImpl
+ {
+ public:
+ ValidatorImpl() {}
+ virtual ~ValidatorImpl() {}
- struct ValidateTextNamedFuncs
- : public LLInitParam::TypeValuesHelper
+ virtual bool validate(const std::string& str) = 0;
+ virtual bool validate(const LLWString& str) = 0;
+
+ bool setError(std::string name, LLSD values = LLSD()) { return mLastErrorName = name, mLastErrorValues = values, false; }
+ bool resetError() { return mLastErrorName.clear(), mLastErrorValues.clear(), true; }
+ const std::string& getLastErrorName() const { return mLastErrorName; }
+ const LLSD& getLastErrorValues() const { return mLastErrorValues; }
+
+ void setLastErrorShowTime();
+ U32 getLastErrorShowTime() const { return mLastErrorShowTime; }
+
+ protected:
+ std::string mLastErrorName;
+ LLSD mLastErrorValues;
+ U32 mLastErrorShowTime { 0 };
+ };
+
+ class Validator
+ {
+ public:
+ Validator() : mImpl(nullptr) {}
+ Validator(ValidatorImpl& impl) : mImpl(&impl) {}
+ Validator(const Validator& validator) : mImpl(validator.mImpl) {}
+ Validator(const Validator* validator) : mImpl(validator->mImpl) {}
+
+ bool validate(const std::string& str) const { return !mImpl || mImpl->validate(str); }
+ bool validate(const LLWString& str) const { return !mImpl || mImpl->validate(str); }
+
+ operator bool() const { return mImpl; }
+
+ static const U32 SHOW_LAST_ERROR_TIMEOUT_SEC = 30;
+ void showLastErrorUsingTimeout(U32 timeout = SHOW_LAST_ERROR_TIMEOUT_SEC);
+
+ private:
+ ValidatorImpl* mImpl;
+ };
+
+ // Available validators
+ extern Validator validateFloat;
+ extern Validator validateInt;
+ extern Validator validatePositiveS32;
+ extern Validator validateNonNegativeS32;
+ extern Validator validateNonNegativeS32NoSpace;
+ extern Validator validateAlphaNum;
+ extern Validator validateAlphaNumSpace;
+ extern Validator validateASCIIPrintableNoPipe;
+ extern Validator validateASCIIPrintableNoSpace;
+ extern Validator validateASCII;
+ extern Validator validateASCIINoLeadingSpace;
+ extern Validator validateASCIIWithNewLine;
+
+ // Add available validators to the internal map
+ struct Validators : public LLInitParam::TypeValuesHelper
{
static void declareValues();
};
-
- bool validateFloat(const LLWString &str );
- bool validateInt(const LLWString &str );
- bool validatePositiveS32(const LLWString &str);
- bool validateNonNegativeS32(const LLWString &str);
- bool validateNonNegativeS32NoSpace(const LLWString &str);
- bool validateAlphaNum(const LLWString &str );
- bool validateAlphaNumSpace(const LLWString &str );
- bool validateASCIIPrintableNoPipe(const LLWString &str);
- bool validateASCIIPrintableNoSpace(const LLWString &str);
- bool validateASCII(const LLWString &str);
- bool validateASCIINoLeadingSpace(const LLWString &str);
- bool validateASCIIWithNewLine(const LLWString &str);
-}
-
+};
#endif
diff --git a/indra/llui/lltimectrl.cpp b/indra/llui/lltimectrl.cpp
index ca9c05bb6a..3d404293c6 100644
--- a/indra/llui/lltimectrl.cpp
+++ b/indra/llui/lltimectrl.cpp
@@ -49,6 +49,36 @@ const U32 HOURS_MAX = 12;
const U32 MINUTES_PER_HOUR = 60;
const U32 MINUTES_PER_DAY = 24 * MINUTES_PER_HOUR;
+class LLTimeValidatorImpl : public LLTextValidate::ValidatorImpl
+{
+public:
+ // virtual
+ bool validate(const std::string& str) override
+ {
+ std::string hours = LLTimeCtrl::getHoursString(str);
+ if (!LLTimeCtrl::isHoursStringValid(hours))
+ return setError("ValidatorInvalidHours", LLSD().with("STR", hours));
+
+ std::string minutes = LLTimeCtrl::getMinutesString(str);
+ if (!LLTimeCtrl::isMinutesStringValid(minutes))
+ return setError("ValidatorInvalidMinutes", LLSD().with("STR", minutes));
+
+ std::string ampm = LLTimeCtrl::getAMPMString(str);
+ if (!LLTimeCtrl::isPMAMStringValid(ampm))
+ return setError("ValidatorInvalidAMPM", LLSD().with("STR", ampm));
+
+ return resetError();
+ }
+
+ // virtual
+ bool validate(const LLWString& wstr) override
+ {
+ std::string str = wstring_to_utf8str(wstr);
+
+ return validate(str);
+ }
+} validateTimeImpl;
+LLTextValidate::Validator validateTime(validateTimeImpl);
LLTimeCtrl::Params::Params()
: label_width("label_width"),
@@ -111,7 +141,7 @@ LLTimeCtrl::LLTimeCtrl(const LLTimeCtrl::Params& p)
params.keystroke_callback(boost::bind(&LLTimeCtrl::onTextEntry, this, _1));
mEditor = LLUICtrlFactory::create (params);
mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace);
- mEditor->setPrevalidate(boost::bind(&LLTimeCtrl::isTimeStringValid, this, _1));
+ mEditor->setPrevalidate(validateTime);
mEditor->setText(LLStringExplicit("12:00 AM"));
addChild(mEditor);
@@ -247,15 +277,6 @@ void LLTimeCtrl::onTextEntry(LLLineEditor* line_editor)
mTime = h24 * MINUTES_PER_HOUR + m;
}
-bool LLTimeCtrl::isTimeStringValid(const LLWString &wstr)
-{
- std::string str = wstring_to_utf8str(wstr);
-
- return isHoursStringValid(getHoursString(str)) &&
- isMinutesStringValid(getMinutesString(str)) &&
- isPMAMStringValid(getAMPMString(str));
-}
-
void LLTimeCtrl::increaseMinutes()
{
mTime = (mTime + mSnapToMin) % MINUTES_PER_DAY - (mTime % mSnapToMin);
diff --git a/indra/llui/lltimectrl.h b/indra/llui/lltimectrl.h
index ff46bc76ca..a2c016ab6f 100644
--- a/indra/llui/lltimectrl.h
+++ b/indra/llui/lltimectrl.h
@@ -60,6 +60,18 @@ public:
void setTime24(F32 time); // 0.0 - 23.98(3)
+ static std::string getHoursString(const std::string& str);
+ static std::string getMinutesString(const std::string& str);
+ static std::string getAMPMString(const std::string& str);
+
+ static bool isHoursStringValid(const std::string& str);
+ static bool isMinutesStringValid(const std::string& str);
+ static bool isPMAMStringValid(const std::string& str);
+
+ static U32 parseHours(const std::string& str);
+ static U32 parseMinutes(const std::string& str);
+ static bool parseAMPM(const std::string& str);
+
protected:
LLTimeCtrl(const Params&);
friend class LLUICtrlFactory;
@@ -87,8 +99,6 @@ private:
void onDownBtn();
void onTextEntry(LLLineEditor* line_editor);
- bool isTimeStringValid(const LLWString& wstr);
-
void increaseMinutes();
void increaseHours();
@@ -102,18 +112,6 @@ private:
EEditingPart getEditingPart();
- static std::string getHoursString(const std::string& str);
- static std::string getMinutesString(const std::string& str);
- static std::string getAMPMString(const std::string& str);
-
- static bool isHoursStringValid(const std::string& str);
- static bool isMinutesStringValid(const std::string& str);
- static bool isPMAMStringValid(const std::string& str);
-
- static U32 parseHours(const std::string& str);
- static U32 parseMinutes(const std::string& str);
- static bool parseAMPM(const std::string& str);
-
class LLTextBox* mLabelBox;
class LLLineEditor* mEditor;
diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp
index 87b5b8b9af..8a6cb683d2 100644
--- a/indra/llui/lltoolbar.cpp
+++ b/indra/llui/lltoolbar.cpp
@@ -1133,8 +1133,7 @@ BOOL LLToolBarButton::handleHover(S32 x, S32 y, MASK mask)
BOOL handled = FALSE;
S32 mouse_distance_squared = (x - mMouseDownX) * (x - mMouseDownX) + (y - mMouseDownY) * (y - mMouseDownY);
- static LLCachedControl drag_threshold(*LLUI::getInstance()->mSettingGroups["config"], "DragAndDropDistanceThreshold", 3);
- if (mouse_distance_squared > drag_threshold * drag_threshold
+ if (mouse_distance_squared > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD
&& hasMouseCapture() &&
mStartDragItemCallback && mHandleDragItemCallback)
{
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index de1a87f17c..471602515d 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -53,7 +53,7 @@ class LLWindow;
class LLView;
class LLHelp;
-
+const S32 DRAG_N_DROP_DISTANCE_THRESHOLD = 3;
// this enum is used by the llview.h (viewer) and the llassetstorage.h (viewer and sim)
enum EDragAndDropType
{
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 5a66009b78..69093393d9 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -80,7 +80,7 @@ LLUICtrl::Params::Params()
mouseenter_callback("mouseenter_callback"),
mouseleave_callback("mouseleave_callback"),
control_name("control_name"),
- font("font", LLFontGL::getFontSansSerif()),
+ font("font", LLFontGL::getFontEmojiMedium()),
font_halign("halign"),
font_valign("valign"),
length("length"), // ignore LLXMLNode cruft
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index afe8493501..d21e8dc1c6 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -41,6 +41,7 @@
const BOOL TAKE_FOCUS_YES = TRUE;
const BOOL TAKE_FOCUS_NO = FALSE;
+const S32 DROP_SHADOW_FLOATER = 5;
class LLUICtrl
: public LLView, public boost::signals2::trackable
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index a41b7ba4a8..877585cbef 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -898,6 +898,34 @@ F32 LLView::getTooltipTimeout()
: tooltip_delay);
}
+// virtual
+const std::string LLView::getToolTip() const
+{
+ if (sDebugUnicode)
+ {
+ std::string text = getText();
+ if (!text.empty())
+ {
+ const std::string& name = getName();
+ std::string tooltip = llformat("Name: \"%s\"", name.c_str());
+
+ if (const LLFontGL* font = getFont())
+ {
+ tooltip += llformat("\nFont: %s (%s)",
+ font->getFontDesc().getName().c_str(),
+ font->getFontDesc().getSize().c_str()
+ );
+ }
+
+ tooltip += "\n\n" + utf8str_showBytesUTF8(text);
+
+ return tooltip;
+ }
+ }
+
+ return mToolTipMsg.getString();
+}
+
BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 321afdab31..fefdd83bd4 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -244,7 +244,9 @@ public:
ECursorType getHoverCursor() { return mHoverCursor; }
static F32 getTooltipTimeout();
- virtual const std::string getToolTip() const { return mToolTipMsg.getString(); }
+ virtual const std::string getToolTip() const;
+ virtual const std::string& getText() const { return LLStringUtil::null; }
+ virtual const LLFontGL* getFont() const { return nullptr; }
void sendChildToFront(LLView* child);
void sendChildToBack(LLView* child);
diff --git a/indra/llui/llviewmodel.cpp b/indra/llui/llviewmodel.cpp
index 3847d073b4..93106b344f 100644
--- a/indra/llui/llviewmodel.cpp
+++ b/indra/llui/llviewmodel.cpp
@@ -81,7 +81,7 @@ void LLTextViewModel::setValue(const LLSD& value)
{
// approximate LLSD storage usage
LLViewModel::setValue(value);
- mDisplay = utf8str_to_wstring(value.asString());
+ mDisplay = utf8str_to_wstring(mStringValue = value.asString());
// mDisplay and mValue agree
mUpdateFromDisplay = false;
@@ -101,23 +101,34 @@ void LLTextViewModel::setDisplay(const LLWString& value)
mUpdateFromDisplay = true;
}
-LLSD LLTextViewModel::getValue() const
+inline void updateFromDisplayIfNeeded(const LLTextViewModel* model)
{
- // Has anyone called setDisplay() since the last setValue()? If so, have
- // to convert mDisplay back to UTF8.
- if (mUpdateFromDisplay)
+ // Has anyone called setDisplay() since the last setValue()?
+ // If so, have to convert mDisplay back to UTF8.
+ if (model->mUpdateFromDisplay)
{
- // The fact that we're lazily updating fields in this object should be
- // transparent to clients, which is why this method is left
- // conventionally const. Nor do we particularly want to make these
- // members mutable. Just cast away constness in this one place.
- LLTextViewModel* nthis = const_cast(this);
+ // The fact that we're lazily updating fields
+ // in this object should be transparent to clients,
+ // which is why this method is left conventionally const.
+ // Nor do we particularly want to make these members mutable.
+ // Just cast away constness in this one place.
+ LLTextViewModel* nthis = const_cast(model);
nthis->mUpdateFromDisplay = false;
- nthis->mValue = wstring_to_utf8str(mDisplay);
+ nthis->mValue = nthis->mStringValue = wstring_to_utf8str(model->mDisplay);
}
- return LLViewModel::getValue();
}
+LLSD LLTextViewModel::getValue() const
+{
+ updateFromDisplayIfNeeded(this);
+ return mValue;
+}
+
+const std::string& LLTextViewModel::getStringValue() const
+{
+ updateFromDisplayIfNeeded(this);
+ return mStringValue;
+}
////////////////////////////////////////////////////////////////////////////
diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h
index de6749f490..6cf2200a81 100644
--- a/indra/llui/llviewmodel.h
+++ b/indra/llui/llviewmodel.h
@@ -100,6 +100,7 @@ public:
// LLViewModel functions
virtual void setValue(const LLSD& value);
virtual LLSD getValue() const;
+ const std::string& getStringValue() const;
// New functions
/// Get the stored value in string form
@@ -114,12 +115,17 @@ public:
void setDisplay(const LLWString& value);
private:
+ std::string mStringValue;
+
/// To avoid converting every widget's stored value from LLSD to LLWString
/// every frame, cache the converted value
LLWString mDisplay;
+
/// As the user edits individual characters (setDisplay()), defer
/// LLWString-to-UTF8 conversions until s/he's done.
bool mUpdateFromDisplay;
+
+ friend void updateFromDisplayIfNeeded(const LLTextViewModel* model);
};
/**
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 8ccda101c1..aff9334cb6 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -199,7 +199,13 @@ public:
// windows only DirectInput8 for joysticks
virtual void* getDirectInput8() { return NULL; };
- virtual bool getInputDevices(U32 device_type_filter, void * devices_callback, void* userdata) { return false; };
+ virtual bool getInputDevices(U32 device_type_filter,
+ std::function osx_callback,
+ void* win_callback,
+ void* userdata)
+ {
+ return false;
+ };
virtual S32 getRefreshRate() { return mRefreshRate; }
protected:
diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm
index 690fe058db..2e75d309ea 100644
--- a/indra/llwindow/llwindowmacosx-objc.mm
+++ b/indra/llwindow/llwindowmacosx-objc.mm
@@ -27,6 +27,7 @@
#include
#include
+#include
#include "llopenglview-objc.h"
#include "llwindowmacosx-objc.h"
#include "llappdelegate-objc.h"
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 34ec85bcf6..453905b19b 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -43,6 +43,13 @@
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+
extern BOOL gDebugWindowProc;
BOOL gHiDPISupport = TRUE;
@@ -212,13 +219,16 @@ bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask)
bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character)
{
- if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y'))
+ //if (mask!=MASK_NONE)
{
- key = gKeyboard->inverseTranslateKey('Y');
- }
- else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z'))
- {
- key = gKeyboard->inverseTranslateKey('Z');
+ if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y'))
+ {
+ key = gKeyboard->inverseTranslateKey('Y');
+ }
+ else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z'))
+ {
+ key = gKeyboard->inverseTranslateKey('Z');
+ }
}
mRawKeyEvent = event;
@@ -1841,6 +1851,486 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async)
}
}
+// String should match ndof, so string mapping code was copied as is
+static char mapChar( char c )
+{
+ unsigned char uc = ( unsigned char ) c;
+
+ switch( uc )
+ {
+ case '/': return '-'; // use dash instead of slash
+
+ case 0x7F: return ' ';
+ case 0x80: return 'A';
+ case 0x81: return 'A';
+ case 0x82: return 'C';
+ case 0x83: return 'E';
+ case 0x84: return 'N';
+ case 0x85: return 'O';
+ case 0x86: return 'U';
+ case 0x87: return 'a';
+ case 0x88: return 'a';
+ case 0x89: return 'a';
+ case 0x8A: return 'a';
+ case 0x8B: return 'a';
+ case 0x8C: return 'a';
+ case 0x8D: return 'c';
+ case 0x8E: return 'e';
+ case 0x8F: return 'e';
+ case 0x90: return ' ';
+ case 0x91: return ' '; // ? '
+ case 0x92: return ' '; // ? '
+ case 0x93: return ' '; // ? "
+ case 0x94: return ' '; // ? "
+ case 0x95: return ' ';
+ case 0x96: return ' ';
+ case 0x97: return ' ';
+ case 0x98: return ' ';
+ case 0x99: return ' ';
+ case 0x9A: return ' ';
+ case 0x9B: return 0x27;
+ case 0x9C: return 0x22;
+ case 0x9D: return ' ';
+ case 0x9E: return ' ';
+ case 0x9F: return ' ';
+ case 0xA0: return ' ';
+ case 0xA1: return ' ';
+ case 0xA2: return ' ';
+ case 0xA3: return ' ';
+ case 0xA4: return ' ';
+ case 0xA5: return ' ';
+ case 0xA6: return ' ';
+ case 0xA7: return ' ';
+ case 0xA8: return ' ';
+ case 0xA9: return ' ';
+ case 0xAA: return ' ';
+ case 0xAB: return ' ';
+ case 0xAC: return ' ';
+ case 0xAD: return ' ';
+ case 0xAE: return ' ';
+ case 0xAF: return ' ';
+ case 0xB0: return ' ';
+ case 0xB1: return ' ';
+ case 0xB2: return ' ';
+ case 0xB3: return ' ';
+ case 0xB4: return ' ';
+ case 0xB5: return ' ';
+ case 0xB6: return ' ';
+ case 0xB7: return ' ';
+ case 0xB8: return ' ';
+ case 0xB9: return ' ';
+ case 0xBA: return ' ';
+ case 0xBB: return ' ';
+ case 0xBC: return ' ';
+ case 0xBD: return ' ';
+ case 0xBE: return ' ';
+ case 0xBF: return ' ';
+ case 0xC0: return ' ';
+ case 0xC1: return ' ';
+ case 0xC2: return ' ';
+ case 0xC3: return ' ';
+ case 0xC4: return ' ';
+ case 0xC5: return ' ';
+ case 0xC6: return ' ';
+ case 0xC7: return ' ';
+ case 0xC8: return ' ';
+ case 0xC9: return ' ';
+ case 0xCA: return ' ';
+ case 0xCB: return 'A';
+ case 0xCC: return 'A';
+ case 0xCD: return 'O';
+ case 0xCE: return ' ';
+ case 0xCF: return ' ';
+ case 0xD0: return '-';
+ case 0xD1: return '-';
+ case 0xD2: return 0x22;
+ case 0xD3: return 0x22;
+ case 0xD4: return 0x27;
+ case 0xD5: return 0x27;
+ case 0xD6: return '-'; // use dash instead of slash
+ case 0xD7: return ' ';
+ case 0xD8: return 'y';
+ case 0xD9: return 'Y';
+ case 0xDA: return '-'; // use dash instead of slash
+ case 0xDB: return ' ';
+ case 0xDC: return '<';
+ case 0xDD: return '>';
+ case 0xDE: return ' ';
+ case 0xDF: return ' ';
+ case 0xE0: return ' ';
+ case 0xE1: return ' ';
+ case 0xE2: return ',';
+ case 0xE3: return ',';
+ case 0xE4: return ' ';
+ case 0xE5: return 'A';
+ case 0xE6: return 'E';
+ case 0xE7: return 'A';
+ case 0xE8: return 'E';
+ case 0xE9: return 'E';
+ case 0xEA: return 'I';
+ case 0xEB: return 'I';
+ case 0xEC: return 'I';
+ case 0xED: return 'I';
+ case 0xEE: return 'O';
+ case 0xEF: return 'O';
+ case 0xF0: return ' ';
+ case 0xF1: return 'O';
+ case 0xF2: return 'U';
+ case 0xF3: return 'U';
+ case 0xF4: return 'U';
+ case 0xF5: return '|';
+ case 0xF6: return ' ';
+ case 0xF7: return ' ';
+ case 0xF8: return ' ';
+ case 0xF9: return ' ';
+ case 0xFA: return '.';
+ case 0xFB: return ' ';
+ case 0xFC: return ' ';
+ case 0xFD: return 0x22;
+ case 0xFE: return ' ';
+ case 0xFF: return ' ';
+ }
+ return c;
+}
+
+// String should match ndof for manufacturer based search to work
+static void sanitizeString( char* inCStr )
+{
+ char* charIt = inCStr;
+ while ( *charIt )
+ {
+ *charIt = mapChar( *charIt );
+ charIt++;
+ }
+}
+
+struct HidDevice
+{
+ long mAxis;
+ long mLocalID;
+ char mProduct[256];
+ char mManufacturer[256];
+ long mUsage;
+ long mUsagePage;
+};
+
+static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_dic, HidDevice* devicep )
+{
+ CFMutableDictionaryRef io_properties = nil;
+ io_registry_entry_t entry1;
+ io_registry_entry_t entry2;
+ kern_return_t rc;
+
+ // Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
+ // get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
+ // try to get parent1
+ rc = IORegistryEntryGetParentEntry( io_obj_p, kIOServicePlane, &entry1 );
+ if ( KERN_SUCCESS == rc )
+ {
+ rc = IORegistryEntryGetParentEntry( entry1, kIOServicePlane, &entry2 );
+
+ IOObjectRelease( entry1 );
+
+ if ( KERN_SUCCESS == rc )
+ {
+ rc = IORegistryEntryCreateCFProperties( entry2, &io_properties, kCFAllocatorDefault, kNilOptions );
+ // either way, release parent2
+ IOObjectRelease( entry2 );
+ }
+ }
+ if ( KERN_SUCCESS == rc )
+ {
+ // IORegistryEntryCreateCFProperties() succeeded
+ if ( io_properties != nil )
+ {
+ CFTypeRef dict_element = 0;
+ // get device info
+ // try hid dictionary first, if fail then go to usb dictionary
+
+
+ dict_element = CFDictionaryGetValue( device_dic, CFSTR(kIOHIDProductKey) );
+ if ( !dict_element )
+ {
+ dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Product Name" ) );
+ }
+ if ( dict_element )
+ {
+ bool res = CFStringGetCString((CFStringRef)dict_element, devicep->mProduct, 256, kCFStringEncodingUTF8);
+ sanitizeString(devicep->mProduct);
+ if ( !res )
+ {
+ LL_WARNS("Joystick") << "Failed to populate mProduct" << LL_ENDL;
+ }
+ }
+
+ dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDManufacturerKey ) );
+ if ( !dict_element )
+ {
+ dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Vendor Name" ) );
+ }
+ if ( dict_element )
+ {
+ bool res = CFStringGetCString( (CFStringRef)dict_element, devicep->mManufacturer, 256, kCFStringEncodingUTF8 );
+ sanitizeString(devicep->mManufacturer);
+ if ( !res )
+ {
+ LL_WARNS("Joystick") << "Failed to populate mManufacturer" << LL_ENDL;
+ }
+ }
+
+ dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDLocationIDKey ) );
+ if ( !dict_element )
+ {
+ dict_element = CFDictionaryGetValue( io_properties, CFSTR( "locationID" ) );
+ }
+ if ( dict_element )
+ {
+ bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mLocalID );
+ if ( !res )
+ {
+ LL_WARNS("Joystick") << "Failed to populate mLocalID" << LL_ENDL;
+ }
+ }
+
+ dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsagePageKey ) );
+ if ( dict_element )
+ {
+ bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsagePage );
+ if ( !res )
+ {
+ LL_WARNS("Joystick") << "Failed to populate mUsagePage" << LL_ENDL;
+ }
+ dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsageKey ) );
+ if ( dict_element )
+ {
+ if ( !CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsage ) )
+ {
+ LL_WARNS("Joystick") << "Failed to populate mUsage" << LL_ENDL;
+ }
+ }
+ }
+
+ //Add axis, because ndof lib checks sutability by axises as well as other elements
+ devicep->mAxis = 0;
+ CFTypeRef hid_elements = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDElementKey ) );
+ if ( hid_elements && CFGetTypeID( hid_elements ) == CFArrayGetTypeID( ) )
+ {
+ long count = CFArrayGetCount( (CFArrayRef) hid_elements );
+ for (int i = 0; i < count; ++i)
+ {
+ CFTypeRef element = CFArrayGetValueAtIndex((CFArrayRef) hid_elements, i);
+ if (element && CFGetTypeID( element ) == CFDictionaryGetTypeID( ))
+ {
+ long type = 0, usage_page = 0, usage = 0;
+
+ CFTypeRef ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementTypeKey ) );
+ if ( ref_value )
+ {
+ CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &type );
+ }
+
+ ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsagePageKey ) );
+ if ( ref_value )
+ {
+ CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage_page );
+ }
+
+ ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsageKey ) );
+ if ( ref_value )
+ {
+ CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage );
+ }
+ if ( type != 0
+ && type != kIOHIDElementTypeCollection
+ && usage_page == kHIDPage_GenericDesktop)
+ {
+ switch( usage )
+ {
+ case kHIDUsage_GD_X:
+ case kHIDUsage_GD_Y:
+ case kHIDUsage_GD_Z:
+ case kHIDUsage_GD_Rx:
+ case kHIDUsage_GD_Ry:
+ case kHIDUsage_GD_Rz:
+ devicep->mAxis++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ CFRelease(io_properties);
+ }
+ else
+ {
+ LL_WARNS("Joystick") << "Failed to populate fields" << LL_ENDL;
+ }
+ }
+}
+
+HidDevice populate_device( io_object_t io_obj )
+{
+ void* interfacep = nullptr;
+ HidDevice device;
+ memset( &device, 0, sizeof( HidDevice ) );
+ CFMutableDictionaryRef device_dic = 0;
+ kern_return_t result = IORegistryEntryCreateCFProperties( io_obj, &device_dic, kCFAllocatorDefault, kNilOptions );
+
+ if ( KERN_SUCCESS == result
+ && device_dic )
+ {
+ IOReturn io_result = kIOReturnSuccess;
+ HRESULT query_result = S_OK;
+ SInt32 the_score = 0;
+ IOCFPlugInInterface **the_interface = NULL;
+
+
+ io_result = IOCreatePlugInInterfaceForService( io_obj, kIOHIDDeviceUserClientTypeID,
+ kIOCFPlugInInterfaceID, &the_interface, &the_score );
+ if ( io_result == kIOReturnSuccess )
+ {
+ query_result = ( *the_interface )->QueryInterface( the_interface, CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ), ( LPVOID * ) & ( interfacep ) );
+ if ( query_result != S_OK )
+ {
+ LL_WARNS("Joystick") << "QueryInterface failed" << LL_ENDL;
+ }
+ IODestroyPlugInInterface( the_interface );
+ }
+ else
+ {
+ LL_WARNS("Joystick") << "IOCreatePlugInInterfaceForService failed" << LL_ENDL;
+ }
+
+ if ( interfacep )
+ {
+ result = ( *( IOHIDDeviceInterface** )interfacep )->open( interfacep, 0 );
+
+ if ( result != kIOReturnSuccess)
+ {
+ LL_WARNS("Joystick") << "open failed" << LL_ENDL;
+ }
+ }
+ // extract needed fields
+ populate_device_info( io_obj, device_dic, &device );
+
+ // Release interface
+ if ( interfacep )
+ {
+ ( *( IOHIDDeviceInterface** ) interfacep )->close( interfacep );
+
+ ( *( IOHIDDeviceInterface** ) interfacep )->Release( interfacep );
+
+ interfacep = NULL;
+ }
+
+ CFRelease( device_dic );
+ }
+ else
+ {
+ LL_WARNS("Joystick") << "populate_device failed" << LL_ENDL;
+ }
+
+ return device;
+}
+
+static void get_devices(std::list &list_of_devices,
+ io_iterator_t inIODeviceIterator)
+{
+ IOReturn result = kIOReturnSuccess; // assume success( optimist! )
+ io_object_t io_obj = 0;
+
+ while ( 0 != (io_obj = IOIteratorNext( inIODeviceIterator ) ) )
+ {
+ HidDevice device = populate_device( io_obj );
+
+ // Should match ndof
+ if (device.mAxis >= 3
+ || (device.mUsagePage == kHIDPage_GenericDesktop
+ && (device.mUsage == kHIDUsage_GD_MultiAxisController
+ || device.mUsage == kHIDUsage_GD_GamePad
+ || device.mUsage == kHIDUsage_GD_Joystick))
+ || (device.mUsagePage == kHIDPage_Game
+ && device.mUsage == kHIDUsage_Game_3DGameController)
+ || strstr(device.mManufacturer, "3Dconnexion"))
+ {
+ list_of_devices.push_back(device);
+ }
+ else
+ {
+ LL_DEBUGS("Joystick");
+ list_of_devices.push_back(device);
+ LL_CONT << "Device axes: " << (S32)device.mAxis
+ << " Device HIDUsepage: " << (S32)device.mUsagePage
+ << " Device HIDUsage: " << (S32)device.mUsage;
+ LL_ENDL;
+ }
+
+
+ // release the device object, it is no longer needed
+ result = IOObjectRelease( io_obj );
+ if ( KERN_SUCCESS != result )
+ {
+ LL_WARNS("Joystick") << "IOObjectRelease failed" << LL_ENDL;
+ }
+ }
+}
+
+bool LLWindowMacOSX::getInputDevices(U32 device_type_filter,
+ std::function osx_callback,
+ void* win_callback,
+ void* userdata)
+{
+ bool return_value = false;
+ CFMutableDictionaryRef device_dict_ref;
+ IOReturn result = kIOReturnSuccess; // assume success( optimist! )
+
+ // Set up matching dictionary to search the I/O Registry for HID devices we are interested in. Dictionary reference is NULL if error.
+
+ // A dictionary to match devices to?
+ device_dict_ref = IOServiceMatching( kIOHIDDeviceKey );
+
+ // BUG FIX! one reference is consumed by IOServiceGetMatchingServices
+ CFRetain( device_dict_ref );
+ io_iterator_t io_iter = 0;
+
+ // create an IO object iterator
+ result = IOServiceGetMatchingServices( kIOMasterPortDefault, device_dict_ref, &io_iter );
+ if ( kIOReturnSuccess != result )
+ {
+ LL_WARNS("Joystick") << "IOServiceGetMatchingServices failed" << LL_ENDL;
+ }
+
+ if ( io_iter )
+ {
+ // add all existing devices
+ std::list device_list;
+
+ get_devices(device_list, io_iter);
+
+ std::list::iterator iter;
+
+ for (iter = device_list.begin(); iter != device_list.end(); ++iter)
+ {
+ std::string label(iter->mProduct);
+ LLSD data;
+ data["manufacturer"] = std::string(iter->mManufacturer);
+ data["product"] = label;
+
+ if (osx_callback(label, data, userdata))
+ {
+ break; //found device
+ }
+ }
+ return_value = true;
+ }
+
+ CFRelease( device_dict_ref );
+ return return_value;
+}
+
LLSD LLWindowMacOSX::getNativeKeyData()
{
LLSD result = LLSD::emptyMap();
diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h
index 196a284ac3..5e09e58a99 100644
--- a/indra/llwindow/llwindowmacosx.h
+++ b/indra/llwindow/llwindowmacosx.h
@@ -116,6 +116,11 @@ public:
void spawnWebBrowser(const std::string& escaped_url, bool async) override;
F32 getSystemUISize() override;
+ bool getInputDevices(U32 device_type_filter,
+ std::function osx_callback,
+ void* win_callback,
+ void* userdata) override;
+
static std::vector getDisplaysResolutionList();
static std::vector getDynamicFallbackFontList();
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 8670298f46..d6b93b93d9 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1642,7 +1642,9 @@ const S32 max_format = (S32)num_formats - 1;
}
else
{
- LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL;
+ LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBVideoDrvErr"));
+ // mWindowHandle is 0, going to crash either way
+ LL_ERRS("Window") << "No wgl_ARB_pixel_format extension!" << LL_ENDL;
}
// Verify what pixel format we actually received.
@@ -1895,12 +1897,16 @@ void LLWindowWin32::destroySharedContext(void* contextPtr)
void LLWindowWin32::toggleVSync(bool enable_vsync)
{
- if (!enable_vsync && wglSwapIntervalEXT)
+ if (wglSwapIntervalEXT == nullptr)
+ {
+ LL_INFOS("Window") << "VSync: wglSwapIntervalEXT not initialized" << LL_ENDL;
+ }
+ else if (!enable_vsync)
{
LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL;
wglSwapIntervalEXT(0);
}
- else if (wglSwapIntervalEXT)
+ else
{
LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL;
wglSwapIntervalEXT(1);
@@ -4464,7 +4470,10 @@ void* LLWindowWin32::getDirectInput8()
return &gDirectInput8;
}
-bool LLWindowWin32::getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata)
+bool LLWindowWin32::getInputDevices(U32 device_type_filter,
+ std::function osx_callback,
+ void * di8_devices_callback,
+ void* userdata)
{
if (gDirectInput8 != NULL)
{
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 6598215f97..33fa67ba50 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -131,7 +131,10 @@ public:
static void setDPIAwareness();
/*virtual*/ void* getDirectInput8();
- /*virtual*/ bool getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata);
+ /*virtual*/ bool getInputDevices(U32 device_type_filter,
+ std::function osx_callback,
+ void* win_callback,
+ void* userdata);
U32 getRawWParam() { return mRawWParam; }
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp
index 264bf0c5b4..5b6d197e52 100644
--- a/indra/llxml/llcontrol.cpp
+++ b/indra/llxml/llcontrol.cpp
@@ -1497,8 +1497,6 @@ DECL_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255));
LLSD test_llsd = LLSD()["testing1"] = LLSD()["testing2"];
DECL_LLCC(LLSD, test_llsd);
-static LLCachedControl test_BrowserHomePage("BrowserHomePage", "hahahahahha", "Not the real comment");
-
void test_cached_control()
{
#define TEST_LLCC(T, V) if((T)mySetting_##T != V) LL_ERRS() << "Fail "#T << LL_ENDL
@@ -1515,8 +1513,6 @@ void test_cached_control()
TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f));
TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255));
//There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd);
-
- if((std::string)test_BrowserHomePage != "http://www.secondlife.com") LL_ERRS() << "Fail BrowserHomePage" << LL_ENDL;
}
#endif // TEST_CACHED_CONTROL
diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp
index cf2bc4476e..2298dc22e7 100644
--- a/indra/llxml/llxmlnode.cpp
+++ b/indra/llxml/llxmlnode.cpp
@@ -837,7 +837,7 @@ bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root,
if (!LLXMLNode::parseFile(filename, root, NULL))
{
- LL_WARNS() << "Problem reading UI description file: " << filename << LL_ENDL;
+ LL_WARNS() << "Problem reading UI description file: " << filename << " " << errno << LL_ENDL;
return false;
}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 738d8e540d..c2869eedfd 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -18,7 +18,6 @@ include(DragDrop)
include(EXPAT)
include(FMODSTUDIO)
include(Hunspell)
-include(ICU4C)
include(JPEGEncoderBasic)
include(JsonCpp)
include(LLAppearance)
@@ -1616,6 +1615,8 @@ set(viewer_APPSETTINGS_FILES
app_settings/autoreplace.xml
app_settings/cmd_line.xml
app_settings/commands.xml
+ app_settings/emoji_groups.xml
+ app_settings/foldertypes.xml
app_settings/grass.xml
app_settings/ignorable_dialogs.xml
app_settings/key_bindings.xml
@@ -1931,7 +1932,6 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${LLPHYSICSEXTENSIONS_LIBRARIES}
ll::bugsplat
ll::tracy
- ll::icu4c
)
if( TARGET ll::intel_memops )
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 2380dcfd47..2fe040f424 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-7.1.7
+7.1.8
diff --git a/indra/newview/app_settings/camera/Front.xml b/indra/newview/app_settings/camera/Front.xml
index 39f44e11a8..f96d3bc779 100644
--- a/indra/newview/app_settings/camera/Front.xml
+++ b/indra/newview/app_settings/camera/Front.xml
@@ -1,16 +1,5 @@
- AppearanceCameraMovement
-
- Comment
- When entering appearance editing mode, camera zooms in on currently selected portion of avatar
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
AvatarSitRotation
Comment
@@ -90,17 +79,6 @@
Value
0.90322577953338623
- EditCameraMovement
-
- Comment
- When entering build mode, camera moves up above avatar
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
FocusOffsetRearView
Comment
diff --git a/indra/newview/app_settings/camera/Rear.xml b/indra/newview/app_settings/camera/Rear.xml
index 8dc36353ce..7eda566e48 100644
--- a/indra/newview/app_settings/camera/Rear.xml
+++ b/indra/newview/app_settings/camera/Rear.xml
@@ -1,16 +1,5 @@
- AppearanceCameraMovement
-
- Comment
- When entering appearance editing mode, camera zooms in on currently selected portion of avatar
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
AvatarSitRotation
Comment
@@ -90,17 +79,6 @@
Value
0.90322577953338623
- EditCameraMovement
-
- Comment
- When entering build mode, camera moves up above avatar
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
FocusOffsetRearView
Comment
diff --git a/indra/newview/app_settings/camera/Side.xml b/indra/newview/app_settings/camera/Side.xml
index 089ab93a8f..77f73f1df1 100644
--- a/indra/newview/app_settings/camera/Side.xml
+++ b/indra/newview/app_settings/camera/Side.xml
@@ -1,16 +1,5 @@
- AppearanceCameraMovement
-
- Comment
- When entering appearance editing mode, camera zooms in on currently selected portion of avatar
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
AvatarSitRotation
Comment
@@ -90,17 +79,6 @@
Value
0.90322577953338623
- EditCameraMovement
-
- Comment
- When entering build mode, camera moves up above avatar
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
FocusOffsetRearView
Comment
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index e1eeefa755..7513c8e3d3 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -137,17 +137,6 @@
Value
1
- AdvanceOutfitSnapshot
-
- Comment
- Display advanced parameter settings in outfit snaphot interface
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
AgentPause
Comment
@@ -214,17 +203,6 @@
Value
1
- AnimationDebug
-
- Comment
- Show active animations in a bubble above avatars head
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
AppearanceCameraMovement
Comment
@@ -269,17 +247,6 @@
Value
0
- AskedAboutCrashReports
-
- Comment
- Turns off dialog asking if you want to enable crash reporting
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
AuctionShowFence
Comment
@@ -302,17 +269,6 @@
Value
0.5
- AudioLevelDoppler
-
- Comment
- Scale of doppler effect on moving audio sources (1.0 = normal, <1.0 = diminished doppler effect, >1.0 = enhanced doppler effect)
- Persist
- 1
- Type
- F32
- Value
- 1.0
-
AudioLevelMaster
Comment
@@ -357,28 +313,6 @@
Value
0.3
- AudioLevelRolloff
-
- Comment
- Controls the distance-based dropoff of audio volume (fraction or multiple of default audio rolloff)
- Persist
- 1
- Type
- F32
- Value
- 1.0
-
- AudioLevelUnderwaterRolloff
-
- Comment
- Controls the distance-based dropoff of audio volume underwater(fraction or multiple of default audio rolloff)
- Persist
- 1
- Type
- F32
- Value
- 5.0
-
AudioLevelSFX
Comment
@@ -411,17 +345,6 @@
F32
Value
0.5
-
- AudioLevelWind
-
- Comment
- Audio level of wind noise when standing still
- Persist
- 1
- Type
- F32
- Value
- 0.5
AudioStreamingMedia
@@ -456,7 +379,7 @@
Value
0
- AutoAcceptNewInventory
+ AutoAcceptNewInventory
Comment
Automatically accept new notecards/textures/landmarks
@@ -478,17 +401,6 @@
Value
1
- AutoLoadWebProfiles
-
- Comment
- Automatically load ALL profile webpages without asking first.
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
AutoLogin
Comment
@@ -687,17 +599,6 @@
Value
1.0
- AvatarBacklight
-
- Comment
- Add rim lighting to avatar rendering to approximate shininess of skin
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
AvatarFeathering
Comment
@@ -709,32 +610,6 @@
Value
16.0
- AvatarPickerSortOrder
-
- Comment
- Specifies sort key for textures in avatar picker (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)
- Persist
- 1
- Type
- U32
- Value
- 2
-
- AvatarPosFinalOffset
-
- Comment
- After-everything-else fixup for avatar position.
- Persist
- 1
- Type
- Vector3
- Value
-
- 0.0
- 0.0
- 0.0
-
-
AvatarPickerURL
Comment
@@ -746,50 +621,6 @@
Value
http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/avatars.html
- AvatarRotateThresholdSlow
-
- Comment
- Angle between avatar facing and camera facing at which avatar turns to face same direction as camera, when moving slowly (degrees)
- Persist
- 1
- Type
- F32
- Value
- 60
-
- AvatarRotateThresholdFast
-
- Comment
- Angle between avatar facing and camera facing at which avatar turns to face same direction as camera, when moving fast (degrees)
- Persist
- 1
- Type
- F32
- Value
- 2
-
- AvatarBakedTextureUploadTimeout
-
- Comment
- Specifes the maximum time in seconds to wait before sending your baked textures for avatar appearance. Set to 0 to disable and wait until all baked textures are at highest resolution.
- Persist
- 1
- Type
- U32
- Value
- 60
-
- AvatarBakedLocalTextureUpdateTimeout
-
- Comment
- Specifes the maximum time in seconds to wait before updating your appearance during appearance mode.
- Persist
- 1
- Type
- U32
- Value
- 10
-
AvatarPhysics
Comment
@@ -823,28 +654,6 @@
Value
40
- BottomPanelNew
-
- Comment
- Enable the new bottom panel
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
- BrowserHomePage
-
- Comment
- [NOT USED]
- Persist
- 1
- Type
- String
- Value
- http://www.secondlife.com
-
BrowserIgnoreSSLCertErrors
Comment
@@ -878,17 +687,6 @@
Value
0
- BlockSomeAvatarAppearanceVisualParams
-
- Comment
- Drop around 50% of VisualParam occurances in appearance messages (for simulating Ruth)
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
BrowserProxyAddress
Comment
@@ -911,17 +709,6 @@
Value
0
- BrowserProxyExclusions
-
- Comment
- [NOT USED]
- Persist
- 1
- Type
- String
- Value
-
-
BrowserProxyPort
Comment
@@ -933,17 +720,6 @@
Value
3128
- BrowserProxySocks45
-
- Comment
- [NOT USED]
- Persist
- 1
- Type
- S32
- Value
- 5
-
Socks5ProxyEnabled
Comment
@@ -1329,39 +1105,6 @@
Value
1
- ButtonHPad
-
- Comment
- Default horizontal spacing between buttons (pixels)
- Persist
- 1
- Type
- S32
- Value
- 4
-
- ButtonHeight
-
- Comment
- Default height for normal buttons (pixels)
- Persist
- 1
- Type
- S32
- Value
- 23
-
- ButtonHeightSmall
-
- Comment
- Default height for small buttons (pixels)
- Persist
- 1
- Type
- S32
- Value
- 23
-
EnableDiskCacheDebugInfo
Comment
@@ -1417,17 +1160,6 @@
Value
- CacheNumberOfRegionsForObjects
-
- Comment
- Controls number of regions to be cached for objects.
- Persist
- 1
- Type
- U32
- Value
- 128
-
CacheSize
Comment
@@ -1513,51 +1245,6 @@
0.75
- CameraOffsetFrontView
-
- Comment
- Initial camera offset from avatar in Front View
- Persist
- 1
- Type
- Vector3
- Value
-
- 2.2
- 0.0
- 0.0
-
-
- CameraOffsetGroupView
-
- Comment
- Initial camera offset from avatar in Group View
- Persist
- 1
- Type
- Vector3
- Value
-
- -1.0
- 0.7
- 0.5
-
-
- CameraOffsetCustomPreset
-
- Comment
- Initial camera offset from avatar for the custom camera preset
- Persist
- 1
- Type
- Vector3
- Value
-
- -3.0
- 0.0
- 0.75
-
-
CameraOffsetScale
Comment
@@ -1712,17 +1399,6 @@
Value
1
- ChatBarStealsFocus
-
- Comment
- Whenever keyboard focus is removed from the UI, and the chat bar is visible, the chat bar takes focus
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
LetterKeysFocusChatBar
Comment
@@ -1767,17 +1443,6 @@
Value
1
- ChatHistoryTornOff
-
- Comment
- Show chat history window separately from Communicate window.
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
ChatLoadGroupMaxMembers
Comment
@@ -1789,17 +1454,6 @@
Value
100
- ChatLoadGroupTimeout
-
- Comment
- Time we give the server to send group participants before we hit the server for group info (seconds)
- Persist
- 1
- Type
- F32
- Value
- 10.0
-
ChatOnlineNotification
Comment
@@ -1811,28 +1465,6 @@
Value
1
- ChatPersistTime
-
- Comment
- Time for which chat stays visible in console (seconds)
- Persist
- 1
- Type
- F32
- Value
- 20.0
-
- ChatShowTimestamps
-
- Comment
- Show timestamps in chat
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
CheesyBeacon
Comment
@@ -1855,50 +1487,6 @@
Value
- ContextConeInAlpha
-
- Comment
- Cone In Alpha
- Persist
- 0
- Type
- F32
- Value
- 0.0
-
- ContextConeOutAlpha
-
- Comment
- Cone Out Alpha
- Persist
- 0
- Type
- F32
- Value
- 1.0
-
- ContextConeFadeTime
-
- Comment
- Cone Fade Time
- Persist
- 0
- Type
- F32
- Value
- .08
-
- ConversationHistoryPageSize
-
- Comment
- Chat history of conversation opened from call log is displayed by pages. So this is number of entries per page.
- Persist
- 1
- Type
- S32
- Value
- 100
-
ConversationSortOrder
Comment
@@ -2077,17 +1665,6 @@
Value
40
- ContactsTornOff
-
- Comment
- Show contacts window separately from Communicate window.
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
CookiesEnabled
Comment
@@ -2132,17 +1709,6 @@
Value
1
- ChatBarCustomWidth
-
- Comment
- Stores customized width of chat bar.
- Persist
- 1
- Type
- S32
- Value
- 0
-
CoroutineStackSize
Comment
@@ -2209,17 +1775,6 @@
Value
0
- CurlMaximumNumberOfHandles
-
- Comment
- Maximum number of handles curl can use (requires restart)
- Persist
- 1
- Type
- S32
- Value
- 256
-
CurlRequestTimeOut
Comment
@@ -2230,17 +1785,6 @@
F32
Value
120.0
-
- CurlUseMultipleThreads
-
- Comment
- Use background threads for executing curl_multi_perform (requires restart)
- Persist
- 1
- Type
- Boolean
- Value
- 1
Cursor3D
@@ -2264,17 +1808,6 @@
Value
- CustomServer
-
- Comment
- Specifies IP address or hostname of grid to which you connect
- Persist
- 1
- Type
- String
- Value
-
-
DebugAnimatedObjects
Comment
@@ -2297,17 +1830,6 @@
Value
0
- AnimatedObjectsIgnoreLimits
-
- Comment
- Ignore server-enforced limits on animated objects. This is only useful for server testing.
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
AnimatedObjectsAllowLeftClick
Comment
@@ -2319,17 +1841,6 @@
Value
0
- AnimatedObjectsGlobalScale
-
- Comment
- Temporary testing: allow an extra scale factor to be forced on animated objects.
- Persist
- 1
- Type
- F32
- Value
- 1.00
-
AnimatedObjectsMaxLegalOffset
Comment
@@ -2352,17 +1863,6 @@
Value
64.0
- AvatarBoundingBoxComplexity
-
- Comment
- How many aspects to consider for avatar bounding box
- Persist
- 1
- Type
- S32
- Value
- 3
-
DebugAvatarAppearanceMessage
Comment
@@ -2473,17 +1973,6 @@
Value
1
- DebugInventoryFilters
-
- Comment
- Turn on debugging display for inventory filtering
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
DebugPermissions
Comment
@@ -2550,18 +2039,6 @@
Value
0
- DebugShowPrivateMem
-
-
- Comment
- (Deprecated) Show Private Mem Info
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
DebugShowRenderInfo
Comment
@@ -2628,435 +2105,6 @@
Value
0
- DebugSlshareLogTag
-
- Comment
- Request slshare-service debug logging
- Persist
- 0
- Type
- String
- Value
-
-
- DebugStatModeFPS
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeBandwidth
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModePacketLoss
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatMode
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeKTrisDrawnFr
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeKTrisDrawnSec
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeTotalObjs
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeNewObjs
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeTextureCount
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeRawCount
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeGLMem
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeFormattedMem
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeRawMem
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeBoundMem
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModePacketsIn
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModePacketsOut
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeObjects
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeTexture
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeAsset
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeLayers
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeActualIn
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeActualOut
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeTimeDialation
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeSimFPS
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModePhysicsFPS
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModePinnedObjects
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeLowLODObjects
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeMemoryAllocated
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeAgentUpdatesSec
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeMainAgents
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeChildAgents
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeSimObjects
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeSimActiveObjects
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeSimActiveScripts
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeSimScriptEvents
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeSimInPPS
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeSimOutPPS
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
- DebugStatModeSimPendingDownloads
-
- Comment
- Mode of stat in Statistics floater
- Persist
- 1
- Type
- S32
- Value
- -1
-
SimPendingUploads
Comment
@@ -3277,17 +2325,6 @@
Value
Male Shape & Outfit
- DefaultUploadCost
-
- Comment
- Default sound/image/file upload cost(in case economy data is not available).
- Persist
- 1
- Type
- U32
- Value
- 10
-
DestinationGuideURL
Comment
@@ -3387,94 +2424,6 @@
Value
1
- EnableIMChatPopups
-
- Comment
- Enable Incoming IM Chat Popups
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- DisplayAvatarAgentTarget
-
- Comment
- Show avatar positioning locators (animation debug)
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
- DisplayChat
-
- Comment
- Display Latest Chat message on LCD
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- DisplayDebug
-
- Comment
- Display Network Information on LCD
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- DisplayDebugConsole
-
- Comment
- Display Console Debug Information on LCD
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- DisplayIM
-
- Comment
- Display Latest IM message on LCD
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- DisplayLinden
-
- Comment
- Display Account Information on LCD
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- DisplayRegion
-
- Comment
- Display Location information on LCD
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
DisplayTimecode
Comment
@@ -3508,28 +2457,6 @@
Value
1
- ClickActionBuyEnabled
-
- Comment
- Enable click to buy actions in tool pie menu
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- ClickActionPayEnabled
-
- Comment
- Enable click to pay actions in tool pie menu
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
DoubleClickAutoPilot
Comment
@@ -3563,72 +2490,6 @@
Value
1
- DragAndDropToolTipDelay
-
- Comment
- Seconds before displaying tooltip when performing drag and drop operation
- Persist
- 1
- Type
- F32
- Value
- 0.10000000149
-
- DragAndDropDistanceThreshold
-
- Comment
- Number of pixels that mouse should move before triggering drag and drop mode
- Persist
- 1
- Type
- S32
- Value
- 3
-
- DropShadowButton
-
- Comment
- Drop shadow width for buttons (pixels)
- Persist
- 1
- Type
- S32
- Value
- 2
-
- DropShadowFloater
-
- Comment
- Drop shadow width for floaters (pixels)
- Persist
- 1
- Type
- S32
- Value
- 5
-
- DropShadowSlider
-
- Comment
- Drop shadow width for sliders (pixels)
- Persist
- 1
- Type
- S32
- Value
- 3
-
- DropShadowTooltip
-
- Comment
- Drop shadow width for tooltips (pixels)
- Persist
- 1
- Type
- S32
- Value
- 4
-
DynamicCameraStrength
Comment
@@ -3662,17 +2523,6 @@
Value
0
- IncludeEnhancedSkeleton
-
- Comment
- Include extended skeleton joints when rendering skinned meshes.
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
MinObjectsForUnlinkConfirm
Comment
@@ -3772,39 +2622,6 @@
Value
1
- EnergyFromTop
-
- Comment
-
- Persist
- 0
- Type
- S32
- Value
- 20
-
- EnergyHeight
-
- Comment
-
- Persist
- 0
- Type
- S32
- Value
- 40
-
- EnergyWidth
-
- Comment
-
- Persist
- 0
- Type
- S32
- Value
- 175
-
EventURL
Comment
@@ -3816,61 +2633,6 @@
Value
http://events.[GRID]/viewer/embed/event/[EVENT_ID]
- FastCacheFetchEnabled
-
- Comment
- Enable texture fast cache fetching if set
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- FeatureManagerHTTPTable
-
- Comment
- Deprecated
- Persist
- 0
- Type
- String
- Value
-
-
- FPSLogFrequency
-
- Comment
- Seconds between display of FPS in log (0 for never)
- Persist
- 1
- Type
- F32
- Value
- 10.0
-
- FilterItemsMaxTimePerFrameVisible
-
- Comment
- Max time devoted to items filtering per frame for visible inventory listings (in milliseconds)
- Persist
- 1
- Type
- S32
- Value
- 10
-
- FilterItemsMaxTimePerFrameUnvisible
-
- Comment
- Max time devoted to items filtering per frame for non visible inventory listings (in milliseconds)
- Persist
- 1
- Type
- S32
- Value
- 1
-
MainWorkTime
Comment
@@ -3882,72 +2644,6 @@
Value
1.0
- QueueInventoryFetchTimeout
-
- Comment
- Max time llcompilequeue will wait for inventory fetch to complete (in seconds)
- Persist
- 1
- Type
- F32
- Value
- 300.0
-
- FindLandArea
-
- Comment
- Enables filtering of land search results by area
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
- FindLandPrice
-
- Comment
- Enables filtering of land search results by price
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- FindLandType
-
- Comment
- Controls which type of land you are searching for in Find Land interface ("All", "Auction", "For Sale")
- Persist
- 1
- Type
- String
- Value
- All
-
- FindPeopleOnline
-
- Comment
- Limits people search to only users who are logged on
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- FindPlacesPictures
-
- Comment
- Display only results of find places that have pictures
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
FirstName
Comment
@@ -4339,17 +3035,6 @@
Value
16.0
- FlycamZoomDirect
-
- Comment
- Map flycam zoom axis directly to camera zoom.
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
FlyingAtExit
Comment
@@ -4376,51 +3061,6 @@
1.0
- FocusOffsetFrontView
-
- Comment
- Initial focus point offset relative to avatar for the camera preset Front View
- Persist
- 1
- Type
- Vector3D
- Value
-
- 0.0
- 0.0
- 0.0
-
-
- FocusOffsetGroupView
-
- Comment
- Initial focus point offset relative to avatar for the camera preset Group View
- Persist
- 1
- Type
- Vector3D
- Value
-
- 1.5
- 0.7
- 1.0
-
-
- FocusOffsetCustomPreset
-
- Comment
- Initial focus point offset relative to avatar for the custom camera preset (x-axis is forward)
- Persist
- 1
- Type
- Vector3D
- Value
-
- 1.0
- 0.0
- 1.0
-
-
AvatarSitRotation
Comment
@@ -4463,17 +3103,6 @@
Value
0.75
- FolderLoadingMessageWaitTime
-
- Comment
- Seconds to wait before showing the LOADING... text in folder views
- Persist
- 1
- Type
- F32
- Value
- 0.5
-
FontScreenDPI
Comment
@@ -4529,17 +3158,6 @@
Value
0
- ForceMandatoryUpdate
-
- Comment
- For QA: On next startup, forces the auto-updater to run
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
FreezeTime
Comment
@@ -4661,28 +3279,6 @@
Value
32
- GroupNotifyBoxHeight
-
- Comment
- Height of group notice messages
- Persist
- 1
- Type
- S32
- Value
- 260
-
- GroupNotifyBoxWidth
-
- Comment
- Width of group notice messages
- Persist
- 1
- Type
- S32
- Value
- 305
-
HelpURLFormat
Comment
@@ -4771,17 +3367,6 @@
Value
- HtmlHelpLastPage
-
- Comment
- Last URL visited via help system
- Persist
- 1
- Type
- String
- Value
-
-
HttpPipelining
Comment
@@ -4804,17 +3389,6 @@
Value
0
- IMShowTimestamps
-
- Comment
- Show timestamps in IM
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
IMShowControlPanel
Comment
@@ -4825,17 +3399,6 @@
Boolean
Value
1
-
- IMShowContentPanel
-
- Comment
- Show Toolbar and Body Panels
- Persist
- 1
- Type
- Boolean
- Value
- 1
IgnoreFOVZoomForLODs
@@ -4902,28 +3465,6 @@
F32
Value
0.0
-
- InspectorFadeTime
-
- Comment
- Fade out timing for inspectors
- Persist
- 1
- Type
- F32
- Value
- 0.5
-
- InspectorShowTime
-
- Comment
- Stay timing for inspectors
- Persist
- 1
- Type
- F32
- Value
- 3.0
InstallLanguage
@@ -4991,17 +3532,6 @@
Value
1
- InventoryOutboxDisplayBoth
-
- Comment
- (Deprecated) Show the legacy Merchant Outbox UI as well as the Marketplace Listings UI
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
InventoryOutboxLogging
Comment
@@ -5251,7 +3781,7 @@
Persist
1
Type
- String
+ LLSD
Value
@@ -5332,17 +3862,6 @@
Value
2.0
- LCDDestination
-
- Comment
- Which LCD to use
- Persist
- 1
- Type
- S32
- Value
- 0
-
LeapCommand
Comment
@@ -5564,105 +4083,6 @@
0.0.0
- LastSnapshotToProfileHeight
-
- Comment
- The height of the last profile snapshot, in px
- Persist
- 1
- Type
- S32
- Value
- 768
-
- LastSnapshotToEmailHeight
-
- Comment
- The height of the last email snapshot, in px
- Persist
- 1
- Type
- S32
- Value
- 768
-
- LastSnapshotToProfileWidth
-
- Comment
- The width of the last profile snapshot, in px
- Persist
- 1
- Type
- S32
- Value
- 1024
-
- LastSnapshotToEmailWidth
-
- Comment
- The width of the last email snapshot, in px
- Persist
- 1
- Type
- S32
- Value
- 1024
-
- LastSnapshotToDiskHeight
-
- Comment
- The height of the last disk snapshot, in px
- Persist
- 1
- Type
- S32
- Value
- 768
-
- LastSnapshotToDiskWidth
-
- Comment
- The width of the last disk snapshot, in px
- Persist
- 1
- Type
- S32
- Value
- 1024
-
- LastSnapshotToInventoryHeight
-
- Comment
- The height of the last texture snapshot, in px
- Persist
- 1
- Type
- S32
- Value
- 512
-
- LastSnapshotToInventoryWidth
-
- Comment
- The width of the last texture snapshot, in px
- Persist
- 1
- Type
- S32
- Value
- 512
-
- LeftClickShowMenu
-
- Comment
- Unused obsolete setting
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
LimitDragDistance
Comment
@@ -5829,17 +4249,6 @@
Value
40.0
- LoginSRVPump
-
- Comment
- (Deprecated) Name of the message pump that handles SRV request)
- Persist
- 0
- Type
- String
- Value
- LLAres
-
LogMessages
Comment
@@ -5928,17 +4337,6 @@
Value
60.0
- MapOverlayIndex
-
- Comment
- Currently selected world map type
- Persist
- 1
- Type
- S32
- Value
- 0
-
MapScale
Comment
@@ -6678,28 +5076,6 @@
Value
0.25
- MenuBarHeight
-
- Comment
-
- Persist
- 0
- Type
- S32
- Value
- 18
-
- MenuBarWidth
-
- Comment
-
- Persist
- 0
- Type
- S32
- Value
- 410
-
MePanelOpened
Comment
@@ -7154,28 +5530,6 @@
Value
0
- NotifyBoxHeight
-
- Comment
- Height of notification messages
- Persist
- 1
- Type
- S32
- Value
- 200
-
- NotifyBoxWidth
-
- Comment
- Width of notification messages
- Persist
- 1
- Type
- S32
- Value
- 305
-
NotificationConferenceIMOptions
Comment
@@ -7353,17 +5707,6 @@
Value
90
- ChannelBottomPanelMargin
-
- Comment
- Space from a lower toast to the Bottom Tray
- Persist
- 1
- Type
- S32
- Value
- 35
-
NotificationChannelRightMargin
Comment
@@ -8063,17 +6406,6 @@
F32
Value
6.0
-
- ClothingLoadingDelay
-
- Comment
- Time to wait for avatar appearance to resolve before showing world (seconds)
- Persist
- 1
- Type
- F32
- Value
- 10.0
PreferredMaturity
@@ -8517,17 +6849,6 @@
Value
0
- RadioLandBrushSize
-
- Comment
- Size of land modification brush (0 = small, 1 = medium, 2 = large)
- Persist
- 1
- Type
- S32
- Value
- 0
-
LandBrushForce
Comment
@@ -8539,17 +6860,6 @@
Value
1.0
- MediaBrowserWindowLimit
-
- Comment
- Maximum number of media brower windows that can be open at once in the media browser floater (0 for no limit)
- Persist
- 1
- Type
- S32
- Value
- 5
-
WebContentWindowLimit
Comment
@@ -8828,17 +7138,6 @@
Value
0
- RenderAvatar
-
- Comment
- Render Avatars
- Persist
- 0
- Type
- Boolean
- Value
- 1
-
RenderAvatarCloth
Comment
@@ -10788,7 +9087,7 @@
Value
1.0
- RendeSkyAutoAdjustBlueHorizonScale
+ RenderSkyAutoAdjustBlueHorizonScale
Comment
Blue Horizon Scale value to use when auto-adjusting legacy skies
@@ -10799,7 +9098,7 @@
Value
1.0
- RendeSkyAutoAdjustBlueDensityScale
+ RenderSkyAutoAdjustBlueDensityScale
Comment
Blue Horizon Scale value to use when auto-adjusting legacy skies
@@ -11774,17 +10073,6 @@
Value
0
- SecondLifeEnterprise
-
- Comment
- Enables Second Life Enterprise features
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
SelectMovableOnly
Comment
@@ -12060,17 +10348,6 @@
Value
0
- ShowEmptyFoldersWhenSearching
-
- Comment
- Shows folders that do not have any visible contents when applying a filter to inventory
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
ShowEventRecorderMenuItems
Comment
@@ -12412,136 +10689,6 @@
Value
1
- ShowPGSearchAll
-
- Comment
- Display results of search All that are flagged as general
- Persist
- 1
- HideFromEditor
- 1
- Type
- Boolean
- Value
- 1
-
- ShowMatureSearchAll
-
- Comment
- Display results of search All that are flagged as moderate
- Persist
- 1
- HideFromEditor
- 1
- Type
- Boolean
- Value
- 0
-
- ShowAdultSearchAll
-
- Comment
- Display results of search All that are flagged as adult
- Persist
- 1
- HideFromEditor
- 1
- Type
- Boolean
- Value
- 0
-
- ShowPGGroups
-
- Comment
- Display results of find groups that are flagged as general
- Persist
- 1
- HideFromEditor
- 1
- Type
- Boolean
- Value
- 1
-
- ShowMatureGroups
-
- Comment
- Display results of find groups that are flagged as moderate
- Persist
- 1
- HideFromEditor
- 1
- Type
- Boolean
- Value
- 0
-
- ShowAdultGroups
-
- Comment
- Display results of find groups that are flagged as adult
- Persist
- 1
- HideFromEditor
- 1
- Type
- Boolean
- Value
- 0
-
- ShowPGClassifieds
-
- Comment
- Display results of find classifieds that are flagged as general
- Persist
- 1
- HideFromEditor
- 1
- Type
- Boolean
- Value
- 1
-
- ShowMatureClassifieds
-
- Comment
- Display results of find classifieds that are flagged as moderate
- Persist
- 1
- HideFromEditor
- 1
- Type
- Boolean
- Value
- 0
-
- ShowAdultClassifieds
-
- Comment
- Display results of find classifieds that are flagged as adult
- Persist
- 1
- HideFromEditor
- 1
- Type
- Boolean
- Value
- 0
-
- ShowPGEvents
-
- Comment
- Display results of find events that are flagged as general
- Persist
- 1
- HideFromEditor
- 1
- Type
- Boolean
- Value
- 1
-
ShowMatureEvents
Comment
@@ -12777,17 +10924,6 @@
Boolean
Value
0
-
- ShowToolBar
-
- Comment
- Show toolbar at bottom of screen
- Persist
- 1
- Type
- Boolean
- Value
- 1
ShowTutorial
@@ -13230,28 +11366,6 @@
Value
1
- TexturePickerShowFolders
-
- Comment
- Show folders with no texures in texture picker
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- TexturePickerSortOrder
-
- Comment
- Specifies sort key for textures in texture picker (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)
- Persist
- 1
- Type
- U32
- Value
- 2
-
TextureReverseByteRange
Comment
@@ -13301,17 +11415,6 @@
Value
3000.0
- UpdaterMaximumBandwidth
-
- Comment
- Obsolete: this parameter is no longer used.
- Persist
- 1
- Type
- F32
- Value
- 500.0
-
ToolTipDelay
Comment
@@ -13444,17 +11547,6 @@
Value
- BingTranslateAPIKey
-
- Comment
- (Deprecated) Bing AppID to use with the Microsoft Translator API
- Persist
- 1
- Type
- String
- Value
-
-
AzureTranslateAPIKey
Comment
@@ -13521,28 +11613,6 @@
Value
6
- UICheckboxctrlBtnSize
-
- Comment
- UI Checkbox Control Button Size
- Persist
- 1
- Type
- S32
- Value
- 13
-
- UICheckboxctrlHeight
-
- Comment
- UI Checkbox Control Height
- Persist
- 1
- Type
- S32
- Value
- 16
-
UICheckboxctrlHPad
Comment
@@ -13774,50 +11844,6 @@
Value
5748decc-f629-461c-9a36-a35a221fe21f
- StartUpChannelUUID
-
- Comment
-
- Persist
- 0
- Type
- String
- Value
- B56AF90D-6684-48E4-B1E4-722D3DEB2CB6
-
- NearByChatChannelUUID
-
- Comment
-
- Persist
- 0
- Type
- String
- Value
- E1158BD6-661C-4981-9DAD-4DCBFF062502
-
- NotificationChannelUUID
-
- Comment
-
- Persist
- 0
- Type
- String
- Value
- AEED3193-8709-4693-8558-7452CCA97AE5
-
- AlertChannelUUID
-
- Comment
-
- Persist
- 0
- Type
- String
- Value
- F3E07BC8-A973-476D-8C7F-F3B7293975D1
-
UILineEditorCursorThickness
Comment
@@ -14005,17 +12031,6 @@
Value
1.0
- LastSystemUIScaleFactor
-
- Comment
- OBSOLETE: System UI scale factor is now automatically and independently from UIScaleFactor applied
- Persist
- 1
- Type
- F32
- Value
- 1.0
-
UIScrollbarSize
Comment
@@ -14335,17 +12350,6 @@
Value
16
- UISpinctrlDefaultLabelWidth
-
- Comment
- UI spin control default label width
- Persist
- 1
- Type
- S32
- Value
- 10
-
UISpinctrlSpacing
Comment
@@ -14467,39 +12471,6 @@
Value
3
- UpdaterServiceCheckPeriod
-
- Comment
- Obsolete; no longer used.
- Persist
- 0
- Type
- U32
- Value
- 3600
-
- UpdaterServiceURL
-
- Comment
- Obsolete; no longer used.
- Persist
- 0
- Type
- String
- Value
- https://update.secondlife.com
-
- UpdaterServicePath
-
- Comment
- Obsolete: no longer used
- Persist
- 0
- Type
- String
- Value
- update
-
UpdaterWillingToTest
Comment
@@ -14632,17 +12603,6 @@
Value
1
- UseEnvironmentFromRegion
-
- Comment
- Choose whether to use the region's environment settings, or override them with the local settings.
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
EnvironmentPersistAcrossLogin
Comment
@@ -14654,62 +12614,6 @@
Value
0
- UseDayCycle
-
- Comment
- Whether to use use a day cycle or a fixed sky.
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- WaterPresetName
-
- Comment
- Water preset to use. May be superseded by region settings.
- Persist
- 1
- Type
- String
- Value
- Default
-
- SkyPresetName
-
- Comment
- Sky preset to use. May be superseded by region settings or by a day cycle (see DayCycleName).
- Persist
- 1
- Type
- String
- Value
- Default
-
- DayCycleName
-
- Comment
- Day cycle to use. May be superseded by region settings.
- Persist
- 1
- Type
- String
- Value
- Default
-
- UseExternalBrowser
-
-
- Comment
- (Deprecated) Use default browser when opening web pages instead of in-world browser.
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
PreferredBrowserBehavior
Comment
@@ -14765,6 +12669,17 @@
Value
1
+ RenderDelayVBUpdate
+
+ Comment
+ Delay vertex buffer updates until just before rendering
+ Persist
+ 1
+ Type
+ Boolean
+ Value
+ 0
+
SocialPhotoResolution
Comment
@@ -15570,17 +13485,6 @@
Value
-1.0
- ForcePeriodicRenderingTime
-
- Comment
- Periodically enable all rendering masks for a single frame.
- Persist
- 1
- Type
- F32
- Value
- -1.0
-
ZoomDirect
Comment
@@ -15746,17 +13650,6 @@
Value
0
- AssetStorageLogFrequency
-
- Comment
- Seconds between display of AssetStorage info in log (0 for never)
- Persist
- 1
- Type
- F32
- Value
- 60.0
-
LogWearableAssetSave
Comment
@@ -15994,28 +13887,6 @@
Value
120.0
- DestinationGuideHintTimeout
-
- Comment
- Number of seconds to wait before telling resident about destination guide.
- Persist
- 1
- Type
- F32
- Value
- 1200.0
-
- SidePanelHintTimeout
-
- Comment
- Number of seconds to wait before telling resident about side panel.
- Persist
- 1
- Type
- F32
- Value
- 300.0
-
GroupMembersSortOrder
Comment
@@ -16060,17 +13931,6 @@
Value
0
- AvatarInspectorTooltipDelay
-
- Comment
- Seconds before displaying avatar inspector tooltip
- Persist
- 1
- Type
- F32
- Value
- 0.35
-
ObjectInspectorTooltipDelay
Comment
@@ -16104,17 +13964,6 @@
Value
1
- EnableGroupInfo
-
- Comment
- Enable viewing and editing of group info from web link
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
EnablePlaceProfile
Comment
@@ -16126,28 +13975,6 @@
Value
1
- EnablePicks
-
- Comment
- Enable editing of picks from web link
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
- EnableWorldMap
-
- Comment
- Enable opening world map from web link
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
EnableAvatarPay
Comment
@@ -16159,17 +13986,6 @@
Value
1
- EnableVoiceCall
-
- Comment
- Enable voice calls from web link
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
EnableAvatarShare
Comment
@@ -16192,17 +14008,6 @@
Value
1
- EnableSearch
-
- Comment
- Enable opening search from web link
- Persist
- 1
- Type
- Boolean
- Value
- 1
-
EnableAppearance
Comment
@@ -16279,17 +14084,6 @@
Boolean
Value
0
-
- AllowBottomTrayButtonReordering
-
- Comment
- Allow user to move and hide bottom tray buttons
- Persist
- 1
- Type
- Boolean
- Value
- 1
AllowSelectAvatar
@@ -17193,28 +14987,6 @@
Value
1000
- FMODExStreamBufferSize
-
- Comment
- Sets the streaming buffer size (in milliseconds) for FMOD Ex or FMOD Studio
- Persist
- 1
- Type
- U32
- Value
- 7000
-
- DisablePrecacheDelayAfterTeleporting
-
- Comment
- Disables the artificial delay in the viewer that precaches some incoming assets
- Persist
- 0
- Type
- Boolean
- Value
- 0
-
VersionChannelName
Comment
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 63608cdbf8..d1dab94a76 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -397,8 +397,18 @@ CreateShortCut "$SMPROGRAMS\$INSTSHORTCUT\Uninstall $INSTSHORTCUT.lnk" \
# Other shortcuts
SetOutPath "$INSTDIR"
-CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" \
+
+Push $0
+${GetParameters} $COMMANDLINE
+${GetOptionsS} $COMMANDLINE "/marker" $0
+# Returns error if option does not exist
+IfErrors 0 DESKTOP_SHORTCUT_DONE
+ # "/marker" is set by updater, do not recreate desktop shortcut
+ CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" \
"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+
+DESKTOP_SHORTCUT_DONE:
+Pop $0
CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" \
"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \
diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp
index 38fa4477b3..82124b7412 100644
--- a/indra/newview/llaccountingcostmanager.cpp
+++ b/indra/newview/llaccountingcostmanager.cpp
@@ -58,16 +58,19 @@ void LLAccountingCostManager::accountingCostCoro(std::string url,
try
{
+ LLAccountingCostManager* self = LLAccountingCostManager::getInstance();
uuid_set_t diffSet;
- std::set_difference(mObjectList.begin(), mObjectList.end(),
- mPendingObjectQuota.begin(), mPendingObjectQuota.end(),
- std::inserter(diffSet, diffSet.begin()));
+ std::set_difference(self->mObjectList.begin(),
+ self->mObjectList.end(),
+ self->mPendingObjectQuota.begin(),
+ self->mPendingObjectQuota.end(),
+ std::inserter(diffSet, diffSet.begin()));
if (diffSet.empty())
return;
- mObjectList.clear();
+ self->mObjectList.clear();
std::string keystr;
if (selectionType == Roots)
@@ -91,18 +94,25 @@ void LLAccountingCostManager::accountingCostCoro(std::string url,
objectList.append(*it);
}
- mPendingObjectQuota.insert(diffSet.begin(), diffSet.end());
+ self->mPendingObjectQuota.insert(diffSet.begin(), diffSet.end());
LLSD dataToPost = LLSD::emptyMap();
dataToPost[keystr.c_str()] = objectList;
- LLAccountingCostObserver* observer = NULL;
-
LLSD results = httpAdapter->postAndSuspend(httpRequest, url, dataToPost);
LLSD httpResults = results["http_result"];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ if (LLApp::isQuitting()
+ || observerHandle.isDead()
+ || !LLAccountingCostManager::instanceExists())
+ {
+ return;
+ }
+
+ LLAccountingCostObserver* observer = NULL;
+
// do/while(false) allows error conditions to break out of following
// block while normal flow goes forward once.
do
@@ -159,7 +169,8 @@ void LLAccountingCostManager::accountingCostCoro(std::string url,
throw;
}
- mPendingObjectQuota.clear();
+ // self can be obsolete by this point
+ LLAccountingCostManager::getInstance()->mPendingObjectQuota.clear();
}
//===============================================================================
@@ -172,7 +183,7 @@ void LLAccountingCostManager::fetchCosts( eSelectionType selectionType,
{
std::string coroname =
LLCoros::instance().launch("LLAccountingCostManager::accountingCostCoro",
- boost::bind(&LLAccountingCostManager::accountingCostCoro, this, url, selectionType, observer_handle));
+ boost::bind(accountingCostCoro, url, selectionType, observer_handle));
LL_DEBUGS() << coroname << " with url '" << url << LL_ENDL;
}
diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h
index a147d8bdbf..1883a709a1 100644
--- a/indra/newview/llaccountingcostmanager.h
+++ b/indra/newview/llaccountingcostmanager.h
@@ -70,7 +70,7 @@ private:
//a fetch has been instigated.
uuid_set_t mPendingObjectQuota;
- void accountingCostCoro(std::string url, eSelectionType selectionType, const LLHandle observerHandle);
+ static void accountingCostCoro(std::string url, eSelectionType selectionType, const LLHandle observerHandle);
};
//===============================================================================
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 70ff7f1941..1912d9d1d5 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -1932,7 +1932,8 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
}
else
{
- target_lag = vel * gSavedSettings.getF32("DynamicCameraStrength") / 30.f;
+ LLCachedControl dynamic_camera_strength(gSavedSettings, "DynamicCameraStrength");
+ target_lag = vel * dynamic_camera_strength / 30.f;
}
mCameraLag = lerp(mCameraLag, target_lag, lag_interp);
diff --git a/indra/newview/llagentpicksinfo.cpp b/indra/newview/llagentpicksinfo.cpp
index 288d04d9a0..17464dcef9 100644
--- a/indra/newview/llagentpicksinfo.cpp
+++ b/indra/newview/llagentpicksinfo.cpp
@@ -49,10 +49,10 @@ public:
void sendAgentPicksRequest()
{
- LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(gAgent.getID());
+ LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(gAgent.getID());
}
- typedef boost::function server_respond_callback_t;
+ typedef boost::function server_respond_callback_t;
void setServerRespondCallback(const server_respond_callback_t& cb)
{
@@ -61,10 +61,10 @@ public:
virtual void processProperties(void* data, EAvatarProcessorType type)
{
- if(APT_PICKS == type)
+ if(APT_PROPERTIES == type)
{
- LLAvatarPicks* picks = static_cast(data);
- if(picks && gAgent.getID() == picks->target_id)
+ LLAvatarData* picks = static_cast(data);
+ if(picks && gAgent.getID() == picks->avatar_id)
{
if(mServerRespondCallback)
{
@@ -115,7 +115,7 @@ bool LLAgentPicksInfo::isPickLimitReached()
return getNumberOfPicks() >= getMaxNumberOfPicks();
}
-void LLAgentPicksInfo::onServerRespond(LLAvatarPicks* picks)
+void LLAgentPicksInfo::onServerRespond(LLAvatarData* picks)
{
if(!picks)
{
diff --git a/indra/newview/llagentpicksinfo.h b/indra/newview/llagentpicksinfo.h
index 19d593bab5..edd41d8746 100644
--- a/indra/newview/llagentpicksinfo.h
+++ b/indra/newview/llagentpicksinfo.h
@@ -29,7 +29,7 @@
#include "llsingleton.h"
-struct LLAvatarPicks;
+struct LLAvatarData;
/**
* Class that provides information about Agent Picks
@@ -74,7 +74,7 @@ public:
void decrementNumberOfPicks() { --mNumberOfPicks; }
- void onServerRespond(LLAvatarPicks* picks);
+ void onServerRespond(LLAvatarData* picks);
private:
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index ceeefd7415..97e1c1e6ee 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -1398,7 +1398,7 @@ const std::string LLAppearanceMgr::sExpectedTextureName = "OutfitPreview";
const LLUUID LLAppearanceMgr::getCOF() const
{
- return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ return mCOFID;
}
S32 LLAppearanceMgr::getCOFVersion() const
@@ -1414,6 +1414,11 @@ S32 LLAppearanceMgr::getCOFVersion() const
}
}
+void LLAppearanceMgr::initCOFID()
+{
+ mCOFID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+}
+
const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink()
{
const LLUUID& current_outfit_cat = getCOF();
@@ -3762,6 +3767,14 @@ LLSD LLAppearanceMgr::dumpCOF() const
return result;
}
+void LLAppearanceMgr::cleanup()
+{
+ mIsInUpdateAppearanceFromCOF = false;
+ mOutstandingAppearanceBakeRequest = false;
+ mRerequestAppearanceBake = false;
+ mCOFID.setNull();
+}
+
// static
void LLAppearanceMgr::onIdle(void *)
{
@@ -4130,7 +4143,7 @@ void LLAppearanceMgr::wearBaseOutfit()
updateCOF(base_outfit_id);
}
-void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
+void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove, nullary_func_t post_update_func)
{
LL_DEBUGS("UIUsage") << "removeItemsFromAvatar" << LL_ENDL;
LLUIUsage::instance().logCommand("Avatar.RemoveItem");
@@ -4140,7 +4153,7 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL;
return;
}
- LLPointer cb = new LLUpdateAppearanceOnDestroy;
+ LLPointer cb = new LLUpdateAppearanceOnDestroy(true, true, post_update_func);
for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it)
{
const LLUUID& id_to_remove = *it;
@@ -4159,11 +4172,11 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
}
}
-void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
+void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove, nullary_func_t post_update_func)
{
uuid_vec_t ids_to_remove;
ids_to_remove.push_back(id_to_remove);
- removeItemsFromAvatar(ids_to_remove);
+ removeItemsFromAvatar(ids_to_remove, post_update_func);
}
@@ -4400,20 +4413,45 @@ BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const
return FALSE;
}
-BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const
+bool LLAppearanceMgr::getIsInCOF(const LLInventoryObject* obj) const
{
- if (!getIsInCOF(obj_id)) return FALSE;
+ const LLUUID& cof = getCOF();
+ if (obj->getUUID() == cof)
+ return true;
+ if (obj && obj->getParentUUID() == cof)
+ return true;
+ return false;
+}
+
+bool LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const
+{
+ if (!getIsInCOF(obj_id)) return false;
// If a non-link somehow ended up in COF, allow deletion.
const LLInventoryObject *obj = gInventory.getObject(obj_id);
if (obj && !obj->getIsLinkType())
{
- return FALSE;
+ return false;
}
// For now, don't allow direct deletion from the COF. Instead, force users
// to choose "Detach" or "Take Off".
- return TRUE;
+ return true;
+}
+
+bool LLAppearanceMgr::getIsProtectedCOFItem(const LLInventoryObject* obj) const
+{
+ if (!getIsInCOF(obj)) return false;
+
+ // If a non-link somehow ended up in COF, allow deletion.
+ if (obj && !obj->getIsLinkType())
+ {
+ return false;
+ }
+
+ // For now, don't allow direct deletion from the COF. Instead, force users
+ // to choose "Detach" or "Take Off".
+ return true;
}
class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index ae23022513..e5de92b653 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -111,9 +111,11 @@ public:
// Find the Current Outfit folder.
const LLUUID getCOF() const;
S32 getCOFVersion() const;
+ void initCOFID();
// Debugging - get truncated LLSD summary of COF contents.
LLSD dumpCOF() const;
+ void cleanup();
// Finds the folder link to the currently worn outfit
const LLViewerInventoryItem *getBaseOutfitLink();
@@ -195,8 +197,8 @@ public:
bool updateBaseOutfit();
//Remove clothing or detach an object from the agent (a bodypart cannot be removed)
- void removeItemsFromAvatar(const uuid_vec_t& item_ids);
- void removeItemFromAvatar(const LLUUID& item_id);
+ void removeItemsFromAvatar(const uuid_vec_t& item_ids, nullary_func_t post_update_func = no_op);
+ void removeItemFromAvatar(const LLUUID& item_id, nullary_func_t post_update_func = no_op);
void onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel);
@@ -276,6 +278,7 @@ private:
attachments_changed_signal_t mAttachmentsChangeSignal;
LLUUID mCOFImageID;
+ LLUUID mCOFID;
std::unique_ptr mUnlockOutfitTimer;
@@ -290,8 +293,10 @@ private:
public:
// Is this in the COF?
BOOL getIsInCOF(const LLUUID& obj_id) const;
+ bool getIsInCOF(const LLInventoryObject* obj) const;
// Is this in the COF and can the user delete it from the COF?
- BOOL getIsProtectedCOFItem(const LLUUID& obj_id) const;
+ bool getIsProtectedCOFItem(const LLUUID& obj_id) const;
+ bool getIsProtectedCOFItem(const LLInventoryObject* obj) const;
// Outfits will prioritize textures with such name to use for preview in gallery
static const std::string sExpectedTextureName;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 617cd18e9f..1626af74e2 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -528,13 +528,6 @@ bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* ba
// or for things that are performance critical. JC
static void settings_to_globals()
{
- LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad");
- BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall");
- BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight");
-
- MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight");
- MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth");
-
LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
#if LL_DARWIN
@@ -4312,7 +4305,8 @@ bool LLAppViewer::initCache()
LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch);
- LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion());
+ const U32 CACHE_NUMBER_OF_REGIONS_FOR_OBJECTS = 128;
+ LLVOCache::getInstance()->initCache(LL_PATH_CACHE, CACHE_NUMBER_OF_REGIONS_FOR_OBJECTS, getObjectCacheVersion());
return true;
}
diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp
index 07e544a1ca..28b6e6dbf6 100644
--- a/indra/newview/llavatariconctrl.cpp
+++ b/indra/newview/llavatariconctrl.cpp
@@ -245,7 +245,7 @@ void LLAvatarIconCtrl::setValue(const LLSD& value)
// messages. People API already hits the user table.
LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI);
app->addObserver(mAvatarId, this);
- app->sendAvatarPropertiesRequest(mAvatarId);
+ app->sendAvatarLegacyPropertiesRequest(mAvatarId);
}
else if (gAgentID == mAvatarId)
{
@@ -299,7 +299,27 @@ bool LLAvatarIconCtrl::updateFromCache()
//virtual
void LLAvatarIconCtrl::processProperties(void* data, EAvatarProcessorType type)
{
- if (APT_PROPERTIES == type)
+ // Both APT_PROPERTIES_LEGACY and APT_PROPERTIES have icon data.
+ // 'Legacy' is cheaper to request so LLAvatarIconCtrl issues that,
+ // but own icon should track any source for the sake of timely updates.
+ //
+ // If this needs to change, make sure to update onCommitProfileImage
+ // to issue right kind of request
+ if (APT_PROPERTIES_LEGACY == type)
+ {
+ LLAvatarLegacyData* avatar_data = static_cast(data);
+ if (avatar_data)
+ {
+ if (avatar_data->avatar_id != mAvatarId)
+ {
+ return;
+ }
+
+ LLAvatarIconIDCache::getInstance()->add(mAvatarId,avatar_data->image_id);
+ updateFromCache();
+ }
+ }
+ else if (APT_PROPERTIES == type)
{
LLAvatarData* avatar_data = static_cast(data);
if (avatar_data)
@@ -309,7 +329,7 @@ void LLAvatarIconCtrl::processProperties(void* data, EAvatarProcessorType type)
return;
}
- LLAvatarIconIDCache::getInstance()->add(mAvatarId,avatar_data->image_id);
+ LLAvatarIconIDCache::getInstance()->add(mAvatarId, avatar_data->image_id);
updateFromCache();
}
}
diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp
index f28cb6147e..72bdbb6975 100644
--- a/indra/newview/llavatarpropertiesprocessor.cpp
+++ b/indra/newview/llavatarpropertiesprocessor.cpp
@@ -52,24 +52,23 @@ LLAvatarPropertiesProcessor::~LLAvatarPropertiesProcessor()
void LLAvatarPropertiesProcessor::addObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer)
{
+ if (!observer)
+ return;
+
// Check if that observer is already in mObservers for that avatar_id
- observer_multimap_t::iterator it;
+ using pair = std::pair;
+ observer_multimap_t::iterator begin = mObservers.begin();
+ observer_multimap_t::iterator end = mObservers.end();
+ observer_multimap_t::iterator it = std::find_if(begin, end, [&](const pair& p)
+ {
+ return p.first == avatar_id && p.second == observer;
+ });
// IAN BUG this should update the observer's UUID if this is a dupe - sent to PE
- it = mObservers.find(avatar_id);
- while (it != mObservers.end())
+ if (it == end)
{
- if (it->second == observer)
- {
- return;
- }
- else
- {
- ++it;
- }
+ mObservers.emplace(avatar_id, observer);
}
-
- mObservers.insert(std::pair(avatar_id, observer));
}
void LLAvatarPropertiesProcessor::removeObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer)
@@ -79,19 +78,18 @@ void LLAvatarPropertiesProcessor::removeObserver(const LLUUID& avatar_id, LLAvat
return;
}
- observer_multimap_t::iterator it;
- it = mObservers.find(avatar_id);
- while (it != mObservers.end())
+ // Check if that observer is in mObservers for that avatar_id
+ using pair = std::pair;
+ observer_multimap_t::iterator begin = mObservers.begin();
+ observer_multimap_t::iterator end = mObservers.end();
+ observer_multimap_t::iterator it = std::find_if(begin, end, [&](const pair& p)
+ {
+ return p.first == avatar_id && p.second == observer;
+ });
+
+ if (it != end)
{
- if (it->second == observer)
- {
- mObservers.erase(it);
- break;
- }
- else
- {
- ++it;
- }
+ mObservers.erase(it);
}
}
@@ -116,32 +114,30 @@ void LLAvatarPropertiesProcessor::sendRequest(const LLUUID& avatar_id, EAvatarPr
return;
}
- std::string cap;
-
- switch (type)
+ // Try to send HTTP request if cap_url is available
+ if (type == APT_PROPERTIES)
{
- case APT_PROPERTIES:
- // indicate we're going to make a request
- sendAvatarPropertiesRequestMessage(avatar_id);
- // can use getRegionCapability("AgentProfile"), but it is heavy
- // initAgentProfileCapRequest(avatar_id, cap);
- break;
- case APT_PICKS:
- case APT_GROUPS:
- case APT_NOTES:
- if (cap.empty())
+ std::string cap_url = gAgent.getRegionCapability("AgentProfile");
+ if (!cap_url.empty())
{
- // indicate we're going to make a request
- sendGenericRequest(avatar_id, type, method);
+ initAgentProfileCapRequest(avatar_id, cap_url, type);
}
else
{
- initAgentProfileCapRequest(avatar_id, cap);
+ // Don't sent UDP request for APT_PROPERTIES
+ LL_WARNS() << "No cap_url for APT_PROPERTIES, request for " << avatar_id << " is not sent" << LL_ENDL;
}
- break;
- default:
+ return;
+ }
+
+ // Send UDP request
+ if (type == APT_PROPERTIES_LEGACY)
+ {
+ sendAvatarPropertiesRequestMessage(avatar_id);
+ }
+ else
+ {
sendGenericRequest(avatar_id, type, method);
- break;
}
}
@@ -150,33 +146,29 @@ void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EA
// indicate we're going to make a request
addPendingRequest(avatar_id, type);
- std::vector strings;
- strings.push_back(avatar_id.asString());
+ std::vector strings{ avatar_id.asString() };
send_generic_message(method, strings);
}
void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequestMessage(const LLUUID& avatar_id)
{
- addPendingRequest(avatar_id, APT_PROPERTIES);
+ addPendingRequest(avatar_id, APT_PROPERTIES_LEGACY);
LLMessageSystem *msg = gMessageSystem;
msg->newMessageFast(_PREHASH_AvatarPropertiesRequest);
msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
+ msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
msg->addUUIDFast(_PREHASH_AvatarID, avatar_id);
gAgent.sendReliableMessage();
}
-void LLAvatarPropertiesProcessor::initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url)
+void LLAvatarPropertiesProcessor::initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url, EAvatarProcessorType type)
{
- addPendingRequest(avatar_id, APT_PROPERTIES);
- addPendingRequest(avatar_id, APT_PICKS);
- addPendingRequest(avatar_id, APT_GROUPS);
- addPendingRequest(avatar_id, APT_NOTES);
+ addPendingRequest(avatar_id, type);
LLCoros::instance().launch("requestAgentUserInfoCoro",
- boost::bind(requestAvatarPropertiesCoro, cap_url, avatar_id));
+ [cap_url, avatar_id, type]() { requestAvatarPropertiesCoro(cap_url, avatar_id, type); });
}
void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id)
@@ -184,19 +176,9 @@ void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avat
sendRequest(avatar_id, APT_PROPERTIES, "AvatarPropertiesRequest");
}
-void LLAvatarPropertiesProcessor::sendAvatarPicksRequest(const LLUUID& avatar_id)
+void LLAvatarPropertiesProcessor::sendAvatarLegacyPropertiesRequest(const LLUUID& avatar_id)
{
- sendGenericRequest(avatar_id, APT_PICKS, "avatarpicksrequest");
-}
-
-void LLAvatarPropertiesProcessor::sendAvatarNotesRequest(const LLUUID& avatar_id)
-{
- sendGenericRequest(avatar_id, APT_NOTES, "avatarnotesrequest");
-}
-
-void LLAvatarPropertiesProcessor::sendAvatarGroupsRequest(const LLUUID& avatar_id)
-{
- sendGenericRequest(avatar_id, APT_GROUPS, "avatargroupsrequest");
+ sendRequest(avatar_id, APT_PROPERTIES_LEGACY, "AvatarPropertiesRequest");
}
void LLAvatarPropertiesProcessor::sendAvatarTexturesRequest(const LLUUID& avatar_id)
@@ -211,42 +193,6 @@ void LLAvatarPropertiesProcessor::sendAvatarClassifiedsRequest(const LLUUID& ava
sendGenericRequest(avatar_id, APT_CLASSIFIEDS, "avatarclassifiedsrequest");
}
-void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const LLAvatarData* avatar_props)
-{
- if (!gAgent.isInitialized() || (gAgent.getID() == LLUUID::null))
- {
- LL_WARNS() << "Sending avatarinfo update DENIED - invalid agent" << LL_ENDL;
- return;
- }
-
- LL_WARNS() << "Sending avatarinfo update. This trims profile descriptions!!!" << LL_ENDL;
-
- // This value is required by sendAvatarPropertiesUpdate method.
- //A profile should never be mature. (From the original code)
- BOOL mature = FALSE;
-
- LLMessageSystem *msg = gMessageSystem;
-
- msg->newMessageFast (_PREHASH_AvatarPropertiesUpdate);
- msg->nextBlockFast (_PREHASH_AgentData);
- msg->addUUIDFast (_PREHASH_AgentID, gAgent.getID() );
- msg->addUUIDFast (_PREHASH_SessionID, gAgent.getSessionID() );
- msg->nextBlockFast (_PREHASH_PropertiesData);
-
- msg->addUUIDFast (_PREHASH_ImageID, avatar_props->image_id);
- msg->addUUIDFast (_PREHASH_FLImageID, avatar_props->fl_image_id);
- msg->addStringFast (_PREHASH_AboutText, avatar_props->about_text);
- msg->addStringFast (_PREHASH_FLAboutText, avatar_props->fl_about_text);
-
- msg->addBOOL(_PREHASH_AllowPublish, avatar_props->allow_publish);
- msg->addBOOL(_PREHASH_MaturePublish, mature);
- msg->addString(_PREHASH_ProfileURL, avatar_props->profile_url);
-
- gAgent.sendReliableMessage();
-}
-
-
-
//static
std::string LLAvatarPropertiesProcessor::accountType(const LLAvatarData* avatar_data)
{
@@ -271,19 +217,21 @@ std::string LLAvatarPropertiesProcessor::accountType(const LLAvatarData* avatar_
std::string LLAvatarPropertiesProcessor::paymentInfo(const LLAvatarData* avatar_data)
{
// Special accounts like M Linden don't have payment info revealed.
- if (!avatar_data->caption_text.empty()) return "";
+ if (!avatar_data->caption_text.empty())
+ return "";
// Linden employees don't have payment info revealed
- const S32 LINDEN_EMPLOYEE_INDEX = 3;
- if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) return "";
+ constexpr S32 LINDEN_EMPLOYEE_INDEX = 3;
+ if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX)
+ return "";
- BOOL transacted = (avatar_data->flags & AVATAR_TRANSACTED);
- BOOL identified = (avatar_data->flags & AVATAR_IDENTIFIED);
+ bool transacted = (avatar_data->flags & AVATAR_TRANSACTED);
+ bool identified = (avatar_data->flags & AVATAR_IDENTIFIED);
// Not currently getting set in dataserver/lldataavatar.cpp for privacy considerations
//BOOL age_verified = (avatar_data->flags & AVATAR_AGEVERIFIED);
const char* payment_text;
- if(transacted)
+ if (transacted)
{
payment_text = "PaymentInfoUsed";
}
@@ -302,18 +250,22 @@ std::string LLAvatarPropertiesProcessor::paymentInfo(const LLAvatarData* avatar_
bool LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(const LLAvatarData* avatar_data)
{
// Special accounts like M Linden don't have payment info revealed.
- if (!avatar_data->caption_text.empty()) return true;
+ if (!avatar_data->caption_text.empty())
+ return true;
// Linden employees don't have payment info revealed
- const S32 LINDEN_EMPLOYEE_INDEX = 3;
- if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) return true;
+ constexpr S32 LINDEN_EMPLOYEE_INDEX = 3;
+ if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX)
+ return true;
return ((avatar_data->flags & AVATAR_TRANSACTED) || (avatar_data->flags & AVATAR_IDENTIFIED));
}
// static
-void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id)
+void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_url, LLUUID avatar_id, EAvatarProcessorType type)
{
+ LLAvatarPropertiesProcessor& inst = instance();
+
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("requestAvatarPropertiesCoro", httpPolicy));
@@ -323,104 +275,104 @@ void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_ur
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
httpOpts->setFollowRedirects(true);
- std::string finalUrl = cap_url + "/" + agent_id.asString();
+ std::string finalUrl = cap_url + "/" + avatar_id.asString();
LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl, httpOpts, httpHeaders);
+ // Response is being processed, no longer pending is required
+ inst.removePendingRequest(avatar_id, type);
+
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if (!status
|| !result.has("id")
- || agent_id != result["id"].asUUID())
+ || avatar_id != result["id"].asUUID())
{
- LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << agent_id << LL_ENDL;
- LLAvatarPropertiesProcessor* self = getInstance();
- self->removePendingRequest(agent_id, APT_PROPERTIES);
- self->removePendingRequest(agent_id, APT_PICKS);
- self->removePendingRequest(agent_id, APT_GROUPS);
- self->removePendingRequest(agent_id, APT_NOTES);
+ LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << avatar_id
+ << (!status ? " (no HTTP status)" : !result.has("id") ? " (no result.id)" :
+ std::string(" (result.id=") + result["id"].asUUID().asString() + ")")
+ << LL_ENDL;
return;
}
- // Avatar Data
-
LLAvatarData avatar_data;
+
std::string birth_date;
- avatar_data.agent_id = agent_id;
- avatar_data.avatar_id = agent_id;
+ avatar_data.agent_id = gAgentID;
+ avatar_data.avatar_id = avatar_id;
avatar_data.image_id = result["sl_image_id"].asUUID();
avatar_data.fl_image_id = result["fl_image_id"].asUUID();
avatar_data.partner_id = result["partner_id"].asUUID();
avatar_data.about_text = result["sl_about_text"].asString();
avatar_data.fl_about_text = result["fl_about_text"].asString();
avatar_data.born_on = result["member_since"].asDate();
- avatar_data.profile_url = getProfileURL(agent_id.asString());
+ // TODO: SL-20163 Remove the "has" check when SRV-684 is done
+ // and the field "hide_age" is included to the http response
+ inst.mIsHideAgeSupportedByServer = result.has("hide_age");
+ avatar_data.hide_age = inst.isHideAgeSupportedByServer() && result["hide_age"].asBoolean();
+ avatar_data.profile_url = getProfileURL(avatar_id.asString());
+ avatar_data.customer_type = result["customer_type"].asString();
+ avatar_data.notes = result["notes"].asString();
avatar_data.flags = 0;
- avatar_data.caption_index = 0;
-
- LLAvatarPropertiesProcessor* self = getInstance();
- // Request processed, no longer pending
- self->removePendingRequest(agent_id, APT_PROPERTIES);
- self->notifyObservers(agent_id, &avatar_data, APT_PROPERTIES);
-
- // Picks
-
- LLSD picks_array = result["picks"];
- LLAvatarPicks avatar_picks;
- avatar_picks.agent_id = agent_id; // Not in use?
- avatar_picks.target_id = agent_id;
-
- for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it)
+ if (result["online"].asBoolean())
{
- const LLSD& pick_data = *it;
- avatar_picks.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString());
+ avatar_data.flags |= AVATAR_ONLINE;
+ }
+ if (result["allow_publish"].asBoolean())
+ {
+ avatar_data.flags |= AVATAR_ALLOW_PUBLISH;
+ }
+ if (result["identified"].asBoolean())
+ {
+ avatar_data.flags |= AVATAR_IDENTIFIED;
+ }
+ if (result["transacted"].asBoolean())
+ {
+ avatar_data.flags |= AVATAR_TRANSACTED;
}
- // Request processed, no longer pending
- self->removePendingRequest(agent_id, APT_PICKS);
- self->notifyObservers(agent_id, &avatar_picks, APT_PICKS);
+ avatar_data.caption_index = 0;
+ if (result.has("charter_member")) // won't be present if "caption" is set
+ {
+ avatar_data.caption_index = result["charter_member"].asInteger();
+ }
+ else if (result.has("caption"))
+ {
+ avatar_data.caption_text = result["caption"].asString();
+ }
// Groups
-
LLSD groups_array = result["groups"];
- LLAvatarGroups avatar_groups;
- avatar_groups.agent_id = agent_id; // Not in use?
- avatar_groups.avatar_id = agent_id; // target_id
-
for (LLSD::array_const_iterator it = groups_array.beginArray(); it != groups_array.endArray(); ++it)
{
const LLSD& group_info = *it;
- LLAvatarGroups::LLGroupData group_data;
+ LLAvatarData::LLGroupData group_data;
group_data.group_powers = 0; // Not in use?
group_data.group_title = group_info["name"].asString(); // Missing data, not in use?
group_data.group_id = group_info["id"].asUUID();
group_data.group_name = group_info["name"].asString();
group_data.group_insignia_id = group_info["image_id"].asUUID();
- avatar_groups.group_list.push_back(group_data);
+ avatar_data.group_list.push_back(group_data);
}
- self->removePendingRequest(agent_id, APT_GROUPS);
- self->notifyObservers(agent_id, &avatar_groups, APT_GROUPS);
+ // Picks
+ LLSD picks_array = result["picks"];
+ for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it)
+ {
+ const LLSD& pick_data = *it;
+ avatar_data.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString());
+ }
- // Notes
- LLAvatarNotes avatar_notes;
-
- avatar_notes.agent_id = agent_id;
- avatar_notes.target_id = agent_id;
- avatar_notes.notes = result["notes"].asString();
-
- // Request processed, no longer pending
- self->removePendingRequest(agent_id, APT_NOTES);
- self->notifyObservers(agent_id, &avatar_notes, APT_NOTES);
+ inst.notifyObservers(avatar_id, &avatar_data, type);
}
-void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* msg, void**)
+void LLAvatarPropertiesProcessor::processAvatarLegacyPropertiesReply(LLMessageSystem* msg, void**)
{
- LLAvatarData avatar_data;
+ LLAvatarLegacyData avatar_data;
std::string birth_date;
msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AgentID, avatar_data.agent_id);
@@ -434,51 +386,35 @@ void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem*
msg->getString( _PREHASH_PropertiesData, _PREHASH_ProfileURL, avatar_data.profile_url);
msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_Flags, avatar_data.flags);
-
LLDateUtil::dateFromPDTString(avatar_data.born_on, birth_date);
avatar_data.caption_index = 0;
S32 charter_member_size = 0;
charter_member_size = msg->getSize(_PREHASH_PropertiesData, _PREHASH_CharterMember);
- if(1 == charter_member_size)
+ if (1 == charter_member_size)
{
msg->getBinaryData(_PREHASH_PropertiesData, _PREHASH_CharterMember, &avatar_data.caption_index, 1);
}
- else if(1 < charter_member_size)
+ else if (1 < charter_member_size)
{
msg->getString(_PREHASH_PropertiesData, _PREHASH_CharterMember, avatar_data.caption_text);
}
LLAvatarPropertiesProcessor* self = getInstance();
// Request processed, no longer pending
- self->removePendingRequest(avatar_data.avatar_id, APT_PROPERTIES);
- self->notifyObservers(avatar_data.avatar_id,&avatar_data,APT_PROPERTIES);
+ self->removePendingRequest(avatar_data.avatar_id, APT_PROPERTIES_LEGACY);
+ self->notifyObservers(avatar_data.avatar_id, &avatar_data, APT_PROPERTIES_LEGACY);
}
void LLAvatarPropertiesProcessor::processAvatarInterestsReply(LLMessageSystem* msg, void**)
{
/*
AvatarInterestsReply is automatically sent by the server in response to the
- AvatarPropertiesRequest sent when the panel is opened (in addition to the AvatarPropertiesReply message).
+ AvatarPropertiesRequest (in addition to the AvatarPropertiesReply message).
If the interests panel is no longer part of the design (?) we should just register the message
to a handler function that does nothing.
That will suppress the warnings and be compatible with old server versions.
WARNING: LLTemplateMessageReader::decodeData: Message from 216.82.37.237:13000 with no handler function received: AvatarInterestsReply
*/
-
- LLInterestsData interests_data;
-
- msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AgentID, interests_data.agent_id );
- msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AvatarID, interests_data.avatar_id );
- msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_WantToMask, interests_data.want_to_mask );
- msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_WantToText, interests_data.want_to_text );
- msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_SkillsMask, interests_data.skills_mask );
- msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_SkillsText, interests_data.skills_text );
- msg->getString( _PREHASH_PropertiesData, _PREHASH_LanguagesText, interests_data.languages_text );
-
- LLAvatarPropertiesProcessor* self = getInstance();
- // Request processed, no longer pending
- self->removePendingRequest(interests_data.avatar_id, APT_INTERESTS_INFO);
- self->notifyObservers(interests_data.avatar_id, &interests_data, APT_INTERESTS_INFO);
}
void LLAvatarPropertiesProcessor::processAvatarClassifiedsReply(LLMessageSystem* msg, void**)
@@ -497,7 +433,7 @@ void LLAvatarPropertiesProcessor::processAvatarClassifiedsReply(LLMessageSystem*
msg->getUUID(_PREHASH_Data, _PREHASH_ClassifiedID, data.classified_id, n);
msg->getString(_PREHASH_Data, _PREHASH_Name, data.name, n);
- classifieds.classifieds_list.push_back(data);
+ classifieds.classifieds_list.emplace_back(data);
}
LLAvatarPropertiesProcessor* self = getInstance();
@@ -537,39 +473,17 @@ void LLAvatarPropertiesProcessor::processClassifiedInfoReply(LLMessageSystem* ms
void LLAvatarPropertiesProcessor::processAvatarNotesReply(LLMessageSystem* msg, void**)
{
- LLAvatarNotes avatar_notes;
-
- msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_notes.agent_id);
- msg->getUUID(_PREHASH_Data, _PREHASH_TargetID, avatar_notes.target_id);
- msg->getString(_PREHASH_Data, _PREHASH_Notes, avatar_notes.notes);
-
- LLAvatarPropertiesProcessor* self = getInstance();
- // Request processed, no longer pending
- self->removePendingRequest(avatar_notes.target_id, APT_NOTES);
- self->notifyObservers(avatar_notes.target_id,&avatar_notes,APT_NOTES);
+ // Deprecated, new "AgentProfile" allows larger notes
}
void LLAvatarPropertiesProcessor::processAvatarPicksReply(LLMessageSystem* msg, void**)
{
- LLAvatarPicks avatar_picks;
- msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_picks.agent_id);
- msg->getUUID(_PREHASH_AgentData, _PREHASH_TargetID, avatar_picks.target_id);
+ LLUUID agent_id;
+ LLUUID target_id;
+ msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
+ msg->getUUID(_PREHASH_AgentData, _PREHASH_TargetID, target_id);
- S32 block_count = msg->getNumberOfBlocks(_PREHASH_Data);
- for (int block = 0; block < block_count; ++block)
- {
- LLUUID pick_id;
- std::string pick_name;
-
- msg->getUUID(_PREHASH_Data, _PREHASH_PickID, pick_id, block);
- msg->getString(_PREHASH_Data, _PREHASH_PickName, pick_name, block);
-
- avatar_picks.picks_list.push_back(std::make_pair(pick_id,pick_name));
- }
- LLAvatarPropertiesProcessor* self = getInstance();
- // Request processed, no longer pending
- self->removePendingRequest(avatar_picks.target_id, APT_PICKS);
- self->notifyObservers(avatar_picks.target_id,&avatar_picks,APT_PICKS);
+ LL_DEBUGS("AvatarProperties") << "Received AvatarPicksReply for " << target_id << LL_ENDL;
}
void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, void**)
@@ -604,44 +518,30 @@ void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, voi
void LLAvatarPropertiesProcessor::processAvatarGroupsReply(LLMessageSystem* msg, void**)
{
- LLAvatarGroups avatar_groups;
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, avatar_groups.agent_id );
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_groups.avatar_id );
+ /*
+ AvatarGroupsReply is automatically sent by the server in response to the
+ AvatarPropertiesRequest in addition to the AvatarPropertiesReply message.
+ */
+ LLUUID agent_id;
+ LLUUID avatar_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_id);
- S32 group_count = msg->getNumberOfBlocksFast(_PREHASH_GroupData);
- for(S32 i = 0; i < group_count; ++i)
- {
- LLAvatarGroups::LLGroupData group_data;
-
- msg->getU64( _PREHASH_GroupData, _PREHASH_GroupPowers, group_data.group_powers, i );
- msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupTitle, group_data.group_title, i );
- msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupID, group_data.group_id, i);
- msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName, group_data.group_name, i );
- msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupInsigniaID, group_data.group_insignia_id, i );
-
- avatar_groups.group_list.push_back(group_data);
- }
-
- LLAvatarPropertiesProcessor* self = getInstance();
- self->removePendingRequest(avatar_groups.avatar_id, APT_GROUPS);
- self->notifyObservers(avatar_groups.avatar_id,&avatar_groups,APT_GROUPS);
+ LL_DEBUGS("AvatarProperties") << "Received AvatarGroupsReply for " << avatar_id << LL_ENDL;
}
-void LLAvatarPropertiesProcessor::notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type)
+void LLAvatarPropertiesProcessor::notifyObservers(const LLUUID& id, void* data, EAvatarProcessorType type)
{
// Copy the map (because observers may delete themselves when updated?)
LLAvatarPropertiesProcessor::observer_multimap_t observers = mObservers;
- observer_multimap_t::iterator oi = observers.begin();
- observer_multimap_t::iterator end = observers.end();
- for (; oi != end; ++oi)
+ for (const auto& [agent_id, observer] : observers)
{
// only notify observers for the same agent, or if the observer
// didn't know the agent ID and passed a NULL id.
- const LLUUID &agent_id = oi->first;
if (agent_id == id || agent_id.isNull())
{
- oi->second->processProperties(data,type);
+ observer->processProperties(data, type);
}
}
}
@@ -655,8 +555,8 @@ void LLAvatarPropertiesProcessor::sendFriendRights(const LLUUID& avatar_id, S32
// setup message header
msg->newMessageFast(_PREHASH_GrantUserRights);
msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUID(_PREHASH_AgentID, gAgent.getID());
- msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUID(_PREHASH_AgentID, gAgentID);
+ msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlockFast(_PREHASH_Rights);
msg->addUUID(_PREHASH_AgentRelated, avatar_id);
@@ -666,34 +566,13 @@ void LLAvatarPropertiesProcessor::sendFriendRights(const LLUUID& avatar_id, S32
}
}
-void LLAvatarPropertiesProcessor::sendNotes(const LLUUID& avatar_id, const std::string notes)
-{
- if(!avatar_id.isNull())
- {
- LLMessageSystem* msg = gMessageSystem;
-
- // setup message header
- msg->newMessageFast(_PREHASH_AvatarNotesUpdate);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUID(_PREHASH_AgentID, gAgent.getID());
- msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
-
- msg->nextBlockFast(_PREHASH_Data);
- msg->addUUID(_PREHASH_TargetID, avatar_id);
- msg->addString(_PREHASH_Notes, notes);
-
- gAgent.sendReliableMessage();
- }
-}
-
-
void LLAvatarPropertiesProcessor::sendPickDelete( const LLUUID& pick_id )
{
LLMessageSystem* msg = gMessageSystem;
msg->newMessage(_PREHASH_PickDelete);
msg->nextBlock(_PREHASH_AgentData);
- msg->addUUID(_PREHASH_AgentID, gAgent.getID());
- msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUID(_PREHASH_AgentID, gAgentID);
+ msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlock(_PREHASH_Data);
msg->addUUID(_PREHASH_PickID, pick_id);
gAgent.sendReliableMessage();
@@ -709,8 +588,8 @@ void LLAvatarPropertiesProcessor::sendClassifiedDelete(const LLUUID& classified_
msg->newMessage(_PREHASH_ClassifiedDelete);
msg->nextBlock(_PREHASH_AgentData);
- msg->addUUID(_PREHASH_AgentID, gAgent.getID());
- msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUID(_PREHASH_AgentID, gAgentID);
+ msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlock(_PREHASH_Data);
msg->addUUID(_PREHASH_ClassifiedID, classified_id);
@@ -718,39 +597,17 @@ void LLAvatarPropertiesProcessor::sendClassifiedDelete(const LLUUID& classified_
gAgent.sendReliableMessage();
}
-void LLAvatarPropertiesProcessor::sendInterestsInfoUpdate(const LLInterestsData* interests_data)
-{
- if(!interests_data)
- {
- return;
- }
-
- LLMessageSystem* msg = gMessageSystem;
-
- msg->newMessage(_PREHASH_AvatarInterestsUpdate);
- msg->nextBlockFast( _PREHASH_AgentData);
- msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() );
- msg->addUUIDFast( _PREHASH_SessionID, gAgent.getSessionID() );
- msg->nextBlockFast( _PREHASH_PropertiesData);
- msg->addU32Fast( _PREHASH_WantToMask, interests_data->want_to_mask);
- msg->addStringFast( _PREHASH_WantToText, interests_data->want_to_text);
- msg->addU32Fast( _PREHASH_SkillsMask, interests_data->skills_mask);
- msg->addStringFast( _PREHASH_SkillsText, interests_data->skills_text);
- msg->addString( _PREHASH_LanguagesText, interests_data->languages_text);
-
- gAgent.sendReliableMessage();
-}
-
void LLAvatarPropertiesProcessor::sendPickInfoUpdate(const LLPickData* new_pick)
{
- if (!new_pick) return;
+ if (!new_pick)
+ return;
LLMessageSystem* msg = gMessageSystem;
msg->newMessage(_PREHASH_PickInfoUpdate);
msg->nextBlock(_PREHASH_AgentData);
- msg->addUUID(_PREHASH_AgentID, gAgent.getID());
- msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUID(_PREHASH_AgentID, gAgentID);
+ msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlock(_PREHASH_Data);
msg->addUUID(_PREHASH_PickID, new_pick->pick_id);
@@ -787,8 +644,8 @@ void LLAvatarPropertiesProcessor::sendClassifiedInfoUpdate(const LLAvatarClassif
msg->newMessage(_PREHASH_ClassifiedInfoUpdate);
msg->nextBlock(_PREHASH_AgentData);
- msg->addUUID(_PREHASH_AgentID, gAgent.getID());
- msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUID(_PREHASH_AgentID, gAgentID);
+ msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlock(_PREHASH_Data);
msg->addUUID(_PREHASH_ClassifiedID, c_data->classified_id);
@@ -809,9 +666,7 @@ void LLAvatarPropertiesProcessor::sendPickInfoRequest(const LLUUID& creator_id,
{
// Must ask for a pick based on the creator id because
// the pick database is distributed to the inventory cluster. JC
- std::vector request_params;
- request_params.push_back(creator_id.asString() );
- request_params.push_back(pick_id.asString() );
+ std::vector request_params{ creator_id.asString(), pick_id.asString() };
send_generic_message("pickinforequest", request_params);
}
@@ -822,8 +677,8 @@ void LLAvatarPropertiesProcessor::sendClassifiedInfoRequest(const LLUUID& classi
msg->newMessage(_PREHASH_ClassifiedInfoRequest);
msg->nextBlock(_PREHASH_AgentData);
- msg->addUUID(_PREHASH_AgentID, gAgent.getID());
- msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUID(_PREHASH_AgentID, gAgentID);
+ msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlock(_PREHASH_Data);
msg->addUUID(_PREHASH_ClassifiedID, classified_id);
@@ -840,7 +695,7 @@ bool LLAvatarPropertiesProcessor::isPendingRequest(const LLUUID& avatar_id, EAva
if (it == mRequestTimestamps.end()) return false;
// We found a request, check if it has timed out
- U32 now = time(NULL);
+ U32 now = time(nullptr);
const U32 REQUEST_EXPIRE_SECS = 5;
U32 expires = it->second + REQUEST_EXPIRE_SECS;
@@ -854,7 +709,7 @@ bool LLAvatarPropertiesProcessor::isPendingRequest(const LLUUID& avatar_id, EAva
void LLAvatarPropertiesProcessor::addPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type)
{
timestamp_map_t::key_type key = std::make_pair(avatar_id, type);
- U32 now = time(NULL);
+ U32 now = time(nullptr);
// Add or update existing (expired) request
mRequestTimestamps[ key ] = now;
}
diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h
index 77bf5fd51e..0a1445419e 100644
--- a/indra/newview/llavatarpropertiesprocessor.h
+++ b/indra/newview/llavatarpropertiesprocessor.h
@@ -50,26 +50,34 @@ class LLMessageSystem;
enum EAvatarProcessorType
{
- APT_PROPERTIES,
- APT_NOTES,
- APT_GROUPS,
- APT_PICKS,
+ APT_PROPERTIES_LEGACY, // APT_PROPERTIES via udp request (Truncates data!!!)
+ APT_PROPERTIES, // APT_PROPERTIES via http request
APT_PICK_INFO,
APT_TEXTURES,
- APT_INTERESTS_INFO,
APT_CLASSIFIEDS,
APT_CLASSIFIED_INFO
};
-struct LLInterestsData
+// legacy data is supposed to match AvatarPropertiesReply,
+// but it is obsolete, fields like about_text will truncate
+// data, if you need them, use AgenProfile cap.
+// Todo: remove it once once icon ids get moved elsewhere,
+// since AgentProfile is too large for bulk icon requests
+struct LLAvatarLegacyData
{
LLUUID agent_id;
LLUUID avatar_id; //target id
- U32 want_to_mask;
- std::string want_to_text;
- U32 skills_mask;
- std::string skills_text;
- std::string languages_text;
+ LLUUID image_id;
+ LLUUID fl_image_id;
+ LLUUID partner_id;
+ std::string about_text;
+ std::string fl_about_text;
+ LLDate born_on;
+ std::string profile_url;
+ U8 caption_index;
+ std::string caption_text;
+ std::string customer_type;
+ U32 flags;
};
struct LLAvatarData
@@ -87,19 +95,28 @@ struct LLAvatarData
std::string caption_text;
std::string customer_type;
U32 flags;
- BOOL allow_publish;
-};
+ bool hide_age;
+ std::string notes;
-struct LLAvatarPicks
-{
- LLUUID agent_id;
- LLUUID target_id; //target id
+ struct LLGroupData;
+ typedef std::list group_list_t;
+ group_list_t group_list;
- typedef std::pair pick_data_t;
+ typedef std::pair pick_data_t;
typedef std::list< pick_data_t> picks_list_t;
picks_list_t picks_list;
};
+struct LLAvatarData::LLGroupData
+{
+ U64 group_powers;
+ BOOL accept_notices;
+ std::string group_title;
+ LLUUID group_id;
+ std::string group_name;
+ LLUUID group_insignia_id;
+};
+
struct LLPickData
{
LLUUID agent_id;
@@ -121,36 +138,6 @@ struct LLPickData
//used only in write (update) requests
LLUUID session_id;
-
-};
-
-struct LLAvatarNotes
-{
- LLUUID agent_id;
- LLUUID target_id; //target id
- std::string notes;
-};
-
-struct LLAvatarGroups
-{
- LLUUID agent_id;
- LLUUID avatar_id; //target id
- BOOL list_in_profile;
-
- struct LLGroupData;
- typedef std::list group_list_t;
-
- group_list_t group_list;
-
- struct LLGroupData
- {
- U64 group_powers;
- BOOL accept_notices;
- std::string group_title;
- LLUUID group_id;
- std::string group_name;
- LLUUID group_insignia_id;
- };
};
struct LLAvatarClassifieds
@@ -211,9 +198,7 @@ public:
// Request various types of avatar data. Duplicate requests will be
// suppressed while waiting for a response from the network.
void sendAvatarPropertiesRequest(const LLUUID& avatar_id);
- void sendAvatarPicksRequest(const LLUUID& avatar_id);
- void sendAvatarNotesRequest(const LLUUID& avatar_id);
- void sendAvatarGroupsRequest(const LLUUID& avatar_id);
+ void sendAvatarLegacyPropertiesRequest(const LLUUID& avatar_id);
void sendAvatarTexturesRequest(const LLUUID& avatar_id);
void sendAvatarClassifiedsRequest(const LLUUID& avatar_id);
@@ -222,21 +207,17 @@ public:
void sendClassifiedInfoRequest(const LLUUID& classified_id);
- void sendAvatarPropertiesUpdate(const LLAvatarData* avatar_props);
-
void sendPickInfoUpdate(const LLPickData* new_pick);
void sendClassifiedInfoUpdate(const LLAvatarClassifiedInfo* c_data);
void sendFriendRights(const LLUUID& avatar_id, S32 rights);
- void sendNotes(const LLUUID& avatar_id, const std::string notes);
-
void sendPickDelete(const LLUUID& pick_id);
void sendClassifiedDelete(const LLUUID& classified_id);
- void sendInterestsInfoUpdate(const LLInterestsData* interests_data);
+ bool isHideAgeSupportedByServer() { return mIsHideAgeSupportedByServer; }
// Returns translated, human readable string for account type, such
// as "Resident" or "Linden Employee". Used for profiles, inspectors.
@@ -249,9 +230,10 @@ public:
static bool hasPaymentInfoOnFile(const LLAvatarData* avatar_data);
- static void requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id);
+ static void requestAvatarPropertiesCoro(std::string cap_url, LLUUID avatar_id, EAvatarProcessorType type);
- static void processAvatarPropertiesReply(LLMessageSystem* msg, void**);
+ // Processing of UDP variant of properties, truncates certain fields!
+ static void processAvatarLegacyPropertiesReply(LLMessageSystem* msg, void**);
static void processAvatarInterestsReply(LLMessageSystem* msg, void**);
@@ -272,7 +254,7 @@ protected:
void sendRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method);
void sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method);
void sendAvatarPropertiesRequestMessage(const LLUUID& avatar_id);
- void initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url);
+ void initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url, EAvatarProcessorType type);
void notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type);
@@ -302,6 +284,9 @@ protected:
// Map avatar_id+request_type -> U32 timestamp in seconds
typedef std::map< std::pair, U32> timestamp_map_t;
timestamp_map_t mRequestTimestamps;
+
+ // Is returned by isHideAgeSupportedByServer()
+ bool mIsHideAgeSupportedByServer { false };
};
#endif // LL_LLAVATARPROPERTIESPROCESSOR_H
diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp
index 1b2581a03c..f66a9865fc 100644
--- a/indra/newview/llchannelmanager.cpp
+++ b/indra/newview/llchannelmanager.cpp
@@ -88,7 +88,7 @@ LLScreenChannel* LLChannelManager::createNotificationChannel()
{
// creating params for a channel
LLScreenChannelBase::Params p;
- p.id = LLUUID(gSavedSettings.getString("NotificationChannelUUID"));
+ p.id = NOTIFICATION_CHANNEL_UUID;
p.channel_align = CA_RIGHT;
p.toast_align = NA_TOP;
@@ -108,7 +108,7 @@ void LLChannelManager::onLoginCompleted()
if (!channel) continue;
// don't calc notifications for Nearby Chat
- if(channel->getChannelID() == LLUUID(gSavedSettings.getString("NearByChatChannelUUID")))
+ if(channel->getChannelID() == NEARBY_CHAT_CHANNEL_UUID)
{
continue;
}
@@ -130,7 +130,7 @@ void LLChannelManager::onLoginCompleted()
{
// create a channel for the StartUp Toast
LLScreenChannelBase::Params p;
- p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID"));
+ p.id = STARTUP_CHANNEL_UUID;
p.channel_align = CA_RIGHT;
mStartUpChannel = createChannel(p);
@@ -144,8 +144,7 @@ void LLChannelManager::onLoginCompleted()
// 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->init(channel_right_bound - NOTIFY_BOX_WIDTH, channel_right_bound);
mStartUpChannel->setMouseDownCallback(boost::bind(&LLFloaterNotificationsTabbed::onStartUpToastClick, LLFloaterNotificationsTabbed::getInstance(), _2, _3, _4));
mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this));
@@ -164,7 +163,7 @@ void LLChannelManager::onStartUpToastClose()
{
mStartUpChannel->setVisible(FALSE);
mStartUpChannel->closeStartUpToast();
- removeChannelByID(LLUUID(gSavedSettings.getString("StartUpChannelUUID")));
+ removeChannelByID(STARTUP_CHANNEL_UUID);
mStartUpChannel = NULL;
}
@@ -258,12 +257,12 @@ LLNotificationsUI::LLScreenChannel* LLChannelManager::getNotificationScreenChann
{
LLNotificationsUI::LLScreenChannel* channel = static_cast
(LLNotificationsUI::LLChannelManager::getInstance()->
- findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+ findChannelByID(NOTIFICATION_CHANNEL_UUID));
if (channel == NULL)
{
- LL_WARNS() << "Can't find screen channel by NotificationChannelUUID" << LL_ENDL;
- llassert(!"Can't find screen channel by NotificationChannelUUID");
+ LL_WARNS() << "Can't find screen channel by Notification Channel UUID" << LL_ENDL;
+ llassert(!"Can't find screen channel by Notification Channel UUID");
}
return channel;
diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp
index 67090772fd..c43864d85f 100644
--- a/indra/newview/llcofwearables.cpp
+++ b/indra/newview/llcofwearables.cpp
@@ -142,7 +142,7 @@ protected:
registrar.add("Attachment.Touch", boost::bind(handleMultiple, handle_attachment_touch, mUUIDs));
registrar.add("Attachment.Edit", boost::bind(handleMultiple, handle_item_edit, mUUIDs));
- registrar.add("Attachment.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs));
+ registrar.add("Attachment.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs, no_op));
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
enable_registrar.add("Attachment.OnEnable", boost::bind(&CofAttachmentContextMenu::onEnable, this, _2));
@@ -195,7 +195,7 @@ protected:
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
LLUUID selected_id = mUUIDs.back();
- registrar.add("Clothing.TakeOff", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs));
+ registrar.add("Clothing.TakeOff", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs, no_op));
registrar.add("Clothing.Replace", boost::bind(replaceWearable, selected_id));
registrar.add("Clothing.Edit", boost::bind(LLAgentWearables::editWearable, selected_id));
registrar.add("Clothing.Create", boost::bind(&CofClothingContextMenu::createNew, this, selected_id));
diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp
index eebef4cc1c..0006a48de5 100644
--- a/indra/newview/llcompilequeue.cpp
+++ b/indra/newview/llcompilequeue.cpp
@@ -66,6 +66,7 @@ namespace
{
const std::string QUEUE_EVENTPUMP_NAME("ScriptActionQueue");
+ const F32 QUEUE_INVENTORY_FETCH_TIMEOUT = 300.f;
// ObjectIventoryFetcher is an adapter between the LLVOInventoryListener::inventoryChanged
// callback mechanism and the LLEventPump coroutine architecture allowing the
@@ -359,8 +360,6 @@ bool LLFloaterCompileQueue::processScript(LLHandle hfloat
// Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
// which is caught in objectScriptProcessingQueueCoro
bool monocompile = floater->mMono;
- F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout");
-
// Initial test to see if we can (or should) attempt to compile the script.
LLInventoryItem *item = dynamic_cast(inventory);
@@ -385,7 +384,7 @@ bool LLFloaterCompileQueue::processScript(LLHandle hfloat
LLExperienceCache::instance().fetchAssociatedExperience(inventory->getParentUUID(), inventory->getUUID(),
boost::bind(&LLFloaterCompileQueue::handleHTTPResponse, pump.getName(), _1));
- result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout,
+ result = llcoro::suspendUntilEventOnWithTimeout(pump, QUEUE_INVENTORY_FETCH_TIMEOUT,
LLSDMap("timeout", LLSD::Boolean(true)));
floater.check();
@@ -435,7 +434,7 @@ bool LLFloaterCompileQueue::processScript(LLHandle hfloat
&LLFloaterCompileQueue::handleScriptRetrieval,
&userData);
- result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout,
+ result = llcoro::suspendUntilEventOnWithTimeout(pump, QUEUE_INVENTORY_FETCH_TIMEOUT,
LLSDMap("timeout", LLSD::Boolean(true)));
}
@@ -481,7 +480,7 @@ bool LLFloaterCompileQueue::processScript(LLHandle hfloat
LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
}
- result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, LLSDMap("timeout", LLSD::Boolean(true)));
+ result = llcoro::suspendUntilEventOnWithTimeout(pump, QUEUE_INVENTORY_FETCH_TIMEOUT, LLSDMap("timeout", LLSD::Boolean(true)));
floater.check();
@@ -736,8 +735,6 @@ void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, L
// Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
// This is expected if the dialog closes.
LLEventMailDrop maildrop(QUEUE_EVENTPUMP_NAME, true);
- F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout");
-
try
{
@@ -759,7 +756,7 @@ void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, L
args["[OBJECT_NAME]"] = (*itObj).mObjectName;
floater->addStringMessage(floater->getString("LoadingObjInv", args));
- LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, fetch_timeout,
+ LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, QUEUE_INVENTORY_FETCH_TIMEOUT,
LLSDMap("timeout", LLSD::Boolean(true)));
if (result.has("timeout"))
diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index d900730e98..b7317272a1 100644
--- a/indra/newview/llcontrolavatar.cpp
+++ b/indra/newview/llcontrolavatar.cpp
@@ -137,9 +137,9 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_
{
LLVector3 pos_box_offset = point_to_box_offset(vol_pos, unshift_extents);
F32 offset_dist = pos_box_offset.length();
- if (offset_dist > max_legal_offset && offset_dist > 0.f)
+ if (offset_dist > MAX_LEGAL_OFFSET && offset_dist > 0.f)
{
- F32 target_dist = (offset_dist - max_legal_offset);
+ F32 target_dist = (offset_dist - MAX_LEGAL_OFFSET);
new_pos_fixup = (target_dist/offset_dist)*pos_box_offset;
}
if (new_pos_fixup != mPositionConstraintFixup)
@@ -152,11 +152,11 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_
}
}
- if (box_size/mScaleConstraintFixup > max_legal_size)
+ if (box_size/mScaleConstraintFixup > MAX_LEGAL_SIZE)
{
- new_scale_fixup = mScaleConstraintFixup*max_legal_size/box_size;
+ new_scale_fixup = mScaleConstraintFixup* MAX_LEGAL_SIZE /box_size;
LL_DEBUGS("ConstraintFix") << getFullname() << " scale fix, box_size " << box_size << " fixup "
- << mScaleConstraintFixup << " max legal " << max_legal_size
+ << mScaleConstraintFixup << " max legal " << MAX_LEGAL_SIZE
<< " -> new scale " << new_scale_fixup << LL_ENDL;
}
}
@@ -201,8 +201,7 @@ void LLControlAvatar::matchVolumeTransform()
mRoot->setWorldRotation(obj_rot * joint_rot);
setRotation(mRoot->getRotation());
- F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale");
- setGlobalScale(global_scale * mScaleConstraintFixup);
+ setGlobalScale(mScaleConstraintFixup);
}
else
{
@@ -252,8 +251,7 @@ void LLControlAvatar::matchVolumeTransform()
}
mRoot->setPosition(vol_pos + mPositionConstraintFixup);
- F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale");
- setGlobalScale(global_scale * mScaleConstraintFixup);
+ setGlobalScale(mScaleConstraintFixup);
}
}
}
diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h
index ecd035c23b..3a3c26f955 100644
--- a/indra/newview/llconversationmodel.h
+++ b/indra/newview/llconversationmodel.h
@@ -82,7 +82,7 @@ public:
virtual BOOL isItemRenameable() const { return TRUE; }
virtual BOOL renameItem(const std::string& new_name) { mName = new_name; mNeedsRefresh = true; return TRUE; }
virtual BOOL isItemMovable( void ) const { return FALSE; }
- virtual BOOL isItemRemovable( void ) const { return FALSE; }
+ virtual BOOL isItemRemovable(bool check_worn = true) const { return FALSE; }
virtual BOOL isItemInTrash( void) const { return FALSE; }
virtual BOOL removeItem() { return FALSE; }
virtual void removeBatch(std::vector& batch) { }
diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp
index 217f29bffb..1abebc996b 100644
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -106,6 +106,8 @@ LLConversationViewSession::~LLConversationViewSession()
}
mFlashTimer->unset();
+ delete mFlashTimer;
+ mFlashStateOn = false;
}
void LLConversationViewSession::destroyView()
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 247a487ace..3c0a523317 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -2116,7 +2116,7 @@ void LLEnvironment::coroRequestEnvironment(S32 parcel_id, LLEnvironment::environ
{
LL_WARNS("ENVIRONMENT") << "Couldn't retrieve environment settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL;
}
- else if (LLApp::isExiting())
+ else if (LLApp::isExiting() || gDisconnected)
{
return;
}
diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp
index 9e526f8c52..7ac90a04db 100644
--- a/indra/newview/llexpandabletextbox.cpp
+++ b/indra/newview/llexpandabletextbox.cpp
@@ -243,6 +243,12 @@ LLExpandableTextBox::LLExpandableTextBox(const Params& p)
mTextBox->setCommitCallback(boost::bind(&LLExpandableTextBox::onExpandClicked, this));
}
+
+LLExpandableTextBox::~LLExpandableTextBox()
+{
+ gViewerWindow->removePopup(this);
+}
+
void LLExpandableTextBox::draw()
{
if(mBGVisible && !mExpanded)
diff --git a/indra/newview/llexpandabletextbox.h b/indra/newview/llexpandabletextbox.h
index 385bb35017..d992f3131a 100644
--- a/indra/newview/llexpandabletextbox.h
+++ b/indra/newview/llexpandabletextbox.h
@@ -121,7 +121,7 @@ public:
/**
* Returns text
*/
- virtual std::string getText() const { return mText; }
+ virtual const std::string& getText() const { return mText; }
/**
* Sets text
@@ -154,6 +154,8 @@ public:
*/
/*virtual*/ void draw();
+ virtual ~LLExpandableTextBox();
+
protected:
LLExpandableTextBox(const Params& p);
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 96ab5da318..51b9923684 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -632,6 +632,9 @@ std::unique_ptr> LLFilePicker::navOpenFilterProc(ELoadF
switch(filter)
{
case FFLOAD_ALL:
+ case FFLOAD_EXE:
+ allowedv->push_back("app");
+ allowedv->push_back("exe");
allowedv->push_back("wav");
allowedv->push_back("bvh");
allowedv->push_back("anim");
@@ -652,9 +655,6 @@ std::unique_ptr> LLFilePicker::navOpenFilterProc(ELoadF
allowedv->push_back("tpic");
allowedv->push_back("png");
break;
- case FFLOAD_EXE:
- allowedv->push_back("app");
- allowedv->push_back("exe");
break;
case FFLOAD_WAV:
allowedv->push_back("wav");
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index cf665ca87d..f903b1bd8d 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -107,15 +107,11 @@ LLFloaterAvatarPicker::LLFloaterAvatarPicker(const LLSD& key)
mCloseOnSelect(FALSE),
mExcludeAgentFromSearchResults(FALSE),
mContextConeOpacity (0.f),
- mContextConeInAlpha(0.f),
- mContextConeOutAlpha(0.f),
- mContextConeFadeTime(0.f)
+ mContextConeInAlpha(CONTEXT_CONE_IN_ALPHA),
+ mContextConeOutAlpha(CONTEXT_CONE_OUT_ALPHA),
+ mContextConeFadeTime(CONTEXT_CONE_FADE_TIME)
{
mCommitCallbackRegistrar.add("Refresh.FriendList", boost::bind(&LLFloaterAvatarPicker::populateFriend, this));
-
- mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
- mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
- mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
}
BOOL LLFloaterAvatarPicker::postBuild()
diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp
index 7e413e35d6..8ad13367c0 100644
--- a/indra/newview/llfloatercolorpicker.cpp
+++ b/indra/newview/llfloatercolorpicker.cpp
@@ -102,9 +102,9 @@ LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show
mActive ( TRUE ),
mCanApplyImmediately ( show_apply_immediate ),
mContextConeOpacity ( 0.f ),
- mContextConeInAlpha ( 0.f ),
- mContextConeOutAlpha ( 0.f ),
- mContextConeFadeTime ( 0.f )
+ mContextConeInAlpha (CONTEXT_CONE_IN_ALPHA),
+ mContextConeOutAlpha (CONTEXT_CONE_OUT_ALPHA),
+ mContextConeFadeTime (CONTEXT_CONE_FADE_TIME)
{
buildFromFile ( "floater_color_picker.xml");
@@ -116,10 +116,6 @@ LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show
mApplyImmediateCheck->setEnabled(FALSE);
mApplyImmediateCheck->set(FALSE);
}
-
- mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
- mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
- mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
}
LLFloaterColorPicker::~LLFloaterColorPicker()
diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp
index 9960864a60..92bf91ab05 100644
--- a/indra/newview/llfloaterconversationpreview.cpp
+++ b/indra/newview/llfloaterconversationpreview.cpp
@@ -37,13 +37,14 @@
const std::string LL_FCP_COMPLETE_NAME("complete_name");
const std::string LL_FCP_ACCOUNT_NAME("user_name");
+const S32 CONVERSATION_HISTORY_PAGE_SIZE = 100;
LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_id)
: LLFloater(session_id),
mChatHistory(NULL),
mSessionID(session_id.asUUID()),
mCurrentPage(0),
- mPageSize(gSavedSettings.getS32("ConversationHistoryPageSize")),
+ mPageSize(CONVERSATION_HISTORY_PAGE_SIZE),
mAccountName(session_id[LL_FCP_ACCOUNT_NAME]),
mCompleteName(session_id[LL_FCP_COMPLETE_NAME]),
mMutex(),
diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp
index 0abc14262e..78b94d1b0c 100644
--- a/indra/newview/llfloateremojipicker.cpp
+++ b/indra/newview/llfloateremojipicker.cpp
@@ -39,8 +39,9 @@
#include "llscrolllistctrl.h"
#include "llscrolllistitem.h"
#include "llsdserialize.h"
-#include "lltextbox.h"
-#include "llviewerchat.h"
+#include "lltextbox.h"
+#include "lltrans.h"
+#include "llviewerchat.h"
namespace {
// The following variables and constants are used for storing the floater state
@@ -128,7 +129,7 @@ public:
, const LLEmojiSearchResult& emoji)
: LLScrollingPanel(panel_params)
, mData(emoji)
- , mText(LLWString(1, emoji.Character))
+ , mChar(LLWString(1, emoji.Character))
{
}
@@ -138,8 +139,8 @@ public:
F32 x = getRect().getWidth() / 2;
F32 y = getRect().getHeight() / 2;
- LLFontGL::getFontEmoji()->render(
- mText, // wstr
+ LLFontGL::getFontEmojiLarge()->render(
+ mChar, // wstr
0, // begin_offset
x, // x
y, // y
@@ -154,11 +155,11 @@ public:
virtual void updatePanel(BOOL allow_modify) override {}
const LLEmojiSearchResult& getData() const { return mData; }
- LLWString getText() const { return mText; }
+ const LLWString& getChar() const { return mChar; }
private:
const LLEmojiSearchResult mData;
- const LLWString mText;
+ const LLWString mChar;
};
class LLEmojiPreviewPanel : public LLPanel
@@ -229,7 +230,7 @@ protected:
{
F32 x0 = x;
F32 x1 = max_pixels;
- LLFontGL* font = LLFontGL::getFontEmoji();
+ LLFontGL* font = LLFontGL::getFontEmojiLarge();
if (mBegin)
{
std::string text = mTitle.substr(0, mBegin);
@@ -332,6 +333,14 @@ void LLFloaterEmojiPicker::onOpen(const LLSD& key)
gFloaterView->adjustToFitScreen(this, FALSE);
}
+void LLFloaterEmojiPicker::onClose(bool app_quitting)
+{
+ if (!app_quitting)
+ {
+ LLEmojiHelper::instance().hideHelper(nullptr, true);
+ }
+}
+
void LLFloaterEmojiPicker::dirtyRect()
{
super::dirtyRect();
@@ -388,9 +397,12 @@ void LLFloaterEmojiPicker::initialize()
}
else
{
- const std::string prompt("No emoji found for ");
- std::string title(prompt + '"' + mFilterPattern.substr(1) + '"');
- mPreview->setData(EMPTY_LIST_IMAGE_INDEX, title, prompt.size() + 1, title.size() - 1);
+ std::size_t begin, end;
+ LLStringUtil::format_map_t args;
+ args["[FILTER]"] = mFilterPattern.substr(1);
+ std::string title(getString("text_no_emoji_for_filter", args));
+ LLEmojiDictionary::searchInShortCode(begin, end, title, mFilterPattern);
+ mPreview->setData(EMPTY_LIST_IMAGE_INDEX, title, begin, end);
showPreview(true);
}
return;
@@ -423,7 +435,7 @@ void LLFloaterEmojiPicker::fillGroups()
mGroupButtons.clear();
LLButton::Params params;
- params.font = LLFontGL::getFontEmoji();
+ params.font = LLFontGL::getFontEmojiLarge();
LLRect rect;
rect.mTop = mGroups->getRect().getHeight();
@@ -485,10 +497,12 @@ void LLFloaterEmojiPicker::fillCategoryRecentlyUsed(std::mapsecond->ShortCodes.empty())
{
- const std::string shortcode(e2d->second->ShortCodes.front());
- if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern))
+ for (const std::string& shortcode : e2d->second->ShortCodes)
{
- emojis.emplace_back(emoji, shortcode, begin, end);
+ if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern))
+ {
+ emojis.emplace_back(emoji, shortcode, begin, end);
+ }
}
}
}
@@ -517,10 +531,12 @@ void LLFloaterEmojiPicker::fillCategoryFrequentlyUsed(std::mapsecond->ShortCodes.empty())
{
- const std::string shortcode(e2d->second->ShortCodes.front());
- if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern))
+ for (const std::string& shortcode : e2d->second->ShortCodes)
{
- emojis.emplace_back(emoji.first, shortcode, begin, end);
+ if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern))
+ {
+ emojis.emplace_back(emoji.first, shortcode, begin, end);
+ }
}
}
}
@@ -553,10 +569,12 @@ void LLFloaterEmojiPicker::fillGroupEmojis(std::mapShortCodes.empty())
{
- const std::string shortcode(descr->ShortCodes.front());
- if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern))
+ for (const std::string& shortcode : descr->ShortCodes)
{
- emojis.emplace_back(descr->Character, shortcode, begin, end);
+ if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern))
+ {
+ emojis.emplace_back(descr->Character, shortcode, begin, end);
+ }
}
}
}
@@ -924,7 +942,7 @@ void LLFloaterEmojiPicker::onEmojiMouseUp(LLUICtrl* ctrl)
if (LLEmojiGridIcon* icon = dynamic_cast(ctrl))
{
- LLSD value(wstring_to_utf8str(icon->getText()));
+ LLSD value(wstring_to_utf8str(icon->getChar()));
setValue(value);
onCommit();
diff --git a/indra/newview/llfloateremojipicker.h b/indra/newview/llfloateremojipicker.h
index 82faaf821b..05b4826e37 100644
--- a/indra/newview/llfloateremojipicker.h
+++ b/indra/newview/llfloateremojipicker.h
@@ -94,6 +94,7 @@ private:
void unselectGridIcon(LLEmojiGridIcon* icon);
void onOpen(const LLSD& key) override;
+ void onClose(bool app_quitting) override;
virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent) override;
class LLPanel* mGroups { nullptr };
diff --git a/indra/newview/llfloaterexperiencepicker.cpp b/indra/newview/llfloaterexperiencepicker.cpp
index 668143933c..93eaa6b64b 100644
--- a/indra/newview/llfloaterexperiencepicker.cpp
+++ b/indra/newview/llfloaterexperiencepicker.cpp
@@ -88,13 +88,10 @@ LLFloaterExperiencePicker::LLFloaterExperiencePicker( const LLSD& key )
:LLFloater(key)
,mSearchPanel(NULL)
,mContextConeOpacity(0.f)
- ,mContextConeInAlpha(0.f)
- ,mContextConeOutAlpha(0.f)
- ,mContextConeFadeTime(0.f)
+ ,mContextConeInAlpha(CONTEXT_CONE_IN_ALPHA)
+ ,mContextConeOutAlpha(CONTEXT_CONE_OUT_ALPHA)
+ ,mContextConeFadeTime(CONTEXT_CONE_FADE_TIME)
{
- mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
- mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
- mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
}
LLFloaterExperiencePicker::~LLFloaterExperiencePicker()
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index 98842eed77..73adb2175a 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -342,55 +342,63 @@ void LLFloaterImagePreview::draw()
//-----------------------------------------------------------------------------
bool LLFloaterImagePreview::loadImage(const std::string& src_filename)
{
- std::string exten = gDirUtilp->getExtension(src_filename);
- U32 codec = LLImageBase::getCodecFromExtension(exten);
-
- LLImageDimensionsInfo image_info;
- if (!image_info.load(src_filename,codec))
+ try
{
- mImageLoadError = image_info.getLastError();
+ std::string exten = gDirUtilp->getExtension(src_filename);
+ U32 codec = LLImageBase::getCodecFromExtension(exten);
+
+ LLImageDimensionsInfo image_info;
+ if (!image_info.load(src_filename, codec))
+ {
+ mImageLoadError = image_info.getLastError();
+ return false;
+ }
+
+ S32 max_width = gSavedSettings.getS32("max_texture_dimension_X");
+ S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y");
+
+ if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height))
+ {
+ LLStringUtil::format_map_t args;
+ args["WIDTH"] = llformat("%d", max_width);
+ args["HEIGHT"] = llformat("%d", max_height);
+
+ mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args);
+ return false;
+ }
+
+ // Load the image
+ LLPointer image = LLImageFormatted::createFromType(codec);
+ if (image.isNull())
+ {
+ return false;
+ }
+ if (!image->load(src_filename))
+ {
+ return false;
+ }
+ // Decompress or expand it in a raw image structure
+ LLPointer raw_image = new LLImageRaw;
+ if (!image->decode(raw_image, 0.0f))
+ {
+ return false;
+ }
+ // Check the image constraints
+ if ((image->getComponents() != 3) && (image->getComponents() != 4))
+ {
+ image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
+ return false;
+ }
+
+ raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+ mRawImagep = raw_image;
+ }
+ catch (...)
+ {
+ LOG_UNHANDLED_EXCEPTION("");
return false;
}
- S32 max_width = gSavedSettings.getS32("max_texture_dimension_X");
- S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y");
-
- if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height))
- {
- LLStringUtil::format_map_t args;
- args["WIDTH"] = llformat("%d", max_width);
- args["HEIGHT"] = llformat("%d", max_height);
-
- mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args);
- return false;
- }
-
- // Load the image
- LLPointer image = LLImageFormatted::createFromType(codec);
- if (image.isNull())
- {
- return false;
- }
- if (!image->load(src_filename))
- {
- return false;
- }
- // Decompress or expand it in a raw image structure
- LLPointer raw_image = new LLImageRaw;
- if (!image->decode(raw_image, 0.0f))
- {
- return false;
- }
- // Check the image constraints
- if ((image->getComponents() != 3) && (image->getComponents() != 4))
- {
- image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
- return false;
- }
-
- raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
- mRawImagep = raw_image;
-
return true;
}
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index 002dc4fa1a..e64f468cbe 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -261,7 +261,8 @@ void LLFloaterIMNearbyChat::loadHistory()
void LLFloaterIMNearbyChat::removeScreenChat()
{
- LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID")));
+ LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(
+ LLNotificationsUI::NEARBY_CHAT_CHANNEL_UUID);
if(chat_channel)
{
chat_channel->removeToastsFromChannel();
diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp
index 9337a9b51b..77ceea19af 100644
--- a/indra/newview/llfloaterimnearbychathandler.cpp
+++ b/indra/newview/llfloaterimnearbychathandler.cpp
@@ -459,7 +459,7 @@ LLFloaterIMNearbyChatHandler::LLFloaterIMNearbyChatHandler()
{
// Getting a Channel for our notifications
LLFloaterIMNearbyChatScreenChannel::Params p;
- p.id = LLUUID(gSavedSettings.getString("NearByChatChannelUUID"));
+ p.id = NEARBY_CHAT_CHANNEL_UUID;
LLFloaterIMNearbyChatScreenChannel* channel = new LLFloaterIMNearbyChatScreenChannel(p);
LLFloaterIMNearbyChatScreenChannel::create_toast_panel_callback_t callback = createToastPanel;
diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp
index ffa23df8d8..a2d1cb7036 100644
--- a/indra/newview/llfloaterimsession.cpp
+++ b/indra/newview/llfloaterimsession.cpp
@@ -653,7 +653,7 @@ void LLFloaterIMSession::setDocked(bool docked, bool pop_on_undock)
// update notification channel state
LLNotificationsUI::LLScreenChannel* channel = static_cast
(LLNotificationsUI::LLChannelManager::getInstance()->
- findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+ findChannelByID(LLNotificationsUI::NOTIFICATION_CHANNEL_UUID));
if(!isChatMultiTab())
{
@@ -689,7 +689,7 @@ void LLFloaterIMSession::setVisible(BOOL visible)
{
LLNotificationsUI::LLScreenChannel* channel = static_cast
(LLNotificationsUI::LLChannelManager::getInstance()->
- findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+ findChannelByID(LLNotificationsUI::NOTIFICATION_CHANNEL_UUID));
LLFloaterIMSessionTab::setVisible(visible);
@@ -867,7 +867,7 @@ void LLFloaterIMSession::updateMessages()
// remove embedded notification from channel
LLNotificationsUI::LLScreenChannel* channel = static_cast
(LLNotificationsUI::LLChannelManager::getInstance()->
- findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+ findChannelByID(LLNotificationsUI::NOTIFICATION_CHANNEL_UUID));
if (getVisible())
{
// toast will be automatically closed since it is not storable toast
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index f7cc6c495e..dc64d09f9f 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -267,9 +267,13 @@ BOOL LLFloaterIMSessionTab::postBuild()
mEmojiRecentEmptyText->setToolTip(mEmojiRecentEmptyText->getText());
mEmojiRecentEmptyText->setVisible(false);
+ mEmojiRecentContainer = getChild("emoji_recent_container");
+ mEmojiRecentContainer->setVisible(false);
+
mEmojiRecentIconsCtrl = getChild("emoji_recent_icons_ctrl");
+ mEmojiRecentIconsCtrl->setFocusReceivedCallback([this](LLFocusableElement*) { onEmojiRecentPanelFocusReceived(); });
+ mEmojiRecentIconsCtrl->setFocusLostCallback([this](LLFocusableElement*) { onEmojiRecentPanelFocusLost(); });
mEmojiRecentIconsCtrl->setCommitCallback([this](LLUICtrl*, const LLSD& value) { onRecentEmojiPicked(value); });
- mEmojiRecentIconsCtrl->setVisible(false);
mEmojiPickerShowBtn = getChild("emoji_picker_show_btn");
mEmojiPickerShowBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerShowBtnClicked(); });
@@ -475,7 +479,7 @@ void LLFloaterIMSessionTab::initEmojiRecentPanel()
if (recentlyUsed.empty())
{
mEmojiRecentEmptyText->setVisible(TRUE);
- mEmojiRecentIconsCtrl->setVisible(FALSE);
+ mEmojiRecentContainer->setVisible(FALSE);
}
else
{
@@ -486,10 +490,22 @@ void LLFloaterIMSessionTab::initEmojiRecentPanel()
}
mEmojiRecentIconsCtrl->setEmojis(emojis);
mEmojiRecentEmptyText->setVisible(FALSE);
- mEmojiRecentIconsCtrl->setVisible(TRUE);
+ mEmojiRecentContainer->setVisible(TRUE);
}
}
+// static
+void LLFloaterIMSessionTab::onEmojiRecentPanelFocusReceived()
+{
+ mEmojiRecentContainer->addBorder();
+}
+
+// static
+void LLFloaterIMSessionTab::onEmojiRecentPanelFocusLost()
+{
+ mEmojiRecentContainer->removeBorder();
+}
+
void LLFloaterIMSessionTab::onRecentEmojiPicked(const LLSD& value)
{
LLSD::String str = value.asString();
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index d378b2ea6b..00b43f499b 100644
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -173,6 +173,7 @@ protected:
LLLayoutPanel* mInputButtonPanel;
LLLayoutPanel* mEmojiRecentPanel;
LLTextBox* mEmojiRecentEmptyText;
+ LLPanel* mEmojiRecentContainer;
LLPanelEmojiComplete* mEmojiRecentIconsCtrl;
LLParticipantList* getParticipantList();
conversations_widgets_map mConversationsWidgets;
@@ -218,6 +219,8 @@ private:
void onEmojiRecentPanelToggleBtnClicked();
void onEmojiPickerShowBtnClicked();
void initEmojiRecentPanel();
+ void onEmojiRecentPanelFocusReceived();
+ void onEmojiRecentPanelFocusLost();
void onRecentEmojiPicked(const LLSD& value);
bool checkIfTornOff();
diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp
index ca0a506802..128cf56be0 100644
--- a/indra/newview/llfloaterjoystick.cpp
+++ b/indra/newview/llfloaterjoystick.cpp
@@ -250,6 +250,13 @@ void LLFloaterJoystick::refresh()
initFromSettings();
}
+bool LLFloaterJoystick::addDeviceCallback(std::string &name, LLSD& value, void* userdata)
+{
+ LLFloaterJoystick * floater = (LLFloaterJoystick*)userdata;
+ floater->mJoysticksCombo->add(name, value, ADD_BOTTOM, 1);
+ return false; // keep searching
+}
+
void LLFloaterJoystick::addDevice(std::string &name, LLSD& value)
{
mJoysticksCombo->add(name, value, ADD_BOTTOM, 1);
@@ -264,19 +271,21 @@ void LLFloaterJoystick::refreshListOfDevices()
mHasDeviceList = false;
+ void* win_calback = nullptr;
// di8_devices_callback callback is immediate and happens in scope of getInputDevices()
#if LL_WINDOWS && !LL_MESA_HEADLESS
// space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib
U32 device_type = DI8DEVCLASS_GAMECTRL;
- void* callback = &di8_list_devices_callback;
-#else
- // MAC doesn't support device search yet
- // On MAC there is an ndof_idsearch and it is possible to specify product
- // and manufacturer in NDOF_Device for ndof_init_first to pick specific one
+ win_calback = di8_list_devices_callback;
+#elif LL_DARWIN
+ U32 device_type = 0;
+#else
+ // On MAC it is possible to specify product
+ // and manufacturer in NDOF_Device for
+ // ndof_init_first to pick specific device
U32 device_type = 0;
- void* callback = NULL;
#endif
- if (gViewerWindow->getWindow()->getInputDevices(device_type, callback, this))
+ if (gViewerWindow->getWindow()->getInputDevices(device_type, addDeviceCallback, win_calback, this))
{
mHasDeviceList = true;
}
@@ -419,9 +428,10 @@ void LLFloaterJoystick::onCommitJoystickEnabled(LLUICtrl*, void *joy_panel)
}
}
- std::string device_id = LLViewerJoystick::getInstance()->getDeviceUUIDString();
- gSavedSettings.setString("JoystickDeviceUUID", device_id);
- LL_DEBUGS("Joystick") << "Selected " << device_id << " as joystick." << LL_ENDL;
+ LLViewerJoystick::getInstance()->saveDeviceIdToSettings();
+
+ std::string device_string = LLViewerJoystick::getInstance()->getDeviceUUIDString();
+ LL_DEBUGS("Joystick") << "Selected " << device_string << " as joystick." << LL_ENDL;
self->refreshListOfDevices();
}
diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h
index 2ed4018670..e304431153 100644
--- a/indra/newview/llfloaterjoystick.h
+++ b/indra/newview/llfloaterjoystick.h
@@ -46,6 +46,7 @@ public:
virtual void draw();
static void setSNDefaults();
+ static bool addDeviceCallback(std::string &name, LLSD& value, void* userdata);
void addDevice(std::string &name, LLSD& value);
protected:
diff --git a/indra/newview/llfloaternotificationstabbed.cpp b/indra/newview/llfloaternotificationstabbed.cpp
index 94d650ddbe..28ef403cf7 100644
--- a/indra/newview/llfloaternotificationstabbed.cpp
+++ b/indra/newview/llfloaternotificationstabbed.cpp
@@ -154,7 +154,7 @@ LLPanel * LLFloaterNotificationsTabbed::findItemByID(const LLUUID& id, std::stri
void LLFloaterNotificationsTabbed::initChannel()
{
LLNotificationsUI::LLScreenChannelBase* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(
- LLUUID(gSavedSettings.getString("NotificationChannelUUID")));
+ LLNotificationsUI::NOTIFICATION_CHANNEL_UUID);
mChannel = dynamic_cast(channel);
if(NULL == mChannel)
{
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 858a64973b..d731f1c592 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -368,9 +368,9 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType type )
{
- if ( APT_PROPERTIES == type )
+ if ( APT_PROPERTIES_LEGACY == type )
{
- const LLAvatarData* pAvatarData = static_cast( pData );
+ const LLAvatarLegacyData* pAvatarData = static_cast( pData );
if (pAvatarData && (gAgent.getID() == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null))
{
mAllowPublish = (bool)(pAvatarData->flags & AVATAR_ALLOW_PUBLISH);
@@ -510,9 +510,7 @@ BOOL LLFloaterPreference::postBuild()
void LLFloaterPreference::updateDeleteTranscriptsButton()
{
- std::vector list_of_transcriptions_file_names;
- LLLogChat::getListOfTranscriptFiles(list_of_transcriptions_file_names);
- getChild("delete_transcripts")->setEnabled(list_of_transcriptions_file_names.size() > 0);
+ getChild("delete_transcripts")->setEnabled(LLLogChat::transcriptFilesExist());
}
void LLFloaterPreference::onDoNotDisturbResponseChanged()
@@ -677,7 +675,6 @@ void LLFloaterPreference::cancel()
void LLFloaterPreference::onOpen(const LLSD& key)
{
-
// this variable and if that follows it are used to properly handle do not disturb mode response message
static bool initialized = FALSE;
// if user is logged in and we haven't initialized do not disturb mode response yet, do it
@@ -704,7 +701,7 @@ void LLFloaterPreference::onOpen(const LLSD& key)
(gAgent.isMature() || gAgent.isGodlike());
LLComboBox* maturity_combo = getChild("maturity_desired_combobox");
- LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest( gAgent.getID() );
+ LLAvatarPropertiesProcessor::getInstance()->sendAvatarLegacyPropertiesRequest( gAgent.getID() );
if (can_choose_maturity)
{
// if they're not adult or a god, they shouldn't see the adult selection, so delete it
diff --git a/indra/newview/llfloaterprofiletexture.cpp b/indra/newview/llfloaterprofiletexture.cpp
index 8b36072034..7108047a6b 100644
--- a/indra/newview/llfloaterprofiletexture.cpp
+++ b/indra/newview/llfloaterprofiletexture.cpp
@@ -33,39 +33,173 @@
#include "llpreview.h" // fors constants
#include "lltrans.h"
#include "llviewercontrol.h"
-#include "lltextureview.h"
#include "llviewertexture.h"
#include "llviewertexturelist.h"
+ //////////////////////////////////////////////////////////////////////////
+ // LLProfileImageCtrl
+ //////////////////////////////////////////////////////////////////////////
+
+static LLDefaultChildRegistry::Register r("profile_image");
+
+LLProfileImageCtrl::LLProfileImageCtrl(const LLProfileImageCtrl::Params& p)
+ : LLIconCtrl(p)
+ , mImage(NULL)
+ , mImageOldBoostLevel(LLGLTexture::BOOST_NONE)
+ , mWasNoDelete(false)
+ , mImageLoadedSignal(NULL)
+{
+}
+
+LLProfileImageCtrl::~LLProfileImageCtrl()
+{
+ LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList);
+ releaseTexture();
+
+ delete mImageLoadedSignal;
+}
+
+void LLProfileImageCtrl::releaseTexture()
+{
+ if (mImage.notNull())
+ {
+ mImage->setBoostLevel(mImageOldBoostLevel);
+ if (!mWasNoDelete)
+ {
+ // In most cases setBoostLevel marks images as NO_DELETE
+ mImage->forceActive();
+ }
+ mImage = NULL;
+ }
+}
+
+void LLProfileImageCtrl::setValue(const LLSD& value)
+{
+ LLUUID id = value.asUUID();
+ setImageAssetId(id);
+ if (id.isNull())
+ {
+ LLIconCtrl::setValue("Generic_Person_Large", LLGLTexture::BOOST_UI);
+ }
+ else
+ {
+ // called second to not change priority before it gets saved to mImageOldBoostLevel
+ LLIconCtrl::setValue(value, LLGLTexture::BOOST_PREVIEW);
+ }
+}
+
+void LLProfileImageCtrl::draw()
+{
+ if (mImage.notNull())
+ {
+ // Pump the texture priority
+ mImage->addTextureStats(MAX_IMAGE_AREA);
+ mImage->setKnownDrawSize(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT, LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT);
+ }
+ LLIconCtrl::draw();
+}
+
+boost::signals2::connection LLProfileImageCtrl::setImageLoadedCallback(const image_loaded_signal_t::slot_type& cb)
+{
+ if (!mImageLoadedSignal) mImageLoadedSignal = new image_loaded_signal_t();
+
+ return mImageLoadedSignal->connect(cb);
+}
+
+void LLProfileImageCtrl::setImageAssetId(const LLUUID& asset_id)
+{
+ if (mImageID == asset_id)
+ {
+ return;
+ }
+
+ releaseTexture();
+
+ mImageID = asset_id;
+ if (mImageID.notNull())
+ {
+ mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+ mWasNoDelete = mImage->getTextureState() == LLGLTexture::NO_DELETE;
+ mImageOldBoostLevel = mImage->getBoostLevel();
+ mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
+ mImage->setKnownDrawSize(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT, LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT);
+ mImage->forceToSaveRawImage(0);
+
+ if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0)
+ {
+ mImage->setLoadedCallback(LLProfileImageCtrl::onImageLoaded,
+ 0, TRUE, FALSE, new LLHandle(getHandle()), &mCallbackTextureList);
+ }
+ else
+ {
+ onImageLoaded(true, mImage);
+ }
+ }
+}
+
+void LLProfileImageCtrl::onImageLoaded(bool success, LLViewerFetchedTexture* img)
+{
+ if (mImageLoadedSignal)
+ {
+ (*mImageLoadedSignal)(success, img);
+ }
+}
+
+// static
+void LLProfileImageCtrl::onImageLoaded(BOOL success,
+ LLViewerFetchedTexture* src_vi,
+ LLImageRaw* src,
+ LLImageRaw* aux_src,
+ S32 discard_level,
+ BOOL final,
+ void* userdata)
+{
+ if (!userdata) return;
+
+ LLHandle* handle = (LLHandle*)userdata;
+
+ if (!handle->isDead())
+ {
+ LLProfileImageCtrl* caller = static_cast(handle->get());
+ if (caller && caller->mImageLoadedSignal)
+ {
+ (*caller->mImageLoadedSignal)(success, src_vi);
+ }
+ }
+
+ if (final || !success)
+ {
+ delete handle;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// LLFloaterProfileTexture
+ //////////////////////////////////////////////////////////////////////////
LLFloaterProfileTexture::LLFloaterProfileTexture(LLView* owner)
: LLFloater(LLSD())
- , mUpdateDimensions(TRUE)
, mLastHeight(0)
, mLastWidth(0)
- , mImage(NULL)
- , mImageOldBoostLevel(LLGLTexture::BOOST_NONE)
, mOwnerHandle(owner->getHandle())
+ , mContextConeOpacity(0.f)
+ , mCloseButton(NULL)
+ , mProfileIcon(NULL)
{
buildFromFile("floater_profile_texture.xml");
}
LLFloaterProfileTexture::~LLFloaterProfileTexture()
{
- if (mImage.notNull())
- {
- mImage->setBoostLevel(mImageOldBoostLevel);
- mImage = NULL;
- }
-
- LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList);
}
// virtual
BOOL LLFloaterProfileTexture::postBuild()
{
- mProfileIcon = getChild("profile_pic");
+ mProfileIcon = getChild("profile_pic");
+ mProfileIcon->setImageLoadedCallback([this](BOOL success, LLViewerFetchedTexture* imagep) {onImageLoaded(success, imagep); });
mCloseButton = getChild("close_btn");
mCloseButton->setCommitCallback([this](LLUICtrl*, void*) { closeFloater(); }, nullptr);
@@ -83,55 +217,41 @@ void LLFloaterProfileTexture::reshape(S32 width, S32 height, BOOL called_from_pa
// When we receive it, reshape the window accordingly.
void LLFloaterProfileTexture::updateDimensions()
{
- if (mImage.isNull())
+ LLPointer image = mProfileIcon->getImage();
+ if (image.isNull())
{
return;
}
- if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0)
+ if ((image->getFullWidth() * image->getFullHeight()) == 0)
{
return;
}
- S32 img_width = mImage->getFullWidth();
- S32 img_height = mImage->getFullHeight();
-
- if (mAssetStatus != LLPreview::PREVIEW_ASSET_LOADED
- || mLastWidth != img_width
- || mLastHeight != img_height)
- {
- mAssetStatus = LLPreview::PREVIEW_ASSET_LOADED;
- // Asset has been fully loaded
- mUpdateDimensions = TRUE;
- }
+ S32 img_width = image->getFullWidth();
+ S32 img_height = image->getFullHeight();
mLastHeight = img_height;
mLastWidth = img_width;
- // Reshape the floater only when required
- if (mUpdateDimensions)
+ LLRect old_floater_rect = getRect();
+ LLRect old_image_rect = mProfileIcon->getRect();
+ S32 width = old_floater_rect.getWidth() - old_image_rect.getWidth() + mLastWidth;
+ S32 height = old_floater_rect.getHeight() - old_image_rect.getHeight() + mLastHeight;
+
+ const F32 MAX_DIMENTIONS = 512; // most profiles are supposed to be 256x256
+
+ S32 biggest_dim = llmax(width, height);
+ if (biggest_dim > MAX_DIMENTIONS)
{
- mUpdateDimensions = FALSE;
-
- LLRect old_floater_rect = getRect();
- LLRect old_image_rect = mProfileIcon->getRect();
- S32 width = old_floater_rect.getWidth() - old_image_rect.getWidth() + mLastWidth;
- S32 height = old_floater_rect.getHeight() - old_image_rect.getHeight() + mLastHeight;
-
- const F32 MAX_DIMENTIONS = 512; // most profiles are supposed to be 256x256
-
- S32 biggest_dim = llmax(width, height);
- if (biggest_dim > MAX_DIMENTIONS)
- {
- F32 scale_down = MAX_DIMENTIONS / (F32)biggest_dim;
- width *= scale_down;
- height *= scale_down;
- }
-
- //reshape floater
- reshape(width, height);
-
- gFloaterView->adjustToFitScreen(this, FALSE);
+ F32 scale_down = MAX_DIMENTIONS / (F32)biggest_dim;
+ width *= scale_down;
+ height *= scale_down;
}
+
+ //reshape floater
+ reshape(width, height);
+
+ gFloaterView->adjustToFitScreen(this, FALSE);
}
void LLFloaterProfileTexture::draw()
@@ -151,75 +271,18 @@ void LLFloaterProfileTexture::onOpen(const LLSD& key)
void LLFloaterProfileTexture::resetAsset()
{
- mProfileIcon->setValue("Generic_Person_Large");
- mImageID = LLUUID::null;
- if (mImage.notNull())
- {
- mImage->setBoostLevel(mImageOldBoostLevel);
- mImage = NULL;
- }
+ mProfileIcon->setValue(LLUUID::null);
}
void LLFloaterProfileTexture::loadAsset(const LLUUID &image_id)
{
- if (mImageID != image_id)
- {
- if (mImage.notNull())
- {
- mImage->setBoostLevel(mImageOldBoostLevel);
- mImage = NULL;
- }
- }
- else
- {
- return;
- }
-
mProfileIcon->setValue(image_id);
- mImageID = image_id;
- mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
- mImageOldBoostLevel = mImage->getBoostLevel();
-
- if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0)
- {
- mImage->setLoadedCallback(LLFloaterProfileTexture::onTextureLoaded,
- 0, TRUE, FALSE, new LLHandle(getHandle()), &mCallbackTextureList);
-
- mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
- mAssetStatus = LLPreview::PREVIEW_ASSET_LOADING;
- }
- else
- {
- mAssetStatus = LLPreview::PREVIEW_ASSET_LOADED;
- }
-
- mUpdateDimensions = TRUE;
updateDimensions();
}
-// static
-void LLFloaterProfileTexture::onTextureLoaded(
- BOOL success,
- LLViewerFetchedTexture *src_vi,
- LLImageRaw* src,
- LLImageRaw* aux_src,
- S32 discard_level,
- BOOL final,
- void* userdata)
+void LLFloaterProfileTexture::onImageLoaded(BOOL success, LLViewerFetchedTexture* imagep)
{
- LLHandle* handle = (LLHandle*)userdata;
-
- if (!handle->isDead())
+ if (success)
{
- LLFloaterProfileTexture* floater = static_cast(handle->get());
- if (floater && success)
- {
- floater->mUpdateDimensions = TRUE;
- floater->updateDimensions();
- }
- }
-
- if (final || !success)
- {
- delete handle;
+ updateDimensions();
}
}
diff --git a/indra/newview/llfloaterprofiletexture.h b/indra/newview/llfloaterprofiletexture.h
index e0ec0b16ef..12efbab572 100644
--- a/indra/newview/llfloaterprofiletexture.h
+++ b/indra/newview/llfloaterprofiletexture.h
@@ -1,25 +1,25 @@
-/**
+/**
* @file llfloaterprofiletexture.h
* @brief LLFloaterProfileTexture class definition
*
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2022, 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$
*/
@@ -28,11 +28,50 @@
#define LL_LLFLOATERPROFILETEXTURE_H
#include "llfloater.h"
+#include "lliconctrl.h"
#include "llviewertexture.h"
class LLButton;
class LLImageRaw;
-class LLIconCtrl;
+
+class LLProfileImageCtrl: public LLIconCtrl
+{
+public:
+ struct Params: public LLInitParam::Block
+ {
+ };
+
+ LLProfileImageCtrl(const Params& p);
+ virtual ~LLProfileImageCtrl();
+
+
+ virtual void setValue(const LLSD& value) override;
+ LLUUID getImageAssetId() { return mImageID; }
+ LLPointer getImage() {return mImage;}
+ void draw() override;
+
+ typedef boost::signals2::signal image_loaded_signal_t;
+ boost::signals2::connection setImageLoadedCallback(const image_loaded_signal_t::slot_type& cb);
+private:
+ void onImageLoaded(bool success, LLViewerFetchedTexture* src_vi);
+ static void onImageLoaded(BOOL success,
+ LLViewerFetchedTexture* src_vi,
+ LLImageRaw* src,
+ LLImageRaw* aux_src,
+ S32 discard_level,
+ BOOL final,
+ void* userdata);
+ void releaseTexture();
+
+ void setImageAssetId(const LLUUID& asset_id);
+private:
+ LLPointer mImage;
+ LLUUID mImageID;
+ S32 mImageOldBoostLevel;
+ bool mWasNoDelete;
+ image_loaded_signal_t* mImageLoadedSignal;
+ LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList;
+};
class LLFloaterProfileTexture : public LLFloater
{
@@ -46,36 +85,23 @@ public:
void resetAsset();
void loadAsset(const LLUUID &image_id);
-
- static void onTextureLoaded(
- BOOL success,
- LLViewerFetchedTexture *src_vi,
- LLImageRaw* src,
- LLImageRaw* aux_src,
- S32 discard_level,
- BOOL final,
- void* userdata);
+ void onImageLoaded(BOOL success, LLViewerFetchedTexture* imagep);
void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override;
+
+ LLHandle getHandle() const { return LLFloater::getHandle(); }
protected:
BOOL postBuild() override;
private:
void updateDimensions();
- LLUUID mImageID;
- LLPointer mImage;
- S32 mImageOldBoostLevel;
- S32 mAssetStatus;
F32 mContextConeOpacity;
S32 mLastHeight;
S32 mLastWidth;
- BOOL mUpdateDimensions;
LLHandle mOwnerHandle;
- LLIconCtrl* mProfileIcon;
+ LLProfileImageCtrl* mProfileIcon;
LLButton* mCloseButton;
-
- LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList;
};
#endif // LL_LLFLOATERPROFILETEXTURE_H
diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp
index 4eda962e8b..bd32807bb9 100644
--- a/indra/newview/llfloatersearch.cpp
+++ b/indra/newview/llfloatersearch.cpp
@@ -48,12 +48,6 @@ public:
LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_CLICK_ONLY) { }
bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web)
{
- if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableSearch"))
- {
- LLNotificationsUtil::add("NoSearch", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
- return true;
- }
-
const size_t parts = tokens.size();
// get the (optional) category for the search
diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp
index 65bd3d3717..f44c9ea953 100644
--- a/indra/newview/llfloatersellland.cpp
+++ b/indra/newview/llfloatersellland.cpp
@@ -283,9 +283,7 @@ void LLFloaterSellLandUI::refreshUI()
getChild("info_size")->setTextArg("[AREA]", llformat("%d", mParcelActualArea));
std::string price_str = getChild("price")->getValue().asString();
- bool valid_price = false;
- valid_price = (price_str != "") && LLTextValidate::validateNonNegativeS32(utf8str_to_wstring(price_str));
-
+ bool valid_price = !price_str.empty() && LLTextValidate::validateNonNegativeS32.validate(price_str);
if (valid_price && mParcelActualArea > 0)
{
F32 per_meter_price = 0;
@@ -299,7 +297,7 @@ void LLFloaterSellLandUI::refreshUI()
{
getChildView("price_per_m")->setVisible(FALSE);
- if ("" == price_str)
+ if (price_str.empty())
{
setBadge("step_price", BADGE_NOTE);
}
@@ -331,9 +329,7 @@ void LLFloaterSellLandUI::refreshUI()
// Must select Sell To: Anybody, or User (with a specified username)
std::string sell_to = getChild("sell_to")->getValue().asString();
- bool valid_sell_to = "select" != sell_to &&
- ("user" != sell_to || mAuthorizedBuyer.notNull());
-
+ bool valid_sell_to = "select" != sell_to && ("user" != sell_to || mAuthorizedBuyer.notNull());
if (!valid_sell_to)
{
setBadge("step_sell_to", BADGE_NOTE);
@@ -344,7 +340,6 @@ void LLFloaterSellLandUI::refreshUI()
}
bool valid_sell_objects = ("none" != getChild("sell_objects")->getValue().asString());
-
if (!valid_sell_objects)
{
setBadge("step_sell_objects", BADGE_NOTE);
diff --git a/indra/newview/llfloatersimplesnapshot.cpp b/indra/newview/llfloatersimplesnapshot.cpp
index 37f845b3d7..5d65bf2d0d 100644
--- a/indra/newview/llfloatersimplesnapshot.cpp
+++ b/indra/newview/llfloatersimplesnapshot.cpp
@@ -370,7 +370,7 @@ void LLFloaterSimpleSnapshot::onSend()
else
{
LLSD notif_args;
- notif_args["REASON"] = LLImage::getLastError().c_str();
+ notif_args["REASON"] = LLImage::getLastThreadError().c_str();
LLNotificationsUtil::add("CannotUploadTexture", notif_args);
}
}
@@ -389,7 +389,7 @@ void LLFloaterSimpleSnapshot::uploadThumbnail(const std::string &file_path, cons
if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN, true))
{
LLSD notif_args;
- notif_args["REASON"] = LLImage::getLastError().c_str();
+ notif_args["REASON"] = LLImage::getLastThreadError().c_str();
LLNotificationsUtil::add("CannotUploadTexture", notif_args);
LL_WARNS("Thumbnail") << "Failed to upload thumbnail for " << inventory_id << " " << task_id << ", reason: " << notif_args["REASON"].asString() << LL_ENDL;
return;
@@ -404,7 +404,7 @@ void LLFloaterSimpleSnapshot::uploadThumbnail(LLPointer raw_image, c
if (!LLViewerTextureList::createUploadFile(raw_image, temp_file, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN))
{
LLSD notif_args;
- notif_args["REASON"] = LLImage::getLastError().c_str();
+ notif_args["REASON"] = LLImage::getLastThreadError().c_str();
LLNotificationsUtil::add("CannotUploadTexture", notif_args);
LL_WARNS("Thumbnail") << "Failed to upload thumbnail for " << inventory_id << " " << task_id << ", reason: " << notif_args["REASON"].asString() << LL_ENDL;
return;
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index da1e6cca74..bb4ae7e8ab 100755
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -146,12 +146,6 @@ public:
const std::string& grid,
LLMediaCtrl* web)
{
- if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableWorldMap"))
- {
- LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
- return true;
- }
-
if (params.size() == 0)
{
// support the secondlife:///app/worldmap SLapp
@@ -207,12 +201,6 @@ public:
const std::string& grid,
LLMediaCtrl* web)
{
- if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableWorldMap"))
- {
- LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
- return true;
- }
-
//Make sure we have some parameters
if (params.size() == 0)
{
diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp
index 71c7606672..5671f6dd59 100644
--- a/indra/newview/llgesturemgr.cpp
+++ b/indra/newview/llgesturemgr.cpp
@@ -58,6 +58,9 @@
// Longest time, in seconds, to wait for all animations to stop playing
const F32 MAX_WAIT_ANIM_SECS = 30.f;
+// Longest time, in seconds, to wait for a key release.
+// This should be relatively long, but not too long. 10 minutes is enough
+const F32 MAX_WAIT_KEY_SECS = 60.f * 10.f;
// Lightweight constructor.
// init() does the heavy lifting.
@@ -528,12 +531,13 @@ void LLGestureMgr::replaceGesture(const LLUUID& item_id, const LLUUID& new_asset
LLGestureMgr::instance().replaceGesture(base_item_id, gesture, new_asset_id);
}
-void LLGestureMgr::playGesture(LLMultiGesture* gesture)
+void LLGestureMgr::playGesture(LLMultiGesture* gesture, bool fromKeyPress)
{
if (!gesture) return;
// Reset gesture to first step
gesture->mCurrentStep = 0;
+ gesture->mTriggeredByKey = fromKeyPress;
// Add to list of playing
gesture->mPlaying = TRUE;
@@ -731,7 +735,8 @@ BOOL LLGestureMgr::triggerGesture(KEY key, MASK mask)
if (!gesture) continue;
if (gesture->mKey == key
- && gesture->mMask == mask)
+ && gesture->mMask == mask
+ && gesture->mWaitingKeyRelease == FALSE)
{
matching.push_back(gesture);
}
@@ -744,13 +749,38 @@ BOOL LLGestureMgr::triggerGesture(KEY key, MASK mask)
LLMultiGesture* gesture = matching[random];
- playGesture(gesture);
+ playGesture(gesture, TRUE);
return TRUE;
}
return FALSE;
}
+BOOL LLGestureMgr::triggerGestureRelease(KEY key, MASK mask)
+{
+ std::vector matching;
+ item_map_t::iterator it;
+
+ // collect matching gestures
+ for (it = mActive.begin(); it != mActive.end(); ++it)
+ {
+ LLMultiGesture* gesture = (*it).second;
+
+ // asset data might not have arrived yet
+ if (!gesture) continue;
+
+ if (gesture->mKey == key
+ && gesture->mMask == mask)
+ {
+ gesture->mKeyReleased = TRUE;
+ }
+ }
+
+ //If we found one, block. Otherwise tell them it's free to go.
+ return matching.size() > 0;
+}
+
+
S32 LLGestureMgr::getPlayingCount() const
{
return mPlaying.size();
@@ -899,6 +929,32 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture)
continue;
}
+ // If we're waiting a fixed amount of time, check for timer
+ // expiration.
+ if (gesture->mWaitingKeyRelease)
+ {
+ // We're waiting for a certain amount of time to pass
+ if (gesture->mKeyReleased)
+ {
+ // wait is done, continue execution
+ gesture->mWaitingKeyRelease = FALSE;
+ gesture->mCurrentStep++;
+ }
+ else if (gesture->mWaitTimer.getElapsedTimeF32() > MAX_WAIT_KEY_SECS)
+ {
+ LL_INFOS("GestureMgr") << "Waited too long for key release, continuing gesture."
+ << LL_ENDL;
+ gesture->mWaitingKeyRelease = FALSE;
+ gesture->mCurrentStep++;
+ }
+ else
+ {
+ // we're waiting, so execution is done for now
+ waiting = TRUE;
+ }
+ continue;
+ }
+
// If we're waiting on our animations to stop, poll for
// completion.
if (gesture->mWaitingAnimations)
@@ -1015,7 +1071,17 @@ void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step)
case STEP_WAIT:
{
LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
- if (wait_step->mFlags & WAIT_FLAG_TIME)
+ if (gesture->mTriggeredByKey // Only wait here IF we were triggered by a key!
+ && gesture->mWaitingKeyRelease == FALSE // We can only do this once! Prevent gestures infinitely running
+ && wait_step->mFlags & WAIT_FLAG_KEY_RELEASE)
+ {
+ // Lets wait for the key release first so we don't hold up re-presses
+ gesture->mWaitingKeyRelease = TRUE;
+ gesture->mKeyReleased = FALSE;
+ // Use the wait timer as a deadlock breaker for key release waits.
+ gesture->mWaitTimer.reset();
+ }
+ else if (wait_step->mFlags & WAIT_FLAG_TIME)
{
gesture->mWaitingTimer = TRUE;
gesture->mWaitTimer.reset();
@@ -1023,8 +1089,7 @@ void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step)
else if (wait_step->mFlags & WAIT_FLAG_ALL_ANIM)
{
gesture->mWaitingAnimations = TRUE;
- // Use the wait timer as a deadlock breaker for animation
- // waits.
+ // Use the wait timer as a deadlock breaker for animation waits.
gesture->mWaitTimer.reset();
}
else
diff --git a/indra/newview/llgesturemgr.h b/indra/newview/llgesturemgr.h
index 73b898c406..b41f0ee106 100644
--- a/indra/newview/llgesturemgr.h
+++ b/indra/newview/llgesturemgr.h
@@ -102,7 +102,10 @@ public:
const item_map_t& getActiveGestures() const { return mActive; }
// Force a gesture to be played, for example, if it is being
// previewed.
- void playGesture(LLMultiGesture* gesture);
+ void playGesture(LLMultiGesture* gesture, bool fromKeyPress);
+ void playGesture(LLMultiGesture* gesture) {
+ playGesture(gesture, FALSE);
+ }
void playGesture(const LLUUID& item_id);
// Stop all requested or playing anims for this gesture
@@ -118,10 +121,14 @@ public:
{
mCallbackMap[inv_item_id] = cb;
}
- // Trigger the first gesture that matches this key.
+ // Trigger a random gesture that matches this key.
// Returns TRUE if it finds a gesture bound to that key.
BOOL triggerGesture(KEY key, MASK mask);
+ // Trigger release wait on all gestures that matches this key.
+ // Returns TRUE if it finds a gesture bound to that key.
+ BOOL triggerGestureRelease(KEY key, MASK mask);
+
// Trigger all gestures referenced as substrings in this string
BOOL triggerAndReviseString(const std::string &str, std::string *revised_string = NULL);
diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp
index 9e46d9c6ca..24ae90e3ae 100644
--- a/indra/newview/llgroupactions.cpp
+++ b/indra/newview/llgroupactions.cpp
@@ -89,12 +89,6 @@ public:
return true;
}
- if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableGroupInfo"))
- {
- LLNotificationsUtil::add("NoGroupInfo", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
- return true;
- }
-
if (tokens.size() < 1)
{
return false;
@@ -373,7 +367,16 @@ void LLGroupActions::processLeaveGroupDataResponse(const LLUUID group_id)
args["GROUP"] = gdatap->mName;
LLSD payload;
payload["group_id"] = group_id;
- LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup);
+ if (gdatap->mMembershipFee > 0)
+ {
+ args["COST"] = gdatap->mMembershipFee;
+ LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup);
+ }
+ else
+ {
+ LLNotificationsUtil::add("GroupLeaveConfirmMemberNoFee", args, payload, onLeaveGroup);
+ }
+
}
// static
@@ -405,7 +408,7 @@ void LLGroupActions::inspect(const LLUUID& group_id)
}
// static
-void LLGroupActions::show(const LLUUID& group_id)
+void LLGroupActions::show(const LLUUID &group_id, bool expand_notices_tab)
{
if (group_id.isNull())
return;
@@ -413,6 +416,10 @@ void LLGroupActions::show(const LLUUID& group_id)
LLSD params;
params["group_id"] = group_id;
params["open_tab_name"] = "panel_group_info_sidetray";
+ if (expand_notices_tab)
+ {
+ params["action"] = "show_notices";
+ }
LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
LLFloater *floater = LLFloaterReg::getTypedInstance("people");
diff --git a/indra/newview/llgroupactions.h b/indra/newview/llgroupactions.h
index 5a447f682f..9195e38bca 100644
--- a/indra/newview/llgroupactions.h
+++ b/indra/newview/llgroupactions.h
@@ -57,7 +57,7 @@ public:
/**
* Show group information panel.
*/
- static void show(const LLUUID& group_id);
+ static void show(const LLUUID& group_id, bool expand_notices_tab = false);
/**
* Show group inspector floater.
diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp
index 12092a02c6..38b2f4adc8 100644
--- a/indra/newview/llgrouplist.cpp
+++ b/indra/newview/llgrouplist.cpp
@@ -303,6 +303,7 @@ void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LL
item->getChildView("info_btn")->setVisible( false);
item->getChildView("profile_btn")->setVisible( false);
+ item->getChildView("notices_btn")->setVisible(false);
item->setGroupIconVisible(mShowIcons);
if (!mShowIcons)
{
@@ -403,6 +404,7 @@ mGroupIcon(NULL),
mGroupNameBox(NULL),
mInfoBtn(NULL),
mProfileBtn(NULL),
+mNoticesBtn(NULL),
mVisibilityHideBtn(NULL),
mVisibilityShowBtn(NULL),
mGroupID(LLUUID::null),
@@ -435,6 +437,9 @@ BOOL LLGroupListItem::postBuild()
mProfileBtn = getChild("profile_btn");
mProfileBtn->setClickedCallback([this](LLUICtrl *, const LLSD &) { onProfileBtnClick(); });
+ mNoticesBtn = getChild("notices_btn");
+ mNoticesBtn->setClickedCallback([this](LLUICtrl *, const LLSD &) { onNoticesBtnClick(); });
+
mVisibilityHideBtn = findChild("visibility_hide_btn");
if (mVisibilityHideBtn)
{
@@ -470,13 +475,17 @@ void LLGroupListItem::onMouseEnter(S32 x, S32 y, MASK mask)
{
mInfoBtn->setVisible(true);
mProfileBtn->setVisible(true);
- if (mForAgent && mVisibilityHideBtn)
+ if (mForAgent)
{
LLGroupData agent_gdatap;
if (gAgent.getGroupData(mGroupID, agent_gdatap))
{
- mVisibilityHideBtn->setVisible(agent_gdatap.mListInProfile);
- mVisibilityShowBtn->setVisible(!agent_gdatap.mListInProfile);
+ if (mVisibilityHideBtn)
+ {
+ mVisibilityHideBtn->setVisible(agent_gdatap.mListInProfile);
+ mVisibilityShowBtn->setVisible(!agent_gdatap.mListInProfile);
+ }
+ mNoticesBtn->setVisible(true);
}
}
}
@@ -489,6 +498,7 @@ void LLGroupListItem::onMouseLeave(S32 x, S32 y, MASK mask)
getChildView("hovered_icon")->setVisible( false);
mInfoBtn->setVisible(false);
mProfileBtn->setVisible(false);
+ mNoticesBtn->setVisible(false);
if (mVisibilityHideBtn)
{
mVisibilityHideBtn->setVisible(false);
@@ -583,6 +593,11 @@ void LLGroupListItem::onProfileBtnClick()
LLGroupActions::show(mGroupID);
}
+void LLGroupListItem::onNoticesBtnClick()
+{
+ LLGroupActions::show(mGroupID, true);
+}
+
void LLGroupListItem::onVisibilityBtnClick(bool new_visibility)
{
LLGroupData agent_gdatap;
diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h
index 69257a2d7c..0e2dcf5fb3 100644
--- a/indra/newview/llgrouplist.h
+++ b/indra/newview/llgrouplist.h
@@ -123,6 +123,7 @@ private:
void setBold(bool bold);
void onInfoBtnClick();
void onProfileBtnClick();
+ void onNoticesBtnClick();
void onVisibilityBtnClick(bool new_visibility);
LLTextBox* mGroupNameBox;
@@ -130,6 +131,7 @@ private:
LLGroupIconCtrl* mGroupIcon;
LLButton* mInfoBtn;
LLButton* mProfileBtn;
+ LLButton* mNoticesBtn;
LLButton* mVisibilityHideBtn;
LLButton* mVisibilityShowBtn;
diff --git a/indra/newview/llimhandler.cpp b/indra/newview/llimhandler.cpp
index 3554412e18..bc2d9052f1 100644
--- a/indra/newview/llimhandler.cpp
+++ b/indra/newview/llimhandler.cpp
@@ -55,8 +55,7 @@ LLIMHandler::~LLIMHandler()
void LLIMHandler::initChannel()
{
S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
- S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
- mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound);
+ mChannel.get()->init(channel_right_bound - NOTIFY_BOX_WIDTH, channel_right_bound);
}
//--------------------------------------------------------------------------
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 0eb5a2c365..187dbdd3a2 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -581,6 +581,12 @@ void chatterBoxHistoryCoro(std::string url, LLUUID sessionId, std::string from,
return;
}
+ if (LLApp::isExiting() || gDisconnected)
+ {
+ LL_DEBUGS("ChatHistory") << "Ignoring chat history response, shutting down" << LL_ENDL;
+ return;
+ }
+
// Add history to IM session
LLSD history = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT];
@@ -3917,6 +3923,12 @@ public:
const LLSD& context,
const LLSD& input) const
{
+ if (LLApp::isExiting() || gDisconnected)
+ {
+ LL_DEBUGS("ChatHistory") << "Ignoring ChatterBox session, Shutting down" << LL_ENDL;
+ return;
+ }
+
LLSD body;
LLUUID temp_session_id;
LLUUID session_id;
diff --git a/indra/newview/llinspect.cpp b/indra/newview/llinspect.cpp
index 92272c7f45..101b9bdc2d 100644
--- a/indra/newview/llinspect.cpp
+++ b/indra/newview/llinspect.cpp
@@ -45,8 +45,8 @@ LLInspect::~LLInspect()
// virtual
void LLInspect::draw()
{
- static LLCachedControl FADE_TIME(*LLUI::getInstance()->mSettingGroups["config"], "InspectorFadeTime", 1.f);
- static LLCachedControl STAY_TIME(*LLUI::getInstance()->mSettingGroups["config"], "InspectorShowTime", 1.f);
+ const F32 FADE_TIME = 0.5f;
+ const F32 STAY_TIME = 3.f;
if (mOpenTimer.getStarted())
{
LLFloater::draw();
@@ -59,7 +59,7 @@ void LLInspect::draw()
}
else if (mCloseTimer.getStarted())
{
- F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_TIME(), 1.f, 0.f);
+ F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 1.f, 0.f);
LLViewDrawContext context(alpha);
LLFloater::draw();
if (mCloseTimer.getElapsedTimeF32() > FADE_TIME)
diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index 61213c1a5d..2bd4796bd0 100644
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -261,12 +261,15 @@ void LLInspectAvatar::requestUpdate()
void LLInspectAvatar::processAvatarData(LLAvatarData* data)
{
LLStringUtil::format_map_t args;
- {
- std::string birth_date = LLTrans::getString("AvatarBirthDateFormat");
- LLStringUtil::format(birth_date, LLSD().with("datetime", (S32) data->born_on.secondsSinceEpoch()));
- args["[BORN_ON]"] = birth_date;
- }
- args["[AGE]"] = LLDateUtil::ageFromDate(data->born_on, LLDate::now());
+
+ std::string birth_date = LLTrans::getString(data->hide_age ?
+ "AvatarBirthDateFormatShort" :
+ "AvatarBirthDateFormatFull");
+ LLStringUtil::format(birth_date, LLSD().with("datetime", (S32)data->born_on.secondsSinceEpoch()));
+ args["[BORN_ON]"] = birth_date;
+ args["[AGE]"] = data->hide_age ?
+ LLStringUtilBase::null :
+ LLDateUtil::ageFromDate(data->born_on, LLDate::now());
args["[SL_PROFILE]"] = data->about_text;
args["[RW_PROFILE"] = data->fl_about_text;
args["[ACCTTYPE]"] = LLAvatarPropertiesProcessor::accountType(data);
diff --git a/indra/newview/llinspecttoast.cpp b/indra/newview/llinspecttoast.cpp
index 0104714a16..2e05893489 100644
--- a/indra/newview/llinspecttoast.cpp
+++ b/indra/newview/llinspecttoast.cpp
@@ -61,7 +61,7 @@ LLInspectToast::LLInspectToast(const LLSD& notification_id) :
LLInspect(LLSD()), mPanel(NULL)
{
LLScreenChannelBase* channel = LLChannelManager::getInstance()->findChannelByID(
- LLUUID(gSavedSettings.getString("NotificationChannelUUID")));
+ LLNotificationsUI::NOTIFICATION_CHANNEL_UUID);
mScreenChannel = dynamic_cast(channel);
if(NULL == mScreenChannel)
{
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 5e66fadd4c..fbb4ac8801 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -90,6 +90,7 @@
void copy_slurl_to_clipboard_callback_inv(const std::string& slurl);
const F32 SOUND_GAIN = 1.0f;
+const F32 FOLDER_LOADING_MESSAGE_DELAY = 0.5f; // Seconds to wait before showing the LOADING... text in folder views
using namespace LLOldEvents;
@@ -308,9 +309,9 @@ void LLInvFVBridge::setCreationDate(time_t creation_date_utc)
// Can be destroyed (or moved to trash)
-BOOL LLInvFVBridge::isItemRemovable() const
+BOOL LLInvFVBridge::isItemRemovable(bool check_worn) const
{
- return get_is_item_removable(getInventoryModel(), mUUID);
+ return get_is_item_removable(getInventoryModel(), mUUID, check_worn);
}
// Can be moved to another folder
@@ -772,9 +773,6 @@ void hide_context_entries(LLMenuGL& menu,
bool found = false;
- std::string myinput;
- std::vector mylist{ "a", "b", "c" };
-
menuentry_vec_t::const_iterator itor2 = std::find(entries_to_show.begin(), entries_to_show.end(), name);
if (itor2 != entries_to_show.end())
{
@@ -874,7 +872,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
}
items.push_back(std::string("Cut"));
- if (!isItemMovable() || !isItemRemovable())
+ if (!isItemMovable() || !canMenuCut())
{
disabled_items.push_back(std::string("Cut"));
}
@@ -923,7 +921,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
if(!single_folder_root)
{
items.push_back(std::string("Cut"));
- if (!isItemMovable() || !isItemRemovable())
+ if (!isItemMovable() || !canMenuCut())
{
disabled_items.push_back(std::string("Cut"));
}
@@ -1068,7 +1066,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
items.push_back(std::string("Delete"));
- if (!isItemRemovable() || isPanelActive("Favorite Items"))
+ if (isPanelActive("Favorite Items") || !canMenuDelete())
{
disabled_items.push_back(std::string("Delete"));
}
@@ -1224,6 +1222,16 @@ void LLInvFVBridge::addLinkReplaceMenuOption(menuentry_vec_t& items, menuentry_v
}
}
+bool LLInvFVBridge::canMenuDelete()
+{
+ return isItemRemovable(false);
+}
+
+bool LLInvFVBridge::canMenuCut()
+{
+ return isItemRemovable(true);
+}
+
// *TODO: remove this
BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
{
@@ -2415,45 +2423,16 @@ void LLFolderBridge::update()
}
}
-
-// Iterate through a folder's children to determine if
-// all the children are removable.
-class LLIsItemRemovable : public LLFolderViewFunctor
-{
-public:
- LLIsItemRemovable() : mPassed(TRUE) {}
- virtual void doFolder(LLFolderViewFolder* folder)
- {
- mPassed &= folder->getViewModelItem()->isItemRemovable();
- }
- virtual void doItem(LLFolderViewItem* item)
- {
- mPassed &= item->getViewModelItem()->isItemRemovable();
- }
- BOOL mPassed;
-};
-
// Can be destroyed (or moved to trash)
-BOOL LLFolderBridge::isItemRemovable() const
+BOOL LLFolderBridge::isItemRemovable(bool check_worn) const
{
- if (!get_is_category_removable(getInventoryModel(), mUUID))
+ if (!get_is_category_and_children_removable(getInventoryModel(), mUUID, check_worn))
{
return FALSE;
}
- LLInventoryPanel* panel = mInventoryPanel.get();
- LLFolderViewFolder* folderp = dynamic_cast(panel ? panel->getItemByID(mUUID) : NULL);
- if (folderp)
- {
- LLIsItemRemovable folder_test;
- folderp->applyFunctorToChildren(folder_test);
- if (!folder_test.mPassed)
- {
- return FALSE;
- }
- }
-
- if (isMarketplaceListingsFolder() && (!LLMarketplaceData::instance().isSLMDataFetched() || LLMarketplaceData::instance().getActivationState(mUUID)))
+ if (isMarketplaceListingsFolder()
+ && (!LLMarketplaceData::instance().isSLMDataFetched() || LLMarketplaceData::instance().getActivationState(mUUID)))
{
return FALSE;
}
@@ -4386,6 +4365,10 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
disabled_items.push_back("New Settings");
}
}
+ else
+ {
+ items.push_back(std::string("New Listing Folder"));
+ }
if (menu_items_added)
{
items.push_back(std::string("Create Separator"));
@@ -4527,7 +4510,7 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t&
return;
}
- if (!isItemRemovable())
+ if (!canMenuDelete())
{
disabled_items.push_back(std::string("Delete"));
}
@@ -4898,6 +4881,192 @@ void LLFolderBridge::modifyOutfit(BOOL append)
}
}
+//static
+void LLFolderBridge::onCanDeleteIdle(void* user_data)
+{
+ LLFolderBridge* self = (LLFolderBridge*)user_data;
+
+ // we really need proper onidle mechanics that returns available time
+ const F32 EXPIRY_SECONDS = 0.008f;
+ LLTimer timer;
+ timer.setTimerExpirySec(EXPIRY_SECONDS);
+
+ LLInventoryModel* model = self->getInventoryModel();
+ if (model)
+ {
+ switch (self->mCanDeleteFolderState)
+ {
+ case CDS_INIT_FOLDER_CHECK:
+ // Can still be expensive, split it further?
+ model->collectDescendents(
+ self->mUUID,
+ self->mFoldersToCheck,
+ self->mItemsToCheck,
+ LLInventoryModel::EXCLUDE_TRASH);
+ self->mCanDeleteFolderState = CDS_PROCESSING_ITEMS;
+ break;
+
+ case CDS_PROCESSING_ITEMS:
+ while (!timer.hasExpired() && !self->mItemsToCheck.empty())
+ {
+ LLViewerInventoryItem* item = self->mItemsToCheck.back().get();
+ if (item)
+ {
+ if (LLAppearanceMgr::instance().getIsProtectedCOFItem(item))
+ {
+ if (get_is_item_worn(item))
+ {
+ // At the moment we disable 'cut' if category has worn items (do we need to?)
+ // but allow 'delete' to happen since it will prompt user to detach
+ self->mCanCut = false;
+ }
+ }
+
+ if (!item->getIsLinkType() && get_is_item_worn(item))
+ {
+ self->mCanCut = false;
+ }
+ }
+ self->mItemsToCheck.pop_back();
+ }
+ self->mCanDeleteFolderState = CDS_PROCESSING_FOLDERS;
+ break;
+ case CDS_PROCESSING_FOLDERS:
+ {
+ const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink();
+ LLViewerInventoryCategory* outfit_linked_category = base_outfit_link ? base_outfit_link->getLinkedCategory() : nullptr;
+
+ while (!timer.hasExpired() && !self->mFoldersToCheck.empty())
+ {
+ LLViewerInventoryCategory* cat = self->mFoldersToCheck.back().get();
+ if (cat)
+ {
+ const LLFolderType::EType folder_type = cat->getPreferredType();
+ if (LLFolderType::lookupIsProtectedType(folder_type))
+ {
+ self->mCanCut = false;
+ self->mCanDelete = false;
+ self->completeDeleteProcessing();
+ break;
+ }
+
+ // Can't delete the outfit that is currently being worn.
+ if (folder_type == LLFolderType::FT_OUTFIT)
+ {
+ if (cat == outfit_linked_category)
+ {
+ self->mCanCut = false;
+ self->mCanDelete = false;
+ self->completeDeleteProcessing();
+ break;
+ }
+ }
+ }
+ self->mFoldersToCheck.pop_back();
+ }
+ }
+ self->mCanDeleteFolderState = CDS_DONE;
+ break;
+ case CDS_DONE:
+ self->completeDeleteProcessing();
+ break;
+ }
+ }
+}
+
+bool LLFolderBridge::canMenuDelete()
+{
+ LLInventoryModel* model = getInventoryModel();
+ if (!model) return false;
+ LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
+ if (!category)
+ {
+ return false;
+ }
+
+ S32 version = category->getVersion();
+ if (mLastCheckedVersion == version)
+ {
+ return mCanDelete;
+ }
+
+ initCanDeleteProcessing(model, version);
+ return false;
+}
+
+bool LLFolderBridge::canMenuCut()
+{
+ LLInventoryModel* model = getInventoryModel();
+ if (!model) return false;
+ LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
+ if (!category)
+ {
+ return false;
+ }
+
+ S32 version = category->getVersion();
+ if (mLastCheckedVersion == version)
+ {
+ return mCanCut;
+ }
+
+ initCanDeleteProcessing(model, version);
+ return false;
+}
+
+void LLFolderBridge::initCanDeleteProcessing(LLInventoryModel* model, S32 version)
+{
+ if (mCanDeleteFolderState == CDS_DONE
+ || mInProgressVersion != version)
+ {
+ if (get_is_category_removable(model, mUUID))
+ {
+ // init recursive check of content
+ mInProgressVersion = version;
+ mCanCut = true;
+ mCanDelete = true;
+ mCanDeleteFolderState = CDS_INIT_FOLDER_CHECK;
+ mFoldersToCheck.clear();
+ mItemsToCheck.clear();
+ gIdleCallbacks.addFunction(onCanDeleteIdle, this);
+ }
+ else
+ {
+ // no check needed
+ mCanDelete = false;
+ mCanCut = false;
+ mLastCheckedVersion = version;
+ mCanDeleteFolderState = CDS_DONE;
+ mFoldersToCheck.clear();
+ mItemsToCheck.clear();
+ }
+ }
+}
+
+void LLFolderBridge::completeDeleteProcessing()
+{
+ LLInventoryModel* model = getInventoryModel();
+ LLViewerInventoryCategory* category = model ? (LLViewerInventoryCategory*)model->getCategory(mUUID) : nullptr;
+ if (model && category && category->getVersion() == mInProgressVersion)
+ {
+ mLastCheckedVersion = mInProgressVersion;
+ mCanDeleteFolderState = CDS_DONE;
+ gIdleCallbacks.deleteFunction(onCanDeleteIdle, this);
+ }
+ else
+ {
+ mCanDelete = false;
+ mCanCut = false;
+ mLastCheckedVersion = LLViewerInventoryCategory::VERSION_UNKNOWN;
+ mCanDeleteFolderState = CDS_DONE;
+ }
+
+ if (mRoot)
+ {
+ mRoot->updateMenu();
+ }
+}
+
// +=================================================+
// | LLMarketplaceFolderBridge |
@@ -4941,9 +5110,7 @@ LLUIImagePtr LLMarketplaceFolderBridge::getMarketplaceFolderIcon(BOOL is_open) c
std::string LLMarketplaceFolderBridge::getLabelSuffix() const
{
- static LLCachedControl folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime", 0.5f);
-
- if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay())
+ if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= FOLDER_LOADING_MESSAGE_DELAY)
{
return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str());
}
@@ -5061,6 +5228,27 @@ void drop_to_favorites_cb(const LLUUID& id, LLPointer cb1,
cb2->fire(id);
}
+LLFolderBridge::LLFolderBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid)
+ : LLInvFVBridge(inventory, root, uuid)
+ , mCallingCards(FALSE)
+ , mWearables(FALSE)
+ , mIsLoading(false)
+ , mShowDescendantsCount(false)
+ , mCanDeleteFolderState(CDS_DONE)
+ , mLastCheckedVersion(S32_MIN)
+ , mInProgressVersion(S32_MIN)
+ , mCanDelete(false)
+ , mCanCut(false)
+{
+}
+
+LLFolderBridge::~LLFolderBridge()
+{
+ gIdleCallbacks.deleteFunction(onCanDeleteIdle, this);
+}
+
void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item, LLPointer cb)
{
// use callback to rearrange favorite landmarks after adding
@@ -6654,6 +6842,26 @@ LLInventoryObject* LLObjectBridge::getObject() const
return object;
}
+LLViewerInventoryItem* LLObjectBridge::getItem() const
+{
+ LLInventoryModel* model = getInventoryModel();
+ if (model)
+ {
+ return model->getItem(mUUID);
+ }
+ return NULL;
+}
+
+LLViewerInventoryCategory* LLObjectBridge::getCategory() const
+{
+ LLInventoryModel* model = getInventoryModel();
+ if (model)
+ {
+ return model->getCategory(mUUID);
+ }
+ return NULL;
+}
+
// virtual
void LLObjectBridge::performAction(LLInventoryModel* model, std::string action)
{
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index e1e0bbb5bd..b0139e225e 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -114,7 +114,7 @@ public:
virtual BOOL isItemRenameable() const { return TRUE; }
virtual BOOL isMultiPreviewAllowed() { return TRUE; }
//virtual BOOL renameItem(const std::string& new_name) {}
- virtual BOOL isItemRemovable() const;
+ virtual BOOL isItemRemovable(bool check_worn = true) const;
virtual BOOL isItemMovable() const;
virtual BOOL isItemInTrash() const;
virtual bool isItemInOutfits() const;
@@ -162,6 +162,9 @@ protected:
virtual void addLinkReplaceMenuOption(menuentry_vec_t& items,
menuentry_vec_t& disabled_items);
+ virtual bool canMenuDelete();
+ virtual bool canMenuCut();
+
protected:
LLInvFVBridge(LLInventoryPanel* inventory, LLFolderView* root, const LLUUID& uuid);
@@ -272,13 +275,9 @@ class LLFolderBridge : public LLInvFVBridge
public:
LLFolderBridge(LLInventoryPanel* inventory,
LLFolderView* root,
- const LLUUID& uuid)
- : LLInvFVBridge(inventory, root, uuid),
- mCallingCards(FALSE),
- mWearables(FALSE),
- mIsLoading(false),
- mShowDescendantsCount(false)
- {}
+ const LLUUID& uuid);
+
+ ~LLFolderBridge();
BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE, LLPointer cb = NULL);
BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE, LLPointer cb = NULL);
@@ -321,7 +320,7 @@ public:
void* cargo_data,
std::string& tooltip_msg);
- virtual BOOL isItemRemovable() const;
+ virtual BOOL isItemRemovable(bool check_worn = true) const;
virtual BOOL isItemMovable() const ;
virtual BOOL isUpToDate() const;
virtual bool isItemCopyable(bool can_copy_as_link = true) const;
@@ -392,6 +391,31 @@ protected:
LLTimer mTimeSinceRequestStart;
std::string mMessage;
LLRootHandle mHandle;
+
+private:
+ // checking if folder is cutable or deletable is expensive,
+ // cache values and split check over frames
+ static void onCanDeleteIdle(void* user_data);
+ void initCanDeleteProcessing(LLInventoryModel* model, S32 version);
+ void completeDeleteProcessing();
+ bool canMenuDelete();
+ bool canMenuCut();
+
+ enum ECanDeleteState
+ {
+ CDS_INIT_FOLDER_CHECK,
+ CDS_PROCESSING_ITEMS,
+ CDS_PROCESSING_FOLDERS,
+ CDS_DONE,
+ };
+
+ ECanDeleteState mCanDeleteFolderState;
+ LLInventoryModel::cat_array_t mFoldersToCheck;
+ LLInventoryModel::item_array_t mItemsToCheck;
+ S32 mLastCheckedVersion;
+ S32 mInProgressVersion;
+ bool mCanDelete;
+ bool mCanCut;
};
class LLTextureBridge : public LLItemBridge
@@ -524,6 +548,8 @@ public:
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
virtual BOOL renameItem(const std::string& new_name);
LLInventoryObject* getObject() const;
+ LLViewerInventoryItem* getItem() const;
+ LLViewerInventoryCategory* getCategory() const;
protected:
static LLUUID sContextMenuItemID; // Only valid while the context menu is open.
U32 mAttachPt;
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 168099f1e7..c8aa235506 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -596,9 +596,8 @@ BOOL get_is_parent_to_worn_item(const LLUUID& id)
return FALSE;
}
-BOOL get_is_item_worn(const LLUUID& id)
+BOOL get_is_item_worn(const LLUUID& id, const LLViewerInventoryItem* item)
{
- const LLViewerInventoryItem* item = gInventory.getItem(id);
if (!item)
return FALSE;
@@ -636,6 +635,21 @@ BOOL get_is_item_worn(const LLUUID& id)
return FALSE;
}
+BOOL get_is_item_worn(const LLUUID& id)
+{
+ const LLViewerInventoryItem* item = gInventory.getItem(id);
+ return get_is_item_worn(id, item);
+}
+
+BOOL get_is_item_worn(const LLViewerInventoryItem* item)
+{
+ if (!item)
+ {
+ return FALSE;
+ }
+ return get_is_item_worn(item->getUUID(), item);
+}
+
BOOL get_can_item_be_worn(const LLUUID& id)
{
const LLViewerInventoryItem* item = gInventory.getItem(id);
@@ -699,39 +713,39 @@ BOOL get_can_item_be_worn(const LLUUID& id)
return FALSE;
}
-BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id)
+bool get_is_item_removable(const LLInventoryModel* model, const LLUUID& id, bool check_worn)
{
if (!model)
{
- return FALSE;
+ return false;
}
// Can't delete an item that's in the library.
if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID()))
{
- return FALSE;
+ return false;
}
// Disable delete from COF folder; have users explicitly choose "detach/take off",
// unless the item is not worn but in the COF (i.e. is bugged).
- if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id))
+ const LLViewerInventoryItem* obj = model->getItem(id);
+ if (LLAppearanceMgr::instance().getIsProtectedCOFItem(obj))
{
- if (get_is_item_worn(id))
+ if (get_is_item_worn(id, obj))
{
- return FALSE;
+ return false;
}
}
- const LLInventoryObject *obj = model->getItem(id);
if (obj && obj->getIsLinkType())
{
- return TRUE;
+ return true;
}
- if (get_is_item_worn(id))
+ if (check_worn && get_is_item_worn(id, obj))
{
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
bool get_is_item_editable(const LLUUID& inv_item_id)
@@ -822,6 +836,74 @@ BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id)
return TRUE;
}
+bool get_is_category_and_children_removable(LLInventoryModel* model, const LLUUID& folder_id, bool check_worn)
+{
+ if (!get_is_category_removable(model, folder_id))
+ {
+ return false;
+ }
+
+ const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ if (mp_id.notNull() && gInventory.isObjectDescendentOf(folder_id, mp_id))
+ {
+ return false;
+ }
+
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+ model->collectDescendents(
+ folder_id,
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH);
+
+ if (check_worn)
+ {
+ for (LLInventoryModel::item_array_t::value_type& item : item_array)
+ {
+ // Disable delete/cut from COF folder; have users explicitly choose "detach/take off",
+ // unless the item is not worn but in the COF (i.e. is bugged).
+ if (item)
+ {
+ if (LLAppearanceMgr::instance().getIsProtectedCOFItem(item))
+ {
+ if (get_is_item_worn(item))
+ {
+ return false;
+ }
+ }
+
+ if (!item->getIsLinkType() && get_is_item_worn(item))
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink();
+ LLViewerInventoryCategory* outfit_linked_category = base_outfit_link ? base_outfit_link->getLinkedCategory() : nullptr;
+ for (LLInventoryModel::cat_array_t::value_type& cat : cat_array)
+ {
+ const LLFolderType::EType folder_type = cat->getPreferredType();
+ if (LLFolderType::lookupIsProtectedType(folder_type))
+ {
+ return false;
+ }
+
+ // Can't delete the outfit that is currently being worn.
+ if (folder_type == LLFolderType::FT_OUTFIT)
+ {
+ if (cat == outfit_linked_category)
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id)
{
if (!model)
@@ -2800,7 +2882,7 @@ bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventory
{
if (item)
{
- return !get_is_item_removable(&gInventory, item->getUUID());
+ return !get_is_item_removable(&gInventory, item->getUUID(), true);
}
if (cat)
{
@@ -3082,6 +3164,8 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
{
const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
bool marketplacelistings_item = false;
+ bool has_worn = false;
+ bool needs_replacement = false;
LLAllDescendentsPassedFilter f;
for (std::set::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it)
{
@@ -3090,14 +3174,69 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
folder->applyFunctorRecursively(f);
}
LLFolderViewModelItemInventory * viewModel = dynamic_cast((*it)->getViewModelItem());
- if (viewModel && gInventory.isObjectDescendentOf(viewModel->getUUID(), marketplacelistings_id))
+ LLUUID obj_id = viewModel->getUUID();
+ if (viewModel && gInventory.isObjectDescendentOf(obj_id, marketplacelistings_id))
{
marketplacelistings_item = true;
break;
}
+
+ LLViewerInventoryCategory* cat = gInventory.getCategory(obj_id);
+ if (cat)
+ {
+ LLInventoryModel::cat_array_t categories;
+ LLInventoryModel::item_array_t items;
+
+ gInventory.collectDescendents(obj_id, categories, items, FALSE);
+
+ for (LLInventoryModel::item_array_t::value_type& item : items)
+ {
+ if (get_is_item_worn(item))
+ {
+ has_worn = true;
+ LLWearableType::EType type = item->getWearableType();
+ if (type == LLWearableType::WT_SHAPE
+ || type == LLWearableType::WT_SKIN
+ || type == LLWearableType::WT_HAIR
+ || type == LLWearableType::WT_EYES)
+ {
+ needs_replacement = true;
+ break;
+ }
+ }
+ }
+ if (needs_replacement)
+ {
+ break;
+ }
+ }
+ LLViewerInventoryItem* item = gInventory.getItem(obj_id);
+ if (item && get_is_item_worn(item))
+ {
+ has_worn = true;
+ LLWearableType::EType type = item->getWearableType();
+ if (type == LLWearableType::WT_SHAPE
+ || type == LLWearableType::WT_SKIN
+ || type == LLWearableType::WT_HAIR
+ || type == LLWearableType::WT_EYES)
+ {
+ needs_replacement = true;
+ break;
+ }
+ }
}
// Fall through to the generic confirmation if the user choose to ignore the specialized one
- if ( (!f.allDescendentsPassedFilter()) && !marketplacelistings_item && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) )
+ if (needs_replacement)
+ {
+ LLNotificationsUtil::add("CantDeleteRequiredClothing");
+ }
+ else if (has_worn)
+ {
+ LLSD payload;
+ payload["has_worn"] = true;
+ LLNotificationsUtil::add("DeleteWornItems", LLSD(), payload, boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle()));
+ }
+ else if ( (!f.allDescendentsPassedFilter()) && !marketplacelistings_item && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) )
{
LLNotificationsUtil::add("DeleteFilteredItems", LLSD(), LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle()));
}
@@ -3420,12 +3559,82 @@ void LLInventoryAction::onItemsRemovalConfirmation(const LLSD& notification, con
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option == 0 && !root.isDead() && !root.get()->isDead())
{
+ bool has_worn = notification["payload"]["has_worn"].asBoolean();
LLFolderView* folder_root = root.get();
//Need to remove item from DND before item is removed from root folder view
//because once removed from root folder view the item is no longer a selected item
removeItemFromDND(folder_root);
+
+ // removeSelectedItems will change selection, collect worn items beforehand
+ uuid_vec_t worn;
+ uuid_vec_t item_deletion_list;
+ uuid_vec_t cat_deletion_list;
+ if (has_worn)
+ {
+ //Get selected items
+ LLFolderView::selected_items_t selectedItems = folder_root->getSelectedItems();
+
+ //If user is in DND and deletes item, make sure the notification is not displayed by removing the notification
+ //from DND history and .xml file. Once this is done, upon exit of DND mode the item deleted will not show a notification.
+ for (LLFolderView::selected_items_t::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it)
+ {
+ LLFolderViewModelItemInventory* viewModel = dynamic_cast((*it)->getViewModelItem());
+
+ LLUUID obj_id = viewModel->getUUID();
+ LLViewerInventoryCategory* cat = gInventory.getCategory(obj_id);
+ bool cat_has_worn = false;
+ if (cat)
+ {
+ LLInventoryModel::cat_array_t categories;
+ LLInventoryModel::item_array_t items;
+
+ gInventory.collectDescendents(obj_id, categories, items, FALSE);
+
+ for (LLInventoryModel::item_array_t::value_type& item : items)
+ {
+ if (get_is_item_worn(item))
+ {
+ worn.push_back(item->getUUID());
+ cat_has_worn = true;
+ }
+ }
+ if (cat_has_worn)
+ {
+ cat_deletion_list.push_back(obj_id);
+ }
+ }
+ LLViewerInventoryItem* item = gInventory.getItem(obj_id);
+ if (item && get_is_item_worn(item))
+ {
+ worn.push_back(obj_id);
+ item_deletion_list.push_back(obj_id);
+ }
+ }
+ }
+
+ // removeSelectedItems will check if items are worn before deletion,
+ // don't 'unwear' yet to prevent race conditions from unwearing
+ // and removing simultaneously
folder_root->removeSelectedItems();
+ // unwear then delete the rest
+ if (!worn.empty())
+ {
+ // should fire once after every item gets detached
+ LLAppearanceMgr::instance().removeItemsFromAvatar(worn,
+ [item_deletion_list, cat_deletion_list]()
+ {
+ for (const LLUUID& id : item_deletion_list)
+ {
+ remove_inventory_item(id, NULL);
+ }
+ for (const LLUUID& id : cat_deletion_list)
+ {
+ remove_inventory_category(id, NULL);
+ }
+ });
+ }
+
// Update the marketplace listings that have been affected by the operation
updateMarketplaceFolders();
}
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 0c4b64586d..5cb996ad54 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -47,17 +47,19 @@ BOOL get_is_parent_to_worn_item(const LLUUID& id);
// Is this item or its baseitem is worn, attached, etc...
BOOL get_is_item_worn(const LLUUID& id);
+BOOL get_is_item_worn(const LLViewerInventoryItem* item);
// Could this item be worn (correct type + not already being worn)
BOOL get_can_item_be_worn(const LLUUID& id);
-BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id);
+bool get_is_item_removable(const LLInventoryModel* model, const LLUUID& id, bool check_worn);
// Performs the appropiate edit action (if one exists) for this item
bool get_is_item_editable(const LLUUID& inv_item_id);
void handle_item_edit(const LLUUID& inv_item_id);
BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id);
+bool get_is_category_and_children_removable(LLInventoryModel* model, const LLUUID& folder_id, bool check_worn);
BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id);
diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp
index 16cdc14b15..329c0d751a 100644
--- a/indra/newview/llinventorygallery.cpp
+++ b/indra/newview/llinventorygallery.cpp
@@ -187,7 +187,7 @@ LLInventoryGallery::~LLInventoryGallery()
mHiddenItems.pop_back();
panelp->die();
}
-
+
if (gInventory.containsObserver(mCategoriesObserver))
{
@@ -200,7 +200,7 @@ LLInventoryGallery::~LLInventoryGallery()
gInventory.removeObserver(mThumbnailsObserver);
}
delete mThumbnailsObserver;
-
+
LLGestureMgr::instance().removeObserver(mGestureObserver);
delete mGestureObserver;
}
@@ -263,7 +263,7 @@ void LLInventoryGallery::updateRootFolder()
updateRemovedItem(mHiddenItems[i]->getUUID());
}
mItemBuildQuery.clear();
-
+
if (gInventory.containsObserver(mCategoriesObserver))
{
gInventory.removeObserver(mCategoriesObserver);
@@ -284,7 +284,7 @@ void LLInventoryGallery::updateRootFolder()
mRootChangedSignal();
gInventory.addObserver(mCategoriesObserver);
-
+
// Start observing changes in selected category.
mCategoriesObserver->addCategory(mFolderID,
boost::bind(&LLInventoryGallery::refreshList, this, mFolderID));
@@ -294,7 +294,7 @@ void LLInventoryGallery::updateRootFolder()
// the observer will refresh the list as soon as the new items
// arrive.
category->fetch();
-
+
//refreshList(cat_id);
LLInventoryModel::cat_array_t* cat_array;
LLInventoryModel::item_array_t* item_array;
@@ -308,7 +308,7 @@ void LLInventoryGallery::updateRootFolder()
{
mItemBuildQuery.insert((*iter)->getUUID());
}
-
+
for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin();
iter != item_array->end();
iter++)
@@ -448,7 +448,7 @@ void LLInventoryGallery::reArrangeRows(S32 row_diff)
buf_items.push_back(*it);
}
mHiddenItems.clear();
-
+
mItemsInRow+= row_diff;
updateGalleryWidth();
@@ -458,7 +458,7 @@ void LLInventoryGallery::reArrangeRows(S32 row_diff)
{
return compareGalleryItem(item1, item2, sort_by_date, sort_folders_by_name);
});
-
+
for (std::vector::const_iterator it = buf_items.begin(); it != buf_items.end(); ++it)
{
(*it)->setHidden(false);
@@ -735,7 +735,7 @@ void LLInventoryGallery::setFilterSubString(const std::string& string)
{
mFilterSubString = string;
mFilter->setFilterSubString(string);
-
+
//reArrangeRows();
}
@@ -763,7 +763,7 @@ bool LLInventoryGallery::checkAgainstFilters(LLInventoryGalleryItem* item, const
{
return false;
}
-
+
bool hidden = false;
if(mFilter->getFilterCreatorType() == LLInventoryFilter::FILTERCREATOR_SELF)
@@ -806,7 +806,7 @@ bool LLInventoryGallery::checkAgainstFilters(LLInventoryGalleryItem* item, const
desc = item->getItemName() + item->getItemNameSuffix();
break;
}
-
+
LLStringUtil::toUpper(desc);
std::string cur_filter = filter_substring;
@@ -1435,7 +1435,7 @@ void LLInventoryGallery::onFocusReceived()
LLInventoryGalleryItem* focus_item = NULL;
for (const LLUUID& id : mSelectedItemIDs)
{
- if (mItemMap[id])
+ if (mItemMap[id] && !mItemMap[id]->isHidden())
{
focus_item = mItemMap[id];
focus_item->setSelected(true);
@@ -1668,6 +1668,45 @@ void LLInventoryGallery::cut()
mFilterSubString.clear();
}
+
+
+bool is_category_removable(const LLUUID& folder_id, bool check_worn)
+{
+ if (!get_is_category_removable(&gInventory, folder_id))
+ {
+ return false;
+ }
+
+ // check children
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+ gInventory.getDirectDescendentsOf(folder_id, cat_array, item_array);
+
+ for (LLInventoryModel::item_array_t::value_type& item : *item_array)
+ {
+ if (!get_is_item_removable(&gInventory, item->getUUID(), check_worn))
+ {
+ return false;
+ }
+ }
+
+ for (LLInventoryModel::cat_array_t::value_type& cat : *cat_array)
+ {
+ if (!is_category_removable(cat->getUUID(), check_worn))
+ {
+ return false;
+ }
+ }
+
+ const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ if (mp_id.notNull() && gInventory.isObjectDescendentOf(folder_id, mp_id))
+ {
+ return false;
+ }
+
+ return true;
+}
+
BOOL LLInventoryGallery::canCut() const
{
if (!getVisible() || !getEnabled() || mSelectedItemIDs.empty())
@@ -1680,12 +1719,12 @@ BOOL LLInventoryGallery::canCut() const
LLViewerInventoryCategory* cat = gInventory.getCategory(id);
if (cat)
{
- if (!get_is_category_removable(&gInventory, id))
+ if (!get_is_category_and_children_removable(&gInventory, id, true))
{
return FALSE;
}
}
- else if (!get_is_item_removable(&gInventory, id))
+ else if (!get_is_item_removable(&gInventory, id, true))
{
return FALSE;
}
@@ -1864,42 +1903,149 @@ void LLInventoryGallery::onDelete(const LLSD& notification, const LLSD& response
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option == 0)
{
- for (const LLUUID& id : selected_ids)
+ bool has_worn = notification["payload"]["has_worn"].asBoolean();
+ uuid_vec_t worn;
+ uuid_vec_t item_deletion_list;
+ uuid_vec_t cat_deletion_list;
+ for (const LLUUID& obj_id : selected_ids)
{
- LLInventoryObject* obj = gInventory.getObject(id);
- if (!obj)
+ LLViewerInventoryCategory* cat = gInventory.getCategory(obj_id);
+ if (cat)
{
- return;
- }
- if (obj->getType() == LLAssetType::AT_CATEGORY)
- {
- if (get_is_category_removable(&gInventory, id))
+ bool cat_has_worn = false;
+ if (has_worn)
{
- gInventory.removeCategory(id);
+ LLInventoryModel::cat_array_t categories;
+ LLInventoryModel::item_array_t items;
+
+ gInventory.collectDescendents(obj_id, categories, items, FALSE);
+
+ for (LLInventoryModel::item_array_t::value_type& item : items)
+ {
+ if (get_is_item_worn(item))
+ {
+ worn.push_back(item->getUUID());
+ cat_has_worn = true;
+ }
+ }
+ }
+ if (cat_has_worn)
+ {
+ cat_deletion_list.push_back(obj_id);
+ }
+ else
+ {
+ gInventory.removeCategory(obj_id);
}
}
- else
+ LLViewerInventoryItem* item = gInventory.getItem(obj_id);
+ if (item)
{
- if (get_is_item_removable(&gInventory, id))
+ if (has_worn && get_is_item_worn(item))
{
- gInventory.removeItem(id);
+ worn.push_back(item->getUUID());
+ item_deletion_list.push_back(item->getUUID());
+ }
+ else
+ {
+ gInventory.removeItem(obj_id);
}
}
}
+
+ if (!worn.empty())
+ {
+ // should fire once after every item gets detached
+ LLAppearanceMgr::instance().removeItemsFromAvatar(worn,
+ [item_deletion_list, cat_deletion_list]()
+ {
+ for (const LLUUID& id : item_deletion_list)
+ {
+ remove_inventory_item(id, NULL);
+ }
+ for (const LLUUID& id : cat_deletion_list)
+ {
+ remove_inventory_category(id, NULL);
+ }
+ });
+ }
}
}
void LLInventoryGallery::deleteSelection()
{
- if (!LLInventoryAction::sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session
+ bool has_worn = false;
+ bool needs_replacement = false;
+ for (const LLUUID& id : mSelectedItemIDs)
{
- LLNotifications::instance().setIgnored("DeleteItems", false);
- LLInventoryAction::sDeleteConfirmationDisplayed = true;
+ LLViewerInventoryCategory* cat = gInventory.getCategory(id);
+ if (cat)
+ {
+ LLInventoryModel::cat_array_t categories;
+ LLInventoryModel::item_array_t items;
+
+ gInventory.collectDescendents(id, categories, items, FALSE);
+
+ for (LLInventoryModel::item_array_t::value_type& item : items)
+ {
+ if (get_is_item_worn(item))
+ {
+ has_worn = true;
+ LLWearableType::EType type = item->getWearableType();
+ if (type == LLWearableType::WT_SHAPE
+ || type == LLWearableType::WT_SKIN
+ || type == LLWearableType::WT_HAIR
+ || type == LLWearableType::WT_EYES)
+ {
+ needs_replacement = true;
+ break;
+ }
+ }
+ }
+ if (needs_replacement)
+ {
+ break;
+ }
+ }
+
+ LLViewerInventoryItem* item = gInventory.getItem(id);
+ if (item && get_is_item_worn(item))
+ {
+ has_worn = true;
+ LLWearableType::EType type = item->getWearableType();
+ if (type == LLWearableType::WT_SHAPE
+ || type == LLWearableType::WT_SKIN
+ || type == LLWearableType::WT_HAIR
+ || type == LLWearableType::WT_EYES)
+ {
+ needs_replacement = true;
+ break;
+ }
+ }
}
- LLSD args;
- args["QUESTION"] = LLTrans::getString("DeleteItem");
- LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryGallery::onDelete, _1, _2, mSelectedItemIDs));
+ if (needs_replacement)
+ {
+ LLNotificationsUtil::add("CantDeleteRequiredClothing");
+ }
+ else if (has_worn)
+ {
+ LLSD payload;
+ payload["has_worn"] = true;
+ LLNotificationsUtil::add("DeleteWornItems", LLSD(), payload, boost::bind(&LLInventoryGallery::onDelete, _1, _2, mSelectedItemIDs));
+ }
+ else
+ {
+ if (!LLInventoryAction::sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session
+ {
+ LLNotifications::instance().setIgnored("DeleteItems", false);
+ LLInventoryAction::sDeleteConfirmationDisplayed = true;
+ }
+
+ LLSD args;
+ args["QUESTION"] = LLTrans::getString("DeleteItem");
+ LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryGallery::onDelete, _1, _2, mSelectedItemIDs));
+ }
}
bool LLInventoryGallery::canDeleteSelection()
@@ -1925,7 +2071,7 @@ bool LLInventoryGallery::canDeleteSelection()
return false;
}
}
- else if (!get_is_item_removable(&gInventory, id))
+ else if (!get_is_item_removable(&gInventory, id, true))
{
return false;
}
@@ -2209,7 +2355,7 @@ void LLInventoryGallery::onCOFChanged()
LLCommonUtils::computeDifference(vnew, mCOFLinkedItems, vadded, vremoved);
mCOFLinkedItems = vnew;
-
+
for (uuid_vec_t::const_iterator iter = vadded.begin();
iter != vadded.end();
++iter)
@@ -2240,7 +2386,7 @@ void LLInventoryGallery::onGesturesChanged()
LLCommonUtils::computeDifference(vnew, mActiveGestures, vadded, vremoved);
mActiveGestures = vnew;
-
+
for (uuid_vec_t::const_iterator iter = vadded.begin();
iter != vadded.end();
++iter)
@@ -2418,7 +2564,7 @@ void LLInventoryGallery::startDrag()
ids.push_back(selected_id);
}
- const LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id);
+ const LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id);
if (cat)
{
if (gInventory.isObjectDescendentOf(selected_id, gInventory.getLibraryRootFolderID()))
@@ -2496,7 +2642,7 @@ bool LLInventoryGallery::checkAgainstFilterType(const LLUUID& object_id)
break;
}
}
-
+
if (filterTypes & LLInventoryFilter::FILTERTYPE_DATE)
{
const U16 HOURS_TO_SECONDS = 3600;
@@ -2939,7 +3085,7 @@ void LLThumbnailsObserver::changed(U32 mask)
{
const LLUUID& obj_id = (*iter).first;
LLItemData& data = (*iter).second;
-
+
LLInventoryObject* obj = gInventory.getObject(obj_id);
if (!obj)
{
@@ -3150,7 +3296,7 @@ BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop,
//
//--------------------------------------------------------------------------------
-
+
//--------------------------------------------------------------------------------
// Determine if item can be moved & dropped
// Note: if user_confirm is false, we already went through those accept logic test and can skip them
@@ -3177,7 +3323,7 @@ BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop,
{
//disable dropping in or out of marketplace for now
return FALSE;
-
+
/*const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, folder_id);
LLViewerInventoryCategory * dest_folder = cat;
accept = can_move_item_to_marketplace(master_folder, dest_folder, inv_item, tooltip_msg, LLToolDragAndDrop::instance().getCargoCount() - LLToolDragAndDrop::instance().getCargoIndex());*/
@@ -3189,7 +3335,7 @@ BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop,
LLViewerInventoryCategory * dest_folder = cat;
accept = dest_folder->acceptItem(inv_item);
}
-
+
LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
if (accept && drop)
@@ -3263,7 +3409,7 @@ BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop,
gInventory.changeItemParent((LLViewerInventoryItem*)inv_item, folder_id, move_is_into_trash);
}
-
+
if (move_is_from_marketplacelistings)
{
// If we move from an active (listed) listing, checks that it's still valid, if not, unlist
@@ -3483,7 +3629,7 @@ BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,
const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
//const LLUUID from_folder_uuid = inv_cat->getParentUUID();
-
+
const BOOL move_is_into_current_outfit = (dest_id == current_outfit_id);
const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(dest_id, marketplacelistings_id);
const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(cat_id, marketplacelistings_id);
@@ -3592,7 +3738,7 @@ BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,
is_movable = FALSE;
// tooltip?
}
-
+
LLInventoryModel::cat_array_t descendent_categories;
LLInventoryModel::item_array_t descendent_items;
if (is_movable)
@@ -3658,7 +3804,7 @@ BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,
}
}
}
-
+
if (is_movable && move_is_into_marketplacelistings)
{
const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, dest_id);
@@ -3731,7 +3877,7 @@ BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,
{
//disable dropping in or out of marketplace for now
return FALSE;
-
+
// If we are moving a folder at the listing folder level (i.e. its parent is the marketplace listings folder)
/*if (from_folder_uuid == marketplacelistings_id)
{
diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp
index 3cb6503a1c..4b47346473 100644
--- a/indra/newview/llinventorygallerymenu.cpp
+++ b/indra/newview/llinventorygallerymenu.cpp
@@ -62,7 +62,7 @@ LLContextMenu* LLInventoryGalleryContextMenu::createMenu()
registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery)));
enable_registrar.add("Inventory.CanSetUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::canSetUploadLocation, this, _2));
-
+
LLContextMenu* menu = createFromFile("menu_gallery_inventory.xml");
updateMenuItemsVisibility(menu);
@@ -321,7 +321,7 @@ void LLInventoryGalleryContextMenu::onRename(const LLSD& notification, const LLS
if (!new_name.empty())
{
LLUUID id = notification["payload"]["id"].asUUID();
-
+
LLViewerInventoryCategory* cat = gInventory.getCategory(id);
if(cat && (cat->getName() != new_name))
{
@@ -330,7 +330,7 @@ void LLInventoryGalleryContextMenu::onRename(const LLSD& notification, const LLS
update_inventory_category(cat->getUUID(),updates, NULL);
return;
}
-
+
LLViewerInventoryItem* item = gInventory.getItem(id);
if(item && (item->getName() != new_name))
{
@@ -379,12 +379,12 @@ bool LLInventoryGalleryContextMenu::canSetUploadLocation(const LLSD& userdata)
bool is_inbox_folder(LLUUID item_id)
{
const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
-
+
if (inbox_id.isNull())
{
return false;
}
-
+
return gInventory.isObjectDescendentOf(item_id, inbox_id);
}
@@ -495,7 +495,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
}
}
items.push_back(std::string("Purge Item"));
- if (is_folder && !get_is_category_removable(&gInventory, selected_id))
+ if (is_folder && !get_is_category_and_children_removable(&gInventory, selected_id, true))
{
disabled_items.push_back(std::string("Purge Item"));
}
@@ -542,11 +542,16 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
}
items.push_back(std::string("Cut"));
items.push_back(std::string("Delete"));
- if(!get_is_category_removable(&gInventory, selected_id))
+
+ if(!get_is_category_and_children_removable(&gInventory, selected_id, false))
{
disabled_items.push_back(std::string("Delete"));
disabled_items.push_back(std::string("Cut"));
}
+ else if (!get_is_category_and_children_removable(&gInventory, selected_id, true))
+ {
+ disabled_items.push_back(std::string("Cut"));
+ }
if(!is_inbox)
{
@@ -577,11 +582,15 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
{
items.push_back(std::string("Delete"));
}
- if(!get_is_item_removable(&gInventory, selected_id))
+ if (!get_is_item_removable(&gInventory, selected_id, false))
{
disabled_items.push_back(std::string("Delete"));
disabled_items.push_back(std::string("Cut"));
}
+ else if(!get_is_item_removable(&gInventory, selected_id, true))
+ {
+ disabled_items.push_back(std::string("Cut"));
+ }
if (selected_item && (selected_item->getInventoryType() != LLInventoryType::IT_CALLINGCARD) && !is_inbox && selected_item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()))
{
@@ -616,7 +625,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
disabled_items.push_back(std::string("Open"));
disabled_items.push_back(std::string("Open Original"));
}
-
+
if(LLAssetType::AT_GESTURE == obj->getType())
{
items.push_back(std::string("Gesture Separator"));
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 0787266adb..65b8bc9e2c 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -1744,12 +1744,10 @@ void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item,
<< " from " << make_inventory_info(item->getParentUUID())
<< " to " << make_inventory_info(new_parent_id) << LL_ENDL;
- LLInventoryModel::update_list_t update;
- LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1);
- update.push_back(old_folder);
- LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
- update.push_back(new_folder);
- accountForUpdate(update);
+ LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(), -1);
+ accountForUpdate(old_folder);
+ LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1, false);
+ accountForUpdate(new_folder);
LLPointer new_item = new LLViewerInventoryItem(item);
new_item->setParent(new_parent_id);
@@ -1779,12 +1777,10 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat,
<< " from " << make_inventory_info(cat->getParentUUID())
<< " to " << make_inventory_info(new_parent_id) << LL_ENDL;
- LLInventoryModel::update_list_t update;
LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1);
- update.push_back(old_folder);
- LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
- update.push_back(new_folder);
- accountForUpdate(update);
+ accountForUpdate(old_folder);
+ LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1, false);
+ accountForUpdate(new_folder);
LLPointer new_cat = new LLViewerInventoryCategory(cat);
new_cat->setParent(new_parent_id);
@@ -2542,7 +2538,10 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const
{
descendents_actual += update.mDescendentDelta;
cat->setDescendentCount(descendents_actual);
- cat->setVersion(++version);
+ if (update.mChangeVersion)
+ {
+ cat->setVersion(++version);
+ }
LL_DEBUGS(LOG_INV) << "accounted: '" << cat->getName() << "' "
<< version << " with " << descendents_actual
<< " descendents." << LL_ENDL;
@@ -2570,7 +2569,7 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const
}
void LLInventoryModel::accountForUpdate(
- const LLInventoryModel::update_list_t& update)
+ const LLInventoryModel::update_list_t& update) const
{
update_list_t::const_iterator it = update.begin();
update_list_t::const_iterator end = update.end();
@@ -2581,7 +2580,7 @@ void LLInventoryModel::accountForUpdate(
}
void LLInventoryModel::accountForUpdate(
- const LLInventoryModel::update_map_t& update)
+ const LLInventoryModel::update_map_t& update) const
{
LLCategoryUpdate up;
update_map_t::const_iterator it = update.begin();
@@ -2706,6 +2705,17 @@ bool LLInventoryModel::loadSkeleton(
gzip_filename.append(".gz");
LLFILE* fp = LLFile::fopen(gzip_filename, "rb");
bool remove_inventory_file = false;
+ if (LLAppViewer::instance()->isSecondInstance())
+ {
+ // Safeguard viewer against trying to unpack file twice
+ // ex: user logs into two accounts simultaneously, so two
+ // viewers are trying to unpack library into same file
+ //
+ // Would be better to do it in gunzip_file, but it doesn't
+ // have access to llfilesystem
+ inventory_filename = gDirUtilp->getTempFilename();
+ remove_inventory_file = true;
+ }
if(fp)
{
fclose(fp);
@@ -2914,7 +2924,7 @@ bool LLInventoryModel::loadSkeleton(
// clean up the gunzipped file.
LLFile::remove(inventory_filename);
}
- if(is_cache_obsolete)
+ if(is_cache_obsolete && !LLAppViewer::instance()->isSecondInstance())
{
// If out of date, remove the gzipped file too.
LL_WARNS(LOG_INV) << "Inv cache out of date, removing" << LL_ENDL;
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 3b943dd121..e179f4a740 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -511,12 +511,14 @@ public:
// Represents the number of items added or removed from a category.
struct LLCategoryUpdate
{
- LLCategoryUpdate() : mDescendentDelta(0) {}
- LLCategoryUpdate(const LLUUID& category_id, S32 delta) :
+ LLCategoryUpdate() : mDescendentDelta(0), mChangeVersion(true) {}
+ LLCategoryUpdate(const LLUUID& category_id, S32 delta, bool change_version = true) :
mCategoryID(category_id),
- mDescendentDelta(delta) {}
+ mDescendentDelta(delta),
+ mChangeVersion(change_version) {}
LLUUID mCategoryID;
S32 mDescendentDelta;
+ bool mChangeVersion;
};
typedef std::vector