Merge branch 'main' into marchcat/x-mf-merge

# Conflicts:
#	doc/contributions.txt
#	indra/newview/llfloaterimagepreview.cpp
master
Andrey Lihatskiy 2024-05-15 12:51:21 +03:00
commit d9153532b8
261 changed files with 4842 additions and 5579 deletions

View File

@ -462,9 +462,11 @@
<key>archive</key>
<map>
<key>hash</key>
<string>7ac35da9b1b5c9a05954edeef3fe8e54</string>
<string>52c41a4547d2d9aceb4a9a1e9e1680c71e5ffa79</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/113242/980233/emoji_shortcodes-6.1.0.579438-darwin64-579438.tar.bz2</string>
<string>https://github.com/secondlife/3p-emoji-shortcodes/releases/download/v6.1.0.5413f58/emoji_shortcodes-6.1.0.5413f58-darwin64-5413f58.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -474,9 +476,11 @@
<key>archive</key>
<map>
<key>hash</key>
<string>087ce7e6d93dcd88b477b10d8e1ab259</string>
<string>3137e06d376767a631bc9626832d558c4d5e5aa9</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/113243/980244/emoji_shortcodes-6.1.0.579438-windows64-579438.tar.bz2</string>
<string>https://github.com/secondlife/3p-emoji-shortcodes/releases/download/v6.1.0.5413f58/emoji_shortcodes-6.1.0.5413f58-windows64-5413f58.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@ -489,7 +493,7 @@
<key>copyright</key>
<string>Copyright 2017-2019 Miles Johnson.</string>
<key>version</key>
<string>6.1.0.579438</string>
<string>6.1.0.5413f58</string>
<key>name</key>
<string>emoji_shortcodes</string>
<key>canonical_repo</key>
@ -955,54 +959,6 @@
<key>description</key>
<string>Havok source code for libs and demos</string>
</map>
<key>icu4c</key>
<map>
<key>platforms</key>
<map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>47bc32b991385f1a6530e4c6179b07f64ca6edc7</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-7d08d82/icu4c-4.8.1-darwin64-7d08d82.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>b7db881dac80302e4d9010af34c0bf6ca9897df9</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-7d08d82/icu4c-4.8.1-windows64-7d08d82.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map>
<key>license</key>
<string>ICU, permissive non-copyleft free software license</string>
<key>license_file</key>
<string>LICENSES/icu.txt</string>
<key>copyright</key>
<string>Copyright (c) 1995-2011 International Business Machines Corporation and others &lt;http://source.icu-project.org&gt;</string>
<key>version</key>
<string>4.8.1-7d08d82</string>
<key>name</key>
<string>icu4c</string>
<key>canonical_repo</key>
<string>https://bitbucket.org/lindenlab/3p-icu4c</string>
<key>description</key>
<string>ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.</string>
</map>
<key>jpegencoderbasic</key>
<map>
<key>platforms</key>
@ -1668,6 +1624,18 @@
<key>name</key>
<string>linux64</string>
</map>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>2e5f1f7046a49d8b0bc295aa878116bc</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/60043/564063/llphysicsextensions_stub-1.0.542456-windows-542456.tar.bz2</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map>
<key>license</key>
<string>internal</string>
@ -2739,11 +2707,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>eb1316584188dafb591f80b46b357c737f90d1a7</string>
<string>8a04e6b3c6ff7f645219955a1389035565eb10d8</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-08bf5ee/viewer_manager-3.0-08bf5ee-darwin64-08bf5ee.tar.zst</string>
<string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-darwin64-f14b5ec.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -2753,11 +2721,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>f4677b0ebd9880f29c118af51ada50883dd0a1e4</string>
<string>a1e467c08ecbe6ab24fc8756a815a431a9b00f62</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-08bf5ee/viewer_manager-3.0-08bf5ee-linux64-08bf5ee.tar.zst</string>
<string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-linux64-f14b5ec.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@ -2767,11 +2735,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>7426c5a1d7eb231b476625637a1f2daba0a6bc55</string>
<string>56b613decdd36b2a17646bf3e2cfc2fed8456b8c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-08bf5ee/viewer_manager-3.0-08bf5ee-windows64-08bf5ee.tar.zst</string>
<string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-windows64-f14b5ec.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@ -2783,8 +2751,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<string>LICENSE</string>
<key>copyright</key>
<string>Copyright (c) 2000-2012, Linden Research, Inc.</string>
<key>version</key>
<string>3.0-08bf5ee</string>
<key>name</key>
<string>viewer-manager</string>
<key>description</key>
@ -2793,6 +2759,8 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<string>https://bitbucket.org/lindenlab/vmp-standalone</string>
<key>source_type</key>
<string>hg</string>
<key>version</key>
<string>3.0-f14b5ec</string>
</map>
<key>vlc-bin</key>
<map>

View File

@ -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

View File

@ -30,7 +30,6 @@ set(cmake_SOURCE_FILES
GoogleMock.cmake
Havok.cmake
Hunspell.cmake
ICU4C.cmake
JsonCpp.cmake
LLAddBuildTest.cmake
LLAppearance.cmake

View File

@ -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)

View File

@ -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)

View File

@ -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()
//-----------------------------------------------------------------------------

View File

@ -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<LLAvatarJoint*> avatar_joint_list_t;

View File

@ -550,7 +550,7 @@ void LLWearable::revertValues()
if(param)
{
F32 value = vp_pair.second;
setVisualParamWeight(id, value);
param->setWeight(value);
mSavedVisualParamMap[id] = param->getWeight();
}
}

View File

@ -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();

View File

@ -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<LLGestureStep*> 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<LLUUID> 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
{

View File

@ -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})

View File

@ -30,7 +30,6 @@
#include "llerror.h"
#include "llfasttimer.h"
#include "llsd.h"
#include <unicode/uchar.h>
#include <vector>
#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

View File

@ -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
*/

View File

@ -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:

View File

@ -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;
}
//---------------------------------------------------------------------------

View File

@ -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;
};

View File

@ -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;
}

View File

@ -58,6 +58,7 @@ private:
BOOL mDecodedRaw;
BOOL mDecodedAux;
LLPointer<LLImageDecodeThread::Responder> 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
}

View File

@ -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:

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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;
//============================================================================

View File

@ -354,11 +354,10 @@ void LLFontFreetype::clearFontStreams()
}
#endif
void LLFontFreetype::addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor)
void LLFontFreetype::addFallbackFont(const LLPointer<LLFontFreetype>& 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<size_t> 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<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> 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);

View File

@ -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<EFontGlyphType, S32> 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;;

View File

@ -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();

View File

@ -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();
}
}

View File

@ -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.
*/

View File

@ -58,10 +58,11 @@ static LLDefaultChildRegistry::Register<LLButton> r("button");
template class LLButton* LLView::getChild<class LLButton>(
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"),

View File

@ -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;

View File

@ -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);

View File

@ -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<S32> 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<S32> 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<S32> 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);
}
}

View File

@ -2039,10 +2039,9 @@ void LLFloater::drawShadow(LLPanel* panel)
S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH;
S32 bottom = LLPANEL_BORDER_WIDTH;
static LLUICachedControl<S32> 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<LLFloater*>(child);
if (floaterp)

View File

@ -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

View File

@ -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<LLLineEditor> (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<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
static LLCachedControl<S32> 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;

View File

@ -345,6 +345,8 @@ protected:
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar;
boost::signals2::connection mRenamerTopLostSignalConnection;
bool mForceArrange;
public:

View File

@ -605,15 +605,13 @@ BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask )
BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
{
static LLCachedControl<S32> 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())

View File

@ -48,8 +48,8 @@ std::string LLFolderViewModelCommon::getStatusText(bool is_empty_folder)
void LLFolderViewModelCommon::filter()
{
static LLCachedControl<S32> 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());
}

View File

@ -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<LLFolderViewModelItem*>& batch) = 0;

View File

@ -83,8 +83,8 @@ template class LLLineEditor* LLView::getChild<class LLLineEditor>(
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);
}

View File

@ -76,8 +76,8 @@ public:
Optional<MaxLength> max_length;
Optional<keystroke_callback_t> keystroke_callback;
Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback;
Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_input_callback;
Optional<LLTextValidate::Validator, LLTextValidate::Validators> prevalidator;
Optional<LLTextValidate::Validator, LLTextValidate::Validators> input_prevalidator;
Optional<LLViewBorder::Params> 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<std::pair<U32, U32> > mMisspellRanges;
std::vector<std::string> 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;

View File

@ -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<S32> 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 )

View File

@ -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<S32> shadow_lines ("DropShadowFloater", 0);
gl_drop_shadow( 0, getRect().getHeight(), getRect().getWidth(), 0,
shadow_color, shadow_lines);
shadow_color, DROP_SHADOW_FLOATER);
LLFloater::draw();

View File

@ -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<LLLineEditor> (params);
mEditor->setFocusReceivedCallback( boost::bind(LLMultiSliderCtrl::onEditorGainFocus, _1, this) );

View File

@ -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<std::string> 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;

View File

@ -201,6 +201,7 @@ public:
Mandatory<std::string> type;
Optional<S32> width;
Optional<S32> max_length_chars;
Optional<bool> allow_emoji;
Optional<std::string> text;
Optional<std::string> value;

View File

@ -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)

View File

@ -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);
}

View File

@ -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<LLLineEditor>(line_p);
mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onEditorGainFocus, _1, this ));

View File

@ -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<S32> 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);

View File

@ -121,6 +121,8 @@ public:
*/
Optional<S32> tab_icon_ctrl_pad;
Optional<bool> use_tab_offset;
Params();
};
@ -321,6 +323,8 @@ private:
S32 mTabIconCtrlPad;
bool mUseTabEllipses;
LLFrameTimer mMouseDownTimer;
bool mUseTabOffset;
};
#endif // LL_TABCONTAINER_H

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -54,7 +54,7 @@ public:
struct Params : public LLInitParam::Block<Params, LLTextBase::Params>
{
Optional<std::string> default_text;
Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback;
Optional<LLTextValidate::Validator, LLTextValidate::Validators> prevalidator;
Optional<bool> 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<LLContextMenu> mContextMenuHandle;
}; // end class LLTextEditor

View File

@ -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 <class CHAR>
LLSD llsd(CHAR ch) { return llsd(std::basic_string<CHAR>(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 <class CHAR>
bool validate(const std::basic_string<CHAR> &str)
{
LLLocale locale(LLLocale::USER_LOCALE);
std::basic_string<CHAR> trimmed = str;
LLStringUtilBase<CHAR>::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<char>(str); }
/*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(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 <class CHAR>
bool validate(const std::basic_string<CHAR> &str)
{
LLLocale locale(LLLocale::USER_LOCALE);
std::basic_string<CHAR> trimmed = str;
LLStringUtilBase<CHAR>::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<char>(str); }
/*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
} validatorIntImpl;
Validator validateInt(validatorIntImpl);
class ValidatorPositiveS32 : public ValidatorImpl
{
template <class CHAR>
bool validate(const std::basic_string<CHAR>& str)
{
LLLocale locale(LLLocale::USER_LOCALE);
std::basic_string<CHAR> trimmed = str;
LLStringUtilBase<CHAR>::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<char>(str); }
/*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
} validatorPositiveS32Impl;
Validator validatePositiveS32(validatorPositiveS32Impl);
class ValidatorNonNegativeS32 : public ValidatorImpl
{
template <class CHAR>
bool validate(const std::basic_string<CHAR>& str)
{
LLLocale locale(LLLocale::USER_LOCALE);
std::basic_string<CHAR> trimmed = str;
LLStringUtilBase<CHAR>::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<char>(str); }
/*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
} validatorNonNegativeS32Impl;
Validator validateNonNegativeS32(validatorNonNegativeS32Impl);
class ValidatorNonNegativeS32NoSpace : public ValidatorImpl
{
template <class CHAR>
bool validate(const std::basic_string<CHAR>& str)
{
LLLocale locale(LLLocale::USER_LOCALE);
std::basic_string<CHAR> 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<char>(str); }
/*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
} validatorNonNegativeS32NoSpaceImpl;
Validator validateNonNegativeS32NoSpace(validatorNonNegativeS32NoSpaceImpl);
class ValidatorAlphaNum : public ValidatorImpl
{
template <class CHAR>
bool validate(const std::basic_string<CHAR>& 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<char>(str); }
/*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
} validatorAlphaNumImpl;
Validator validateAlphaNum(validatorAlphaNumImpl);
class ValidatorAlphaNumSpace : public ValidatorImpl
{
template <class CHAR>
bool validate(const std::basic_string<CHAR>& 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<char>(str); }
/*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(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 <class CHAR>
bool validate(const std::basic_string<CHAR>& 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<char>(str); }
/*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
} validatorASCIIPrintableNoPipeImpl;
Validator validateASCIIPrintableNoPipe(validatorASCIIPrintableNoPipeImpl);
// Used for avatar names
class ValidatorASCIIPrintableNoSpace : public ValidatorImpl
{
template <class CHAR>
bool validate(const std::basic_string<CHAR>& 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<char>(str); }
/*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
} validatorASCIIPrintableNoSpaceImpl;
Validator validateASCIIPrintableNoSpace(validatorASCIIPrintableNoSpaceImpl);
class ValidatorASCII : public ValidatorImpl
{
protected:
template <class CHAR>
bool validate(const std::basic_string<CHAR>& 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<char>(str); }
/*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
} validatorASCIIImpl;
Validator validateASCII(validatorASCIIImpl);
class ValidatorASCIINoLeadingSpace : public ValidatorASCII
{
template <class CHAR>
bool validate(const std::basic_string<CHAR>& str)
{
if (LLStringOps::isSpace(str.front()))
{
return false;
}
return ValidatorASCII::validate<CHAR>(str);
}
public:
/*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
/*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(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 <class CHAR>
bool validate(const std::basic_string<CHAR>& 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<char>(str); }
/*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(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

View File

@ -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<BOOL (const LLWString &wstr)> validate_func_t;
class ValidatorImpl
{
public:
ValidatorImpl() {}
virtual ~ValidatorImpl() {}
struct ValidateTextNamedFuncs
: public LLInitParam::TypeValuesHelper<validate_func_t, ValidateTextNamedFuncs>
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<Validator, Validators>
{
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

View File

@ -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<LLLineEditor> (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);

View File

@ -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;

View File

@ -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<S32> 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)
{

View File

@ -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
{

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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<LLTextViewModel*>(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<LLTextViewModel*>(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;
}
////////////////////////////////////////////////////////////////////////////

View File

@ -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);
};
/**

View File

@ -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<bool(std::string&, LLSD&, void*)> osx_callback,
void* win_callback,
void* userdata)
{
return false;
};
virtual S32 getRefreshRate() { return mRefreshRate; }
protected:

View File

@ -27,6 +27,7 @@
#include <AppKit/AppKit.h>
#include <Cocoa/Cocoa.h>
#include <errno.h>
#include "llopenglview-objc.h"
#include "llwindowmacosx-objc.h"
#include "llappdelegate-objc.h"

View File

@ -43,6 +43,13 @@
#include <CoreServices/CoreServices.h>
#include <CoreGraphics/CGDisplayConfiguration.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOMessage.h>
#include <IOKit/hid/IOHIDUsageTables.h>
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/usb/IOUSBLib.h>
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<HidDevice> &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<bool(std::string&, LLSD&, void*)> 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<HidDevice> device_list;
get_devices(device_list, io_iter);
std::list<HidDevice>::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();

View File

@ -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<bool(std::string&, LLSD&, void*)> osx_callback,
void* win_callback,
void* userdata) override;
static std::vector<std::string> getDisplaysResolutionList();
static std::vector<std::string> getDynamicFallbackFontList();

View File

@ -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<bool(std::string&, LLSD&, void*)> osx_callback,
void * di8_devices_callback,
void* userdata)
{
if (gDirectInput8 != NULL)
{

View File

@ -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<bool(std::string&, LLSD&, void*)> osx_callback,
void* win_callback,
void* userdata);
U32 getRawWParam() { return mRawWParam; }

View File

@ -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<std::string> 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

View File

@ -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;
}

View File

@ -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 )

View File

@ -1 +1 @@
7.1.7
7.1.8

View File

@ -1,16 +1,5 @@
<llsd>
<map>
<key>AppearanceCameraMovement</key>
<map>
<key>Comment</key>
<string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>AvatarSitRotation</key>
<map>
<key>Comment</key>
@ -90,17 +79,6 @@
<key>Value</key>
<real>0.90322577953338623</real>
</map>
<key>EditCameraMovement</key>
<map>
<key>Comment</key>
<string>When entering build mode, camera moves up above avatar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FocusOffsetRearView</key>
<map>
<key>Comment</key>

View File

@ -1,16 +1,5 @@
<llsd>
<map>
<key>AppearanceCameraMovement</key>
<map>
<key>Comment</key>
<string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>AvatarSitRotation</key>
<map>
<key>Comment</key>
@ -90,17 +79,6 @@
<key>Value</key>
<real>0.90322577953338623</real>
</map>
<key>EditCameraMovement</key>
<map>
<key>Comment</key>
<string>When entering build mode, camera moves up above avatar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FocusOffsetRearView</key>
<map>
<key>Comment</key>

View File

@ -1,16 +1,5 @@
<llsd>
<map>
<key>AppearanceCameraMovement</key>
<map>
<key>Comment</key>
<string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>AvatarSitRotation</key>
<map>
<key>Comment</key>
@ -90,17 +79,6 @@
<key>Value</key>
<real>0.90322577953338623</real>
</map>
<key>EditCameraMovement</key>
<map>
<key>Comment</key>
<string>When entering build mode, camera moves up above avatar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FocusOffsetRearView</key>
<map>
<key>Comment</key>

File diff suppressed because it is too large Load Diff

View File

@ -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" \

View File

@ -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;
}

View File

@ -70,7 +70,7 @@ private:
//a fetch has been instigated.
uuid_set_t mPendingObjectQuota;
void accountingCostCoro(std::string url, eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle);
static void accountingCostCoro(std::string url, eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle);
};
//===============================================================================

View File

@ -1932,7 +1932,8 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
}
else
{
target_lag = vel * gSavedSettings.getF32("DynamicCameraStrength") / 30.f;
LLCachedControl<F32> dynamic_camera_strength(gSavedSettings, "DynamicCameraStrength");
target_lag = vel * dynamic_camera_strength / 30.f;
}
mCameraLag = lerp(mCameraLag, target_lag, lag_interp);

View File

@ -49,10 +49,10 @@ public:
void sendAgentPicksRequest()
{
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(gAgent.getID());
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(gAgent.getID());
}
typedef boost::function<void(LLAvatarPicks*)> server_respond_callback_t;
typedef boost::function<void(LLAvatarData*)> 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<LLAvatarPicks*>(data);
if(picks && gAgent.getID() == picks->target_id)
LLAvatarData* picks = static_cast<LLAvatarData*>(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)
{

View File

@ -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:

View File

@ -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<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
LLPointer<LLInventoryCallback> 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

View File

@ -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<LLOutfitUnLockTimer> 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;

View File

@ -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;
}

View File

@ -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<LLAvatarLegacyData*>(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<LLAvatarData*>(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();
}
}

View File

@ -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<LLUUID, LLAvatarPropertiesObserver*>;
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<LLUUID, LLAvatarPropertiesObserver*>(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<LLUUID, LLAvatarPropertiesObserver*>;
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<std::string> strings;
strings.push_back(avatar_id.asString());
std::vector<std::string> 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<std::string> request_params;
request_params.push_back(creator_id.asString() );
request_params.push_back(pick_id.asString() );
std::vector<std::string> 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;
}

View File

@ -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<LLGroupData> group_list_t;
group_list_t group_list;
typedef std::pair<LLUUID,std::string> pick_data_t;
typedef std::pair<LLUUID, std::string> 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<LLGroupData> 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<LLUUID, EAvatarProcessorType>, U32> timestamp_map_t;
timestamp_map_t mRequestTimestamps;
// Is returned by isHideAgeSupportedByServer()
bool mIsHideAgeSupportedByServer { false };
};
#endif // LL_LLAVATARPROPERTIESPROCESSOR_H

View File

@ -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::LLScreenChannel*>
(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;

View File

@ -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));

View File

@ -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<LLFloaterCompileQueue> 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<LLInventoryItem *>(inventory);
@ -385,7 +384,7 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> 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<LLFloaterCompileQueue> 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<LLFloaterCompileQueue> 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"))

View File

@ -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);
}
}
}

View File

@ -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<LLFolderViewModelItem*>& batch) { }

View File

@ -106,6 +106,8 @@ LLConversationViewSession::~LLConversationViewSession()
}
mFlashTimer->unset();
delete mFlashTimer;
mFlashStateOn = false;
}
void LLConversationViewSession::destroyView()

View File

@ -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;
}

Some files were not shown because too many files have changed in this diff Show More