diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2023-07-17 23:34:59 +0300 |
---|---|---|
committer | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2023-07-17 23:34:59 +0300 |
commit | acf82867b61535b7b39b89f71a282e3ce3d0673e (patch) | |
tree | 2795aa7a92d291d5535d935ab0782cfdf6ec45e4 | |
parent | d3233e787aaf1ba0558a714d5216ea70c7249c36 (diff) | |
parent | ec4135da63a3f3877222fba4ecb59b15650371fe (diff) |
Merge branch 'main' (DRTVWR-580) into DRTVWR-567
# Conflicts:
# indra/llui/llfolderviewitem.cpp
# indra/newview/llinventorymodel.cpp
# indra/newview/llinventorymodelbackgroundfetch.cpp
77 files changed, 1592 insertions, 895 deletions
diff --git a/doc/contributions.txt b/doc/contributions.txt index cf3f7668f2..11a58dfbc5 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -1189,6 +1189,7 @@ PanteraPolnocy SL-18891 SL-18904 SL-18937 + SL-19681 Parvati Silverweb Patric Mills VWR-2645 @@ -1413,6 +1414,7 @@ Sovereign Engineer SL-18497 SL-18525 SL-18534 + SL-19336 SpacedOut Frye VWR-34 VWR-45 diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index 6720f902bd..3cef382bbf 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -1391,6 +1391,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, boo // get number of joint motions //------------------------------------------------------------------------- U32 num_motions = 0; + S32 rotation_dupplicates = 0; + S32 position_dupplicates = 0; if (!dp.unpackU32(num_motions, "num_joints")) { LL_WARNS() << "can't read number of joints" @@ -1621,6 +1623,12 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, boo rCurve->mKeys[time] = rot_key; } + if (joint_motion->mRotationCurve.mNumKeys > joint_motion->mRotationCurve.mKeys.size()) + { + rotation_dupplicates++; + LL_INFOS() << "Motion: " << asset_id << " had dupplicate rotation keys that were removed" << LL_ENDL; + } + //--------------------------------------------------------------------- // scan position curve header //--------------------------------------------------------------------- @@ -1723,9 +1731,24 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, boo } } + if (joint_motion->mPositionCurve.mNumKeys > joint_motion->mPositionCurve.mKeys.size()) + { + position_dupplicates++; + } + joint_motion->mUsage = joint_state->getUsage(); } + if (rotation_dupplicates > 0) + { + LL_INFOS() << "Motion: " << asset_id << " had " << rotation_dupplicates << " dupplicate rotation keys that were removed" << LL_ENDL; + } + + if (position_dupplicates > 0) + { + LL_INFOS() << "Motion: " << asset_id << " had " << position_dupplicates << " dupplicate position keys that were removed" << LL_ENDL; + } + //------------------------------------------------------------------------- // get number of constraints //------------------------------------------------------------------------- @@ -2005,10 +2028,13 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const JointMotion* joint_motionp = mJointMotionList->getJointMotion(i); success &= dp.packString(joint_motionp->mJointName, "joint_name"); success &= dp.packS32(joint_motionp->mPriority, "joint_priority"); - success &= dp.packS32(joint_motionp->mRotationCurve.mNumKeys, "num_rot_keys"); + success &= dp.packS32(joint_motionp->mRotationCurve.mKeys.size(), "num_rot_keys"); - LL_DEBUGS("BVH") << "Joint " << joint_motionp->mJointName << LL_ENDL; - for (RotationCurve::key_map_t::value_type& rot_pair : joint_motionp->mRotationCurve.mKeys) + LL_DEBUGS("BVH") << "Joint " << i + << " name: " << joint_motionp->mJointName + << " Rotation keys: " << joint_motionp->mRotationCurve.mKeys.size() + << " Position keys: " << joint_motionp->mPositionCurve.mKeys.size() << LL_ENDL; + for (RotationCurve::key_map_t::value_type& rot_pair : joint_motionp->mRotationCurve.mKeys) { RotationKey& rot_key = rot_pair.second; U16 time_short = F32_to_U16(rot_key.mTime, 0.f, mJointMotionList->mDuration); @@ -2028,7 +2054,7 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const LL_DEBUGS("BVH") << " rot: t " << rot_key.mTime << " angles " << rot_angles.mV[VX] <<","<< rot_angles.mV[VY] <<","<< rot_angles.mV[VZ] << LL_ENDL; } - success &= dp.packS32(joint_motionp->mPositionCurve.mNumKeys, "num_pos_keys"); + success &= dp.packS32(joint_motionp->mPositionCurve.mKeys.size(), "num_pos_keys"); for (PositionCurve::key_map_t::value_type& pos_pair : joint_motionp->mPositionCurve.mKeys) { PositionKey& pos_key = pos_pair.second; diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 54020a4231..ef4899978e 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -39,7 +39,6 @@ set(llcommon_SOURCE_FILES lldependencies.cpp lldictionary.cpp llerror.cpp - llerrorthread.cpp llevent.cpp lleventapi.cpp lleventcoro.cpp @@ -151,7 +150,6 @@ set(llcommon_HEADER_FILES llendianswizzle.h llerror.h llerrorcontrol.h - llerrorthread.h llevent.h lleventapi.h lleventcoro.h diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index d839b19c99..b99166991f 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -39,7 +39,6 @@ #include "llcommon.h" #include "llapr.h" #include "llerrorcontrol.h" -#include "llerrorthread.h" #include "llframetimer.h" #include "lllivefile.h" #include "llmemory.h" @@ -108,12 +107,7 @@ LLAppErrorHandler LLApp::sErrorHandler = NULL; BOOL LLApp::sErrorThreadRunning = FALSE; -LLApp::LLApp() : mThreadErrorp(NULL) -{ - commonCtor(); -} - -void LLApp::commonCtor() +LLApp::LLApp() { // Set our status to running setStatus(APP_STATUS_RUNNING); @@ -143,12 +137,6 @@ void LLApp::commonCtor() mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe"; } -LLApp::LLApp(LLErrorThread *error_thread) : - mThreadErrorp(error_thread) -{ - commonCtor(); -} - LLApp::~LLApp() { @@ -158,13 +146,6 @@ LLApp::~LLApp() mLiveFiles.clear(); setStopped(); - // HACK: wait for the error thread to clean itself - ms_sleep(20); - if (mThreadErrorp) - { - delete mThreadErrorp; - mThreadErrorp = NULL; - } SUBSYSTEM_CLEANUP_DBG(LLCommon); } @@ -393,27 +374,6 @@ void LLApp::setupErrorHandling(bool second_instance) #endif // ! LL_BUGSPLAT #endif // ! LL_WINDOWS - -#ifdef LL_BUGSPLAT - // do not start our own error thread -#else // ! LL_BUGSPLAT - startErrorThread(); -#endif -} - -void LLApp::startErrorThread() -{ - // - // Start the error handling thread, which is responsible for taking action - // when the app goes into the APP_STATUS_ERROR state - // - if(!mThreadErrorp) - { - LL_INFOS() << "Starting error thread" << LL_ENDL; - mThreadErrorp = new LLErrorThread(); - mThreadErrorp->setUserData((void *) this); - mThreadErrorp->start(); - } } void LLApp::setErrorHandler(LLAppErrorHandler handler) @@ -476,7 +436,7 @@ void LLApp::setStatus(EAppStatus status) // static void LLApp::setError() { - // set app status to ERROR so that the LLErrorThread notices + // set app status to ERROR setStatus(APP_STATUS_ERROR); } diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index c65fe21c9c..c832c8b142 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -34,7 +34,6 @@ #include <atomic> #include <chrono> // Forward declarations -class LLErrorThread; class LLLiveFile; #if LL_LINUX #include <signal.h> @@ -53,7 +52,6 @@ void clear_signals(); class LL_COMMON_API LLApp { - friend class LLErrorThread; public: typedef enum e_app_status { @@ -67,11 +65,6 @@ public: LLApp(); virtual ~LLApp(); -protected: - LLApp(LLErrorThread* error_thread); - void commonCtor(); -public: - /** * @brief Return the static app instance if one was created. */ @@ -257,14 +250,14 @@ public: void setupErrorHandling(bool mSecondInstance=false); void setErrorHandler(LLAppErrorHandler handler); - static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred. + static void runErrorHandler(); // run shortly after we detect an error //@} - + // the maximum length of the minidump filename returned by getMiniDumpFilename() static const U32 MAX_MINDUMP_PATH_LENGTH = 256; // change the directory where Breakpad minidump files are written to - void setDebugFileNames(const std::string &path); + void setDebugFileNames(const std::string &path); // Return the Google Breakpad minidump filename after a crash. char *getMiniDumpFilename() { return mMinidumpPath; } @@ -310,13 +303,11 @@ protected: void stepFrame(); private: - void startErrorThread(); - // Contains the filename of the minidump file after a crash. char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH]; - std::string mStaticDebugFileName; - std::string mDynamicDebugFileName; + std::string mStaticDebugFileName; + std::string mDynamicDebugFileName; // *NOTE: On Windows, we need a routine to reset the structured // exception handler when some evil driver has taken it over for @@ -324,9 +315,6 @@ private: typedef int(*signal_handler_func)(int signum); static LLAppErrorHandler sErrorHandler; - // Default application threads - LLErrorThread* mThreadErrorp; // Waits for app to go to status ERROR, then runs the error callback - // This is the application level runnable scheduler. LLRunner mRunner; diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index d06c0e2132..020f05e8f5 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -274,7 +274,6 @@ namespace LLError // used to indicate no class info known for logging //LLCallStacks keeps track of call stacks and output the call stacks to log file - //when LLAppViewer::handleViewerCrash() is triggered. // //Note: to be simple, efficient and necessary to keep track of correct call stacks, //LLCallStacks is designed not to be thread-safe. diff --git a/indra/llcommon/llerrorthread.cpp b/indra/llcommon/llerrorthread.cpp deleted file mode 100644 index f6bc68b5c1..0000000000 --- a/indra/llcommon/llerrorthread.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/** - * @file llerrorthread.cpp - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llerrorthread.h" - -#include "llapp.h" -#include "lltimer.h" // ms_sleep() - -LLErrorThread::LLErrorThread() - : LLThread("Error"), - mUserDatap(NULL) -{ -} - -LLErrorThread::~LLErrorThread() -{ -} - -void LLErrorThread::setUserData(void* user_data) -{ - mUserDatap = user_data; -} - - -void* LLErrorThread::getUserData() const -{ - return mUserDatap; -} - -#if !LL_WINDOWS -// -// Various signal/error handling functions that can't be put into the class -// -void get_child_status(const int waitpid_status, int &process_status, bool &exited, bool do_logging) -{ - exited = false; - process_status = -1; - // The child process exited. Call its callback, and then clean it up - if (WIFEXITED(waitpid_status)) - { - process_status = WEXITSTATUS(waitpid_status); - exited = true; - if (do_logging) - { - LL_INFOS() << "get_child_status - Child exited cleanly with return of " << process_status << LL_ENDL; - } - return; - } - else if (WIFSIGNALED(waitpid_status)) - { - process_status = WTERMSIG(waitpid_status); - exited = true; - if (do_logging) - { - LL_INFOS() << "get_child_status - Child died because of uncaught signal " << process_status << LL_ENDL; -#ifdef WCOREDUMP - if (WCOREDUMP(waitpid_status)) - { - LL_INFOS() << "get_child_status - Child dumped core" << LL_ENDL; - } - else - { - LL_INFOS() << "get_child_status - Child didn't dump core" << LL_ENDL; - } -#endif - } - return; - } - else if (do_logging) - { - // This is weird. I just dump the waitpid status into the status code, - // not that there's any way of telling what it is... - LL_INFOS() << "get_child_status - Got SIGCHILD but child didn't exit" << LL_ENDL; - process_status = waitpid_status; - } - -} -#endif - -void LLErrorThread::run() -{ - LLApp::sErrorThreadRunning = TRUE; - // This thread sits and waits for the sole purpose - // of waiting for the signal/exception handlers to flag the - // application state as APP_STATUS_ERROR. - LL_INFOS() << "thread_error - Waiting for an error" << LL_ENDL; - - S32 counter = 0; - while (! (LLApp::isError() || LLApp::isStopped())) - { - ms_sleep(10); - counter++; - } - if (LLApp::isError()) - { - // The app is in an error state, run the application's error handler. - //LL_INFOS() << "thread_error - An error has occurred, running error callback!" << LL_ENDL; - // Run the error handling callback - LLApp::runErrorHandler(); - } - else - { - // Everything is okay, a clean exit. - //LL_INFOS() << "thread_error - Application exited cleanly" << LL_ENDL; - } - - //LL_INFOS() << "thread_error - Exiting" << LL_ENDL; - LLApp::sErrorThreadRunning = FALSE; -} - diff --git a/indra/llcommon/llerrorthread.h b/indra/llcommon/llerrorthread.h deleted file mode 100644 index 474cef3a50..0000000000 --- a/indra/llcommon/llerrorthread.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - * @file llerrorthread.h - * @brief Specialized thread to handle runtime errors. - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLERRORTHREAD_H -#define LL_LLERRORTHREAD_H - -#include "llthread.h" - -class LL_COMMON_API LLErrorThread : public LLThread -{ -public: - LLErrorThread(); - ~LLErrorThread(); - - /*virtual*/ void run(void); - void setUserData(void *user_data); - void *getUserData() const; - -protected: - void* mUserDatap; // User data associated with this thread -}; - -#endif // LL_LLERRORTHREAD_H diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 66bd85f4e6..a2e85cf6c2 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -552,7 +552,9 @@ std::string LLCacheName::buildUsername(const std::string& full_name) // if the input wasn't a correctly formatted legacy name, just return it // cleaned up from a potential terminal "Resident" - return cleanFullName(full_name); + std::string clean_name = cleanFullName(full_name); + LLStringUtil::toLower(clean_name); + return clean_name; } //static diff --git a/indra/llprimitive/llmaterial.cpp b/indra/llprimitive/llmaterial.cpp index a219ac1450..fa22145972 100644 --- a/indra/llprimitive/llmaterial.cpp +++ b/indra/llprimitive/llmaterial.cpp @@ -426,18 +426,18 @@ bool LLMaterial::operator != (const LLMaterial& rhs) const } -U32 LLMaterial::getShaderMask(U32 alpha_mode) +U32 LLMaterial::getShaderMask(U32 alpha_mode, BOOL is_alpha) { //NEVER incorporate this value into the message system -- this function will vary depending on viewer implementation - U32 ret = 0; - //two least significant bits are "diffuse alpha mode" - if (alpha_mode != DIFFUSE_ALPHA_MODE_DEFAULT) + //two least significant bits are "diffuse alpha mode" + U32 ret = alpha_mode; + if (ret == DIFFUSE_ALPHA_MODE_DEFAULT) { - ret = alpha_mode; - } - else - { - ret = getDiffuseAlphaMode(); + ret = getDiffuseAlphaMode(); + if (ret == DIFFUSE_ALPHA_MODE_BLEND && !is_alpha) + { + ret = DIFFUSE_ALPHA_MODE_NONE; + } } llassert(ret < SHADER_COUNT); diff --git a/indra/llprimitive/llmaterial.h b/indra/llprimitive/llmaterial.h index d58b7ee812..d92ef1dfba 100644 --- a/indra/llprimitive/llmaterial.h +++ b/indra/llprimitive/llmaterial.h @@ -126,7 +126,7 @@ public: bool operator == (const LLMaterial& rhs) const; bool operator != (const LLMaterial& rhs) const; - U32 getShaderMask(U32 alpha_mode = DIFFUSE_ALPHA_MODE_DEFAULT); + U32 getShaderMask(U32 alpha_mode, BOOL is_alpha); protected: LLUUID mNormalID; diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 022c307de7..15fddbc99f 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -494,7 +494,7 @@ F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max return getWidthF32(wtext.c_str(), begin_offset, max_chars); } -F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars) const +F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars, bool no_padding) const { const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; @@ -517,12 +517,15 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars F32 advance = mFontFreetype->getXAdvance(fgi); - // for the last character we want to measure the greater of its width and xadvance values - // so keep track of the difference between these values for the each character we measure - // so we can fix things up at the end - width_padding = llmax( 0.f, // always use positive padding amount - width_padding - advance, // previous padding left over after advance of current character - (F32)(fgi->mWidth + fgi->mXBearing) - advance); // difference between width of this character and advance to next character + if (!no_padding) + { + // for the last character we want to measure the greater of its width and xadvance values + // so keep track of the difference between these values for the each character we measure + // so we can fix things up at the end + width_padding = llmax(0.f, // always use positive padding amount + width_padding - advance, // previous padding left over after advance of current character + (F32)(fgi->mWidth + fgi->mXBearing) - advance); // difference between width of this character and advance to next character + } cur_x += advance; llwchar next_char = wchars[i+1]; @@ -539,8 +542,11 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars cur_x = (F32)ll_round(cur_x); } - // add in extra pixels for last character's width past its xadvance - cur_x += width_padding; + if (!no_padding) + { + // add in extra pixels for last character's width past its xadvance + cur_x += width_padding; + } return cur_x / sScaleX; } diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 9608b7ea91..9bbf9ce0c4 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -138,7 +138,7 @@ public: F32 getWidthF32(const std::string& utf8text) const; F32 getWidthF32(const llwchar* wchars) const; F32 getWidthF32(const std::string& text, S32 offset, S32 max_chars ) const; - F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars) const; + F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars, bool no_padding = false) const; // The following are called often, frequently with large buffers, so do not use a string interface diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 9dc140b5b9..465f30a343 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -859,9 +859,16 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 stop_glerror(); if (prev_mip_data) - delete[] prev_mip_data; + { + if (prev_mip_data != cur_mip_data) + delete[] prev_mip_data; + prev_mip_data = nullptr; + } if (cur_mip_data) + { delete[] cur_mip_data; + cur_mip_data = nullptr; + } mGLTextureCreated = false; return FALSE; diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 7090156b4e..0093f4c17c 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -399,7 +399,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height ) // it is purely visual, so it is fine to do at our laisure refreshSuffix(); } - mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(LLFontGL::NORMAL)->getWidth(mLabelSuffix) + mLabelPaddingRight; + mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(LLFontGL::NORMAL)->getWidth(mLabelSuffix) + mLabelPaddingRight; mLabelWidthDirty = false; } diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp index e01aba402e..2791377a5e 100644 --- a/indra/llui/lliconctrl.cpp +++ b/indra/llui/lliconctrl.cpp @@ -37,6 +37,8 @@ #include "lluiimage.h" #include "llwindow.h" +#include "llgltexture.h" + static LLDefaultChildRegistry::Register<LLIconCtrl> r("icon"); LLIconCtrl::Params::Params() @@ -94,6 +96,22 @@ BOOL LLIconCtrl::handleHover(S32 x, S32 y, MASK mask) return LLUICtrl::handleHover(x, y, mask); } +void LLIconCtrl::onVisibilityChange(BOOL new_visibility) +{ + LLUICtrl::onVisibilityChange(new_visibility); + if (mPriority == LLGLTexture::BOOST_ICON) + { + if (new_visibility) + { + loadImage(getValue(), mPriority); + } + else + { + mImagep = nullptr; + } + } +} + // virtual // value might be a string or a UUID void LLIconCtrl::setValue(const LLSD& value) @@ -110,6 +128,14 @@ void LLIconCtrl::setValue(const LLSD& value, S32 priority) tvalue = LLSD(LLUUID(value.asString())); } LLUICtrl::setValue(tvalue); + + loadImage(tvalue, priority); +} + +void LLIconCtrl::loadImage(const LLSD& tvalue, S32 priority) +{ + if(mPriority == LLGLTexture::BOOST_ICON && !getVisible()) return; + if (tvalue.isUUID()) { mImagep = LLUI::getUIImageByID(tvalue.asUUID(), priority); diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h index b5aad17ca6..e983d63a01 100644 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -74,6 +74,7 @@ public: virtual BOOL handleHover(S32 x, S32 y, MASK mask); // lluictrl overrides + void onVisibilityChange(BOOL new_visibility); virtual void setValue(const LLSD& value ); std::string getImageName() const; @@ -97,6 +98,8 @@ protected: bool mInteractable; private: + void loadImage(const LLSD& value, S32 priority); + LLUIColor mColor; LLPointer<LLUIImage> mImagep; }; diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index b8f47ef6ba..8018365d3e 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -127,6 +127,7 @@ public: virtual void clearCtrls(); // overridden in LLPanelObject and LLPanelVolume // Border controls + const LLViewBorder* getBorder() const { return mBorder; } void addBorder( LLViewBorder::Params p); void addBorder(); void removeBorder(); diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 82a3c01c6d..8732a7ce45 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -361,7 +361,7 @@ void LLTextBase::onValueChange(S32 start, S32 end) { } -std::vector<LLRect> LLTextBase::getSelctionRects() +std::vector<LLRect> LLTextBase::getSelectionRects() { // Nor supposed to be called without selection llassert(hasSelection()); @@ -458,7 +458,7 @@ void LLTextBase::drawSelectionBackground() // Draw selection even if we don't have keyboard focus for search/replace if (hasSelection() && !mLineInfoList.empty()) { - std::vector<LLRect> selection_rects = getSelctionRects(); + std::vector<LLRect> selection_rects = getSelectionRects(); // Draw the selection box (we're using a box instead of reversing the colors on the selected text). gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -1356,9 +1356,9 @@ void LLTextBase::draw() drawCursor(); } - mDocumentView->setVisible(FALSE); + mDocumentView->setVisibleDirect(FALSE); LLUICtrl::draw(); - mDocumentView->setVisible(TRUE); + mDocumentView->setVisibleDirect(TRUE); } @@ -3464,7 +3464,7 @@ bool LLNormalTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& w height = mFontHeight; const LLWString &text = getWText(); // if last character is a newline, then return true, forcing line break - width = mStyle->getFont()->getWidthF32(text.c_str(), mStart + first_char, num_chars); + width = mStyle->getFont()->getWidthF32(text.c_str(), mStart + first_char, num_chars, true); } return false; } diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index e3cf56a5ee..3611ab0499 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -638,7 +638,7 @@ protected: return mLabel.getString() + getToolTip(); } - std::vector<LLRect> getSelctionRects(); + std::vector<LLRect> getSelectionRects(); protected: // text segmentation and flow diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index c567451973..521dabf9d4 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -171,7 +171,8 @@ void LLTextBox::reshapeToFitText(BOOL called_from_parent) S32 width = getTextPixelWidth(); S32 height = getTextPixelHeight(); - reshape( width + 2 * mHPad, height + 2 * mVPad, called_from_parent ); + //consider investigating reflow() to find missing width pixel (see SL-17045 changes) + reshape( width + 2 * mHPad + 1, height + 2 * mVPad, called_from_parent ); } diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp index 244f0c6f00..096336045c 100644 --- a/indra/llui/lluicolortable.cpp +++ b/indra/llui/lluicolortable.cpp @@ -200,7 +200,6 @@ LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& defa void LLUIColorTable::setColor(const std::string& name, const LLColor4& color) { setColor(name, color, mUserSetColors); - setColor(name, color, mLoadedColors); } bool LLUIColorTable::loadFromSettings() @@ -229,6 +228,11 @@ void LLUIColorTable::saveUserSettings() const it != mUserSetColors.end(); ++it) { + // Compare user color value with the default value, skip if equal + string_color_map_t::const_iterator itd = mLoadedColors.find(it->first); + if(itd != mLoadedColors.end() && itd->second == it->second) + continue; + ColorEntryParams color_entry; color_entry.name = it->first; color_entry.color.value = it->second; diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 444a4c3cb5..7360fd0fb9 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -288,6 +288,7 @@ public: void setAllChildrenEnabled(BOOL b); virtual void setVisible(BOOL visible); + void setVisibleDirect(BOOL visible) { mVisible = visible; } const BOOL& getVisible() const { return mVisible; } virtual void setEnabled(BOOL enabled); BOOL getEnabled() const { return mEnabled; } diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 97154f804c..e9d5f8c17f 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.6.13 +6.6.14 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index df3dd65a0e..b812219685 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12973,13 +12973,13 @@ <key>TranslationService</key> <map> <key>Comment</key> - <string>Translation API to use. (google|bing)</string> + <string>Translation API to use. (google|azure)</string> <key>Persist</key> <integer>1</integer> <key>Type</key> <string>String</string> <key>Value</key> - <string>bing</string> + <string>azure</string> </map> <key>GoogleTranslateAPIKey</key> <map> @@ -12995,7 +12995,7 @@ <key>BingTranslateAPIKey</key> <map> <key>Comment</key> - <string>Bing AppID to use with the Microsoft Translator API</string> + <string>(Deprecated) Bing AppID to use with the Microsoft Translator API</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -13003,6 +13003,28 @@ <key>Value</key> <string></string> </map> + <key>AzureTranslateAPIKey</key> + <map> + <key>Comment</key> + <string>Azure Translation service data to use with the MS Azure Translator API</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <string></string> + </map> + <key>DeepLTranslateAPIKey</key> + <map> + <key>Comment</key> + <string>DeepL Translation service data to use with the DeepL Translator API</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <string></string> + </map> <key>TutorialURL</key> <map> <key>Comment</key> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 94e0f20267..69429fb5ce 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3582,8 +3582,6 @@ void LLAppViewer::writeSystemInfo() // "CrashNotHandled" is set here, while things are running well, // in case of a freeze. If there is a freeze, the crash logger will be launched // and can read this value from the debug_info.log. - // If the crash is handled by LLAppViewer::handleViewerCrash, ie not a freeze, - // then the value of "CrashNotHandled" will be set to true. gDebugInfo["CrashNotHandled"] = LLSD::Boolean(true); #else // LL_BUGSPLAT // "CrashNotHandled" is obsolete; it used (not very successsfully) @@ -3675,163 +3673,6 @@ void getFileList() } #endif -void LLAppViewer::handleViewerCrash() -{ - LL_INFOS("CRASHREPORT") << "Handle viewer crash entry." << LL_ENDL; - - LL_INFOS("CRASHREPORT") << "Last render pool type: " << LLPipeline::sCurRenderPoolType << LL_ENDL ; - - LLMemory::logMemoryInfo(true) ; - - //print out recorded call stacks if there are any. - LLError::LLCallStacks::print(); - - LLAppViewer* pApp = LLAppViewer::instance(); - if (pApp->beingDebugged()) - { - // This will drop us into the debugger. - abort(); - } - - if (LLApp::isCrashloggerDisabled()) - { - abort(); - } - - // Returns whether a dialog was shown. - // Only do the logic in here once - if (pApp->mReportedCrash) - { - return; - } - pApp->mReportedCrash = TRUE; - - // Insert crash host url (url to post crash log to) if configured. - std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl"); - if(crashHostUrl != "") - { - gDebugInfo["Dynamic"]["CrashHostUrl"] = crashHostUrl; - } - - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if ( parcel && parcel->getMusicURL()[0]) - { - gDebugInfo["Dynamic"]["ParcelMusicURL"] = parcel->getMusicURL(); - } - if ( parcel && parcel->getMediaURL()[0]) - { - gDebugInfo["Dynamic"]["ParcelMediaURL"] = parcel->getMediaURL(); - } - - gDebugInfo["Dynamic"]["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds()); - gDebugInfo["Dynamic"]["RAMInfo"]["Allocated"] = LLSD::Integer(LLMemory::getCurrentRSS() / 1024); - - if(gLogoutInProgress) - { - gDebugInfo["Dynamic"]["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH; - } - else - { - gDebugInfo["Dynamic"]["LastExecEvent"] = gLLErrorActivated ? LAST_EXEC_LLERROR_CRASH : LAST_EXEC_OTHER_CRASH; - } - - if(gAgent.getRegion()) - { - gDebugInfo["Dynamic"]["CurrentSimHost"] = gAgent.getRegion()->getSimHostName(); - gDebugInfo["Dynamic"]["CurrentRegion"] = gAgent.getRegion()->getName(); - - const LLVector3& loc = gAgent.getPositionAgent(); - gDebugInfo["Dynamic"]["CurrentLocationX"] = loc.mV[0]; - gDebugInfo["Dynamic"]["CurrentLocationY"] = loc.mV[1]; - gDebugInfo["Dynamic"]["CurrentLocationZ"] = loc.mV[2]; - } - - if(LLAppViewer::instance()->mMainloopTimeout) - { - gDebugInfo["Dynamic"]["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); - } - - // The crash is being handled here so set this value to false. - // Otherwise the crash logger will think this crash was a freeze. - gDebugInfo["Dynamic"]["CrashNotHandled"] = LLSD::Boolean(false); - - //Write out the crash status file - //Use marker file style setup, as that's the simplest, especially since - //we're already in a crash situation - if (gDirUtilp) - { - std::string crash_marker_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, - gLLErrorActivated - ? LLERROR_MARKER_FILE_NAME - : ERROR_MARKER_FILE_NAME); - LLAPRFile crash_marker_file ; - crash_marker_file.open(crash_marker_file_name, LL_APR_WB); - if (crash_marker_file.getFileHandle()) - { - LL_INFOS("MarkerFile") << "Created crash marker file " << crash_marker_file_name << LL_ENDL; - recordMarkerVersion(crash_marker_file); - } - else - { - LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_marker_file_name << LL_ENDL; - } - } - else - { - LL_WARNS("MarkerFile") << "No gDirUtilp with which to create error marker file name" << LL_ENDL; - } - -#ifdef LL_WINDOWS - Sleep(200); -#endif - - char *minidump_file = pApp->getMiniDumpFilename(); - LL_DEBUGS("CRASHREPORT") << "minidump file name " << minidump_file << LL_ENDL; - if(minidump_file && minidump_file[0] != 0) - { - gDebugInfo["Dynamic"]["MinidumpPath"] = minidump_file; - } - else - { -#ifdef LL_WINDOWS - getFileList(); -#else - LL_WARNS("CRASHREPORT") << "no minidump file?" << LL_ENDL; -#endif - } - gDebugInfo["Dynamic"]["CrashType"]="crash"; - - if (gMessageSystem && gDirUtilp) - { - std::string filename; - filename = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "stats.log"); - LL_DEBUGS("CRASHREPORT") << "recording stats " << filename << LL_ENDL; - llofstream file(filename.c_str(), std::ios_base::binary); - if(file.good()) - { - gMessageSystem->summarizeLogs(file); - file.close(); - } - else - { - LL_WARNS("CRASHREPORT") << "problem recording stats" << LL_ENDL; - } - } - - if (gMessageSystem) - { - gMessageSystem->getCircuitInfo(gDebugInfo["CircuitInfo"]); - gMessageSystem->stopLogging(); - } - - if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo["Dynamic"]); - - gDebugInfo["FatalMessage"] = LLError::getFatalMessage(); - - // Close the debug file - pApp->writeDebugInfo(false); //false answers the isStatic question with the least overhead. -} - // static void LLAppViewer::recordMarkerVersion(LLAPRFile& marker_file) { diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index f28a90c703..bc4dec6bec 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -119,7 +119,6 @@ public: virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism. // return false if the error trap needed restoration. - static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon. void checkForCrash(); // Thread accessors diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index dc487967fc..9f58f90326 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -80,8 +80,6 @@ int main( int argc, char **argv ) // install unexpected exception handler gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler); - // install crash handlers - viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash); bool ok = viewer_app_ptr->init(); if(!ok) diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index cb5cac6f2d..8b313a321b 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -83,8 +83,6 @@ void constructViewer() } gViewerAppPtr = new LLAppViewerMacOSX(); - - gViewerAppPtr->setErrorHandler(LLAppViewer::handleViewerCrash); } bool initViewer() diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index d22fb7a4e6..298d841934 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -428,8 +428,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler); - viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash); - // Set a debug info flag to indicate if multiple instances are running. bool found_other_instance = !create_app_mutex(); gDebugInfo["FoundOtherInstanceAtStartup"] = LLSD::Boolean(found_other_instance); diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h index f778634d25..10cde35f9c 100644 --- a/indra/newview/llavatarpropertiesprocessor.h +++ b/indra/newview/llavatarpropertiesprocessor.h @@ -85,6 +85,7 @@ struct LLAvatarData std::string profile_url; U8 caption_index; std::string caption_text; + std::string customer_type; U32 flags; BOOL allow_publish; }; diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 594cfe513d..3fd15d36df 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -402,7 +402,7 @@ void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL t if(pparams->mFace) { LLViewerObject* vobj = pparams->mFace->getViewerObject(); - if(vobj->isAttachment()) + if(vobj && vobj->isAttachment()) { trackAttachments(vobj, false, &ratPtr); } @@ -429,7 +429,7 @@ void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, if(pparams->mFace) { LLViewerObject* vobj = pparams->mFace->getViewerObject(); - if(vobj->isAttachment()) + if(vobj && vobj->isAttachment()) { trackAttachments( vobj, true ,&ratPtr); } @@ -459,7 +459,7 @@ void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_text if(pparams->mFace) { LLViewerObject* vobj = pparams->mFace->getViewerObject(); - if(vobj->isAttachment()) + if(vobj && vobj->isAttachment()) { trackAttachments( vobj, false, &ratPtr); } @@ -484,7 +484,7 @@ void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batc if(pparams->mFace) { LLViewerObject* vobj = pparams->mFace->getViewerObject(); - if(vobj->isAttachment()) + if(vobj && vobj->isAttachment()) { trackAttachments( vobj, true, &ratPtr); } @@ -514,7 +514,7 @@ void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_ if((*pparams).mFace) { LLViewerObject* vobj = (*pparams).mFace->getViewerObject(); - if(vobj->isAttachment()) + if(vobj && vobj->isAttachment()) { trackAttachments( vobj, false, &ratPtr); } @@ -539,7 +539,7 @@ void LLRenderPass::pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture, BOOL if((*pparams).mFace) { LLViewerObject* vobj = (*pparams).mFace->getViewerObject(); - if(vobj->isAttachment()) + if(vobj && vobj->isAttachment()) { trackAttachments( vobj, true, &ratPtr); } diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 5b205d373b..ab1ac7e30c 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -281,6 +281,8 @@ void LLDrawPoolAlpha::renderDebugAlpha() { gHighlightProgram.bind(); gGL.diffuseColor4f(1, 0, 0, 1); + + LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f * 1024.f); gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::sSmokeImagep); @@ -347,7 +349,7 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) if(params.mFace) { LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); - if(vobj->isAttachment()) + if(vobj && vobj->isAttachment()) { trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); } @@ -620,7 +622,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) { LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); - if(vobj->isAttachment()) + if(vobj && vobj->isAttachment()) { trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); } diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index b61afcbbc9..f1f156c2e0 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -55,9 +55,6 @@ LLFilePicker LLFilePicker::sInstance; #define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0" #define ANIM_FILTER L"Animations (*.bvh; *.anim)\0*.bvh;*.anim\0" #define COLLADA_FILTER L"Scene (*.dae)\0*.dae\0" -#ifdef _CORY_TESTING -#define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0" -#endif #define XML_FILTER L"XML files (*.xml)\0*.xml\0" #define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0" #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0" @@ -197,12 +194,6 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) mOFN.lpstrFilter = COLLADA_FILTER \ L"\0"; break; -#ifdef _CORY_TESTING - case FFLOAD_GEOMETRY: - mOFN.lpstrFilter = GEOMETRY_FILTER \ - L"\0"; - break; -#endif case FFLOAD_XML: mOFN.lpstrFilter = XML_FILTER \ L"\0"; @@ -498,18 +489,6 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, L"XAF Anim File (*.xaf)\0*.xaf\0" \ L"\0"; break; -#ifdef _CORY_TESTING - case FFSAVE_GEOMETRY: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.slg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"slg"; - mOFN.lpstrFilter = - L"SLG SL Geometry File (*.slg)\0*.slg\0" \ - L"\0"; - break; -#endif case FFSAVE_XML: if (filename.empty()) { @@ -652,11 +631,6 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF case FFLOAD_COLLADA: allowedv->push_back("dae"); break; -#ifdef _CORY_TESTING - case FFLOAD_GEOMETRY: - allowedv->push_back("slg"); - break; -#endif case FFLOAD_XML: allowedv->push_back("xml"); break; @@ -771,14 +745,6 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, creator = "\?\?\?\?"; extension = "xaf"; break; - -#ifdef _CORY_TESTING - case LLFilePicker::FFSAVE_GEOMETRY: - type = "\?\?\?\?"; - creator = "\?\?\?\?"; - extension = "slg"; - break; -#endif case LLFilePicker::FFSAVE_XML: type = "\?\?\?\?"; diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 26649e0940..692b908fff 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -77,9 +77,6 @@ public: FFLOAD_WAV = 2, FFLOAD_IMAGE = 3, FFLOAD_ANIM = 4, -#ifdef _CORY_TESTING - FFLOAD_GEOMETRY = 5, -#endif FFLOAD_XML = 6, FFLOAD_SLOBJECT = 7, FFLOAD_RAW = 8, @@ -99,9 +96,6 @@ public: FFSAVE_BMP = 5, FFSAVE_AVI = 6, FFSAVE_ANIM = 7, -#ifdef _CORY_TESTING - FFSAVE_GEOMETRY = 8, -#endif FFSAVE_XML = 9, FFSAVE_COLLADA = 10, FFSAVE_RAW = 11, diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index f1807f1c5b..0d2c6d8e4c 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -108,6 +108,8 @@ LLFloaterIMNearbyChat::LLFloaterIMNearbyChat(const LLSD& llsd) mEnableCallbackRegistrar.add("Avatar.EnableGearItem", boost::bind(&cb_do_nothing)); mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", boost::bind(&cb_do_nothing)); mEnableCallbackRegistrar.add("Avatar.CheckGearItem", boost::bind(&cb_do_nothing)); + + mMinFloaterHeight = EXPANDED_MIN_HEIGHT; } //static diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 78271369d2..af4e7f5aff 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -92,6 +92,8 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id) mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLFloaterIMSessionTab::enableContextMenuItem, this, _2)); mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLFloaterIMSessionTab::doToSelected, this, _2)); mCommitCallbackRegistrar.add("Group.DoToSelected", boost::bind(&cb_group_do_nothing)); + + mMinFloaterHeight = getMinHeight(); } LLFloaterIMSessionTab::~LLFloaterIMSessionTab() @@ -934,10 +936,13 @@ void LLFloaterIMSessionTab::reshapeFloater(bool collapse) S32 height = mContentPanel->getRect().getHeight() + mToolbarPanel->getRect().getHeight() + mChatLayoutPanel->getRect().getHeight() - mChatLayoutPanelHeight + 2; floater_rect.mTop -= height; + + setResizeLimits(getMinWidth(), floater_rect.getHeight()); } else { floater_rect.mTop = floater_rect.mBottom + mFloaterHeight; + setResizeLimits(getMinWidth(), mMinFloaterHeight); } enableResizeCtrls(true, true, !collapse); @@ -962,6 +967,7 @@ void LLFloaterIMSessionTab::restoreFloater() setShape(floater_rect, true); mBodyStack->updateLayout(); mExpandCollapseLineBtn->setImageOverlay(getString("expandline_icon")); + setResizeLimits(getMinWidth(), mMinFloaterHeight); setMessagePaneExpanded(true); saveCollapsedState(); mInputEditor->enableSingleLineMode(false); diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h index 9f00917647..d478922617 100644 --- a/indra/newview/llfloaterimsessiontab.h +++ b/indra/newview/llfloaterimsessiontab.h @@ -152,6 +152,7 @@ protected: bool mMessagePaneExpanded; bool mIsParticipantListExpanded; + S32 mMinFloaterHeight; LLIMModel::LLIMSession* mSession; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index da7a4733c7..a24f04ccfb 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -317,7 +317,6 @@ void LLFloaterRegionInfo::onOpen(const LLSD& key) } refreshFromRegion(gAgent.getRegion()); requestRegionInfo(); - requestMeshRezInfo(); if (!mGodLevelChangeSlot.connected()) { @@ -1006,19 +1005,6 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L return false; } -void LLFloaterRegionInfo::requestMeshRezInfo() -{ - std::string sim_console_url = gAgent.getRegionCapability("SimConsoleAsync"); - - if (!sim_console_url.empty()) - { - std::string request_str = "get mesh_rez_enabled"; - - LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(sim_console_url, LLSD(request_str), - "Requested mesh_rez_enabled", "Error requesting mesh_rez_enabled"); - } -} - // setregioninfo // strings[0] = 'Y' - block terraform, 'N' - not // strings[1] = 'Y' - block fly, 'N' - not diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index c34dbb62e8..3eb39b250f 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -102,7 +102,6 @@ public: void onRegionChanged(); void requestRegionInfo(); - void requestMeshRezInfo(); void enableTopButtons(); void disableTopButtons(); diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp index 082bb888b1..d29ecbbf95 100644 --- a/indra/newview/llfloatertranslationsettings.cpp +++ b/indra/newview/llfloatertranslationsettings.cpp @@ -45,15 +45,9 @@ LLFloaterTranslationSettings::LLFloaterTranslationSettings(const LLSD& key) : LLFloater(key) , mMachineTranslationCB(NULL) -, mLanguageCombo(NULL) -, mTranslationServiceRadioGroup(NULL) -, mBingAPIKeyEditor(NULL) -, mGoogleAPIKeyEditor(NULL) -, mBingVerifyBtn(NULL) -, mGoogleVerifyBtn(NULL) -, mOKBtn(NULL) -, mBingKeyVerified(false) +, mAzureKeyVerified(false) , mGoogleKeyVerified(false) +, mDeepLKeyVerified(false) { } @@ -63,24 +57,54 @@ BOOL LLFloaterTranslationSettings::postBuild() mMachineTranslationCB = getChild<LLCheckBoxCtrl>("translate_chat_checkbox"); mLanguageCombo = getChild<LLComboBox>("translate_language_combo"); mTranslationServiceRadioGroup = getChild<LLRadioGroup>("translation_service_rg"); - mBingAPIKeyEditor = getChild<LLLineEditor>("bing_api_key"); + mAzureAPIEndpointEditor = getChild<LLComboBox>("azure_api_endpoint_combo"); + mAzureAPIKeyEditor = getChild<LLLineEditor>("azure_api_key"); + mAzureAPIRegionEditor = getChild<LLLineEditor>("azure_api_region"); mGoogleAPIKeyEditor = getChild<LLLineEditor>("google_api_key"); - mBingVerifyBtn = getChild<LLButton>("verify_bing_api_key_btn"); + mDeepLAPIDomainCombo = getChild<LLComboBox>("deepl_api_domain_combo"); + mDeepLAPIKeyEditor = getChild<LLLineEditor>("deepl_api_key"); + mAzureVerifyBtn = getChild<LLButton>("verify_azure_api_key_btn"); mGoogleVerifyBtn = getChild<LLButton>("verify_google_api_key_btn"); + mDeepLVerifyBtn = getChild<LLButton>("verify_deepl_api_key_btn"); mOKBtn = getChild<LLButton>("ok_btn"); mMachineTranslationCB->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::updateControlsEnabledState, this)); mTranslationServiceRadioGroup->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::updateControlsEnabledState, this)); mOKBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnOK, this)); getChild<LLButton>("cancel_btn")->setClickedCallback(boost::bind(&LLFloater::closeFloater, this, false)); - mBingVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnBingVerify, this)); + mAzureVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnAzureVerify, this)); mGoogleVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnGoogleVerify, this)); + mDeepLVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnDeepLVerify, this)); + + mAzureAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1)); + mAzureAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this), NULL); + mAzureAPIRegionEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1)); + mAzureAPIRegionEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this), NULL); + + mAzureAPIEndpointEditor->setFocusLostCallback([this](LLFocusableElement*) + { + setAzureVerified(false, false, 0); + }); + mAzureAPIEndpointEditor->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) + { + setAzureVerified(false, false, 0); + }); - mBingAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1)); - mBingAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onBingKeyEdited, this), NULL); mGoogleAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1)); mGoogleAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onGoogleKeyEdited, this), NULL); + mDeepLAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1)); + mDeepLAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onDeepLKeyEdited, this), NULL); + + mDeepLAPIDomainCombo->setFocusLostCallback([this](LLFocusableElement*) + { + setDeepLVerified(false, false, 0); + }); + mDeepLAPIDomainCombo->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) + { + setDeepLVerified(false, false, 0); + }); + center(); return TRUE; } @@ -92,17 +116,28 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key) mLanguageCombo->setSelectedByValue(gSavedSettings.getString("TranslateLanguage"), TRUE); mTranslationServiceRadioGroup->setSelectedByValue(gSavedSettings.getString("TranslationService"), TRUE); - std::string bing_key = gSavedSettings.getString("BingTranslateAPIKey"); - if (!bing_key.empty()) + LLSD azure_key = gSavedSettings.getLLSD("AzureTranslateAPIKey"); + if (azure_key.isMap() && !azure_key["id"].asString().empty()) { - mBingAPIKeyEditor->setText(bing_key); - mBingAPIKeyEditor->setTentative(FALSE); - verifyKey(LLTranslate::SERVICE_BING, bing_key, false); + mAzureAPIKeyEditor->setText(azure_key["id"].asString()); + mAzureAPIKeyEditor->setTentative(false); + if (azure_key.has("region") && !azure_key["region"].asString().empty()) + { + mAzureAPIRegionEditor->setText(azure_key["region"].asString()); + mAzureAPIRegionEditor->setTentative(false); + } + else + { + mAzureAPIRegionEditor->setTentative(true); + } + mAzureAPIEndpointEditor->setValue(azure_key["endpoint"]); + verifyKey(LLTranslate::SERVICE_AZURE, azure_key, false); } else { - mBingAPIKeyEditor->setTentative(TRUE); - mBingKeyVerified = FALSE; + mAzureAPIKeyEditor->setTentative(TRUE); + mAzureAPIRegionEditor->setTentative(true); + mAzureKeyVerified = FALSE; } std::string google_key = gSavedSettings.getString("GoogleTranslateAPIKey"); @@ -118,39 +153,74 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key) mGoogleKeyVerified = FALSE; } + LLSD deepl_key = gSavedSettings.getLLSD("DeepLTranslateAPIKey"); + if (deepl_key.isMap() && !deepl_key["id"].asString().empty()) + { + mDeepLAPIKeyEditor->setText(deepl_key["id"].asString()); + mDeepLAPIKeyEditor->setTentative(false); + mDeepLAPIDomainCombo->setValue(deepl_key["domain"]); + verifyKey(LLTranslate::SERVICE_DEEPL, deepl_key, false); + } + else + { + mDeepLAPIKeyEditor->setTentative(TRUE); + mDeepLKeyVerified = FALSE; + } + updateControlsEnabledState(); } -void LLFloaterTranslationSettings::setBingVerified(bool ok, bool alert) +void LLFloaterTranslationSettings::setAzureVerified(bool ok, bool alert, S32 status) { if (alert) { - showAlert(ok ? "bing_api_key_verified" : "bing_api_key_not_verified"); + showAlert(ok ? "azure_api_key_verified" : "azure_api_key_not_verified", status); } - mBingKeyVerified = ok; + mAzureKeyVerified = ok; updateControlsEnabledState(); } -void LLFloaterTranslationSettings::setGoogleVerified(bool ok, bool alert) +void LLFloaterTranslationSettings::setGoogleVerified(bool ok, bool alert, S32 status) { if (alert) { - showAlert(ok ? "google_api_key_verified" : "google_api_key_not_verified"); + showAlert(ok ? "google_api_key_verified" : "google_api_key_not_verified", status); } mGoogleKeyVerified = ok; updateControlsEnabledState(); } +void LLFloaterTranslationSettings::setDeepLVerified(bool ok, bool alert, S32 status) +{ + if (alert) + { + showAlert(ok ? "deepl_api_key_verified" : "deepl_api_key_not_verified", status); + } + + mDeepLKeyVerified = ok; + updateControlsEnabledState(); +} + std::string LLFloaterTranslationSettings::getSelectedService() const { return mTranslationServiceRadioGroup->getSelectedValue().asString(); } -std::string LLFloaterTranslationSettings::getEnteredBingKey() const +LLSD LLFloaterTranslationSettings::getEnteredAzureKey() const { - return mBingAPIKeyEditor->getTentative() ? LLStringUtil::null : mBingAPIKeyEditor->getText(); + LLSD key; + if (!mAzureAPIKeyEditor->getTentative()) + { + key["endpoint"] = mAzureAPIEndpointEditor->getValue(); + key["id"] = mAzureAPIKeyEditor->getText(); + if (!mAzureAPIRegionEditor->getTentative()) + { + key["region"] = mAzureAPIRegionEditor->getText(); + } + } + return key; } std::string LLFloaterTranslationSettings::getEnteredGoogleKey() const @@ -158,10 +228,26 @@ std::string LLFloaterTranslationSettings::getEnteredGoogleKey() const return mGoogleAPIKeyEditor->getTentative() ? LLStringUtil::null : mGoogleAPIKeyEditor->getText(); } -void LLFloaterTranslationSettings::showAlert(const std::string& msg_name) const +LLSD LLFloaterTranslationSettings::getEnteredDeepLKey() const +{ + LLSD key; + if (!mDeepLAPIKeyEditor->getTentative()) + { + key["domain"] = mDeepLAPIDomainCombo->getValue(); + key["id"] = mDeepLAPIKeyEditor->getText(); + } + return key; +} + +void LLFloaterTranslationSettings::showAlert(const std::string& msg_name, S32 status) const { + LLStringUtil::format_map_t string_args; + // For now just show an http error code, whole 'reason' string might be added later + string_args["[STATUS]"] = llformat("%d", status); + std::string message = getString(msg_name, string_args); + LLSD args; - args["MESSAGE"] = getString(msg_name); + args["MESSAGE"] = message; LLNotificationsUtil::add("GenericAlert", args); } @@ -170,34 +256,51 @@ void LLFloaterTranslationSettings::updateControlsEnabledState() // Enable/disable controls based on the checkbox value. bool on = mMachineTranslationCB->getValue().asBoolean(); std::string service = getSelectedService(); - bool bing_selected = service == "bing"; + bool azure_selected = service == "azure"; bool google_selected = service == "google"; + bool deepl_selected = service == "deepl"; mTranslationServiceRadioGroup->setEnabled(on); mLanguageCombo->setEnabled(on); - getChild<LLTextBox>("bing_api_key_label")->setEnabled(on); - mBingAPIKeyEditor->setEnabled(on); + // MS Azure + getChild<LLTextBox>("azure_api_endoint_label")->setEnabled(on); + mAzureAPIEndpointEditor->setEnabled(on && azure_selected); + getChild<LLTextBox>("azure_api_key_label")->setEnabled(on); + mAzureAPIKeyEditor->setEnabled(on && azure_selected); + getChild<LLTextBox>("azure_api_region_label")->setEnabled(on); + mAzureAPIRegionEditor->setEnabled(on && azure_selected); - getChild<LLTextBox>("google_api_key_label")->setEnabled(on); - mGoogleAPIKeyEditor->setEnabled(on); + mAzureVerifyBtn->setEnabled(on && azure_selected && + !mAzureKeyVerified && getEnteredAzureKey().isMap()); - mBingAPIKeyEditor->setEnabled(on && bing_selected); - mGoogleAPIKeyEditor->setEnabled(on && google_selected); + // Google + getChild<LLTextBox>("google_api_key_label")->setEnabled(on); + mGoogleAPIKeyEditor->setEnabled(on && google_selected); - mBingVerifyBtn->setEnabled(on && bing_selected && - !mBingKeyVerified && !getEnteredBingKey().empty()); mGoogleVerifyBtn->setEnabled(on && google_selected && !mGoogleKeyVerified && !getEnteredGoogleKey().empty()); - bool service_verified = (bing_selected && mBingKeyVerified) || (google_selected && mGoogleKeyVerified); + // DeepL + getChild<LLTextBox>("deepl_api_domain_label")->setEnabled(on); + mDeepLAPIDomainCombo->setEnabled(on && deepl_selected); + getChild<LLTextBox>("deepl_api_key_label")->setEnabled(on); + mDeepLAPIKeyEditor->setEnabled(on && deepl_selected); + + mDeepLVerifyBtn->setEnabled(on && deepl_selected && + !mDeepLKeyVerified && getEnteredDeepLKey().isMap()); + + bool service_verified = + (azure_selected && mAzureKeyVerified) + || (google_selected && mGoogleKeyVerified) + || (deepl_selected && mDeepLKeyVerified); gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified); mOKBtn->setEnabled(!on || service_verified); } /*static*/ -void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, bool alert) +void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, bool alert, S32 status) { LLFloaterTranslationSettings* floater = LLFloaterReg::getTypedInstance<LLFloaterTranslationSettings>("prefs_translation"); @@ -210,20 +313,23 @@ void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, b switch (service) { - case LLTranslate::SERVICE_BING: - floater->setBingVerified(ok, alert); + case LLTranslate::SERVICE_AZURE: + floater->setAzureVerified(ok, alert, status); break; case LLTranslate::SERVICE_GOOGLE: - floater->setGoogleVerified(ok, alert); + floater->setGoogleVerified(ok, alert, status); + break; + case LLTranslate::SERVICE_DEEPL: + floater->setDeepLVerified(ok, alert, status); break; } } -void LLFloaterTranslationSettings::verifyKey(int service, const std::string& key, bool alert) +void LLFloaterTranslationSettings::verifyKey(int service, const LLSD& key, bool alert) { LLTranslate::verifyKey(static_cast<LLTranslate::EService>(service), key, - boost::bind(&LLFloaterTranslationSettings::setVerificationStatus, _1, _2, alert)); + boost::bind(&LLFloaterTranslationSettings::setVerificationStatus, _1, _2, alert, _3)); } void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control) @@ -239,11 +345,13 @@ void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control) } } -void LLFloaterTranslationSettings::onBingKeyEdited() +void LLFloaterTranslationSettings::onAzureKeyEdited() { - if (mBingAPIKeyEditor->isDirty()) + if (mAzureAPIKeyEditor->isDirty() + || mAzureAPIRegionEditor->isDirty()) { - setBingVerified(false, false); + // todo: verify mAzureAPIEndpointEditor url + setAzureVerified(false, false, 0); } } @@ -251,16 +359,24 @@ void LLFloaterTranslationSettings::onGoogleKeyEdited() { if (mGoogleAPIKeyEditor->isDirty()) { - setGoogleVerified(false, false); + setGoogleVerified(false, false, 0); } } -void LLFloaterTranslationSettings::onBtnBingVerify() +void LLFloaterTranslationSettings::onDeepLKeyEdited() { - std::string key = getEnteredBingKey(); - if (!key.empty()) + if (mDeepLAPIKeyEditor->isDirty()) + { + setDeepLVerified(false, false, 0); + } +} + +void LLFloaterTranslationSettings::onBtnAzureVerify() +{ + LLSD key = getEnteredAzureKey(); + if (key.isMap()) { - verifyKey(LLTranslate::SERVICE_BING, key); + verifyKey(LLTranslate::SERVICE_AZURE, key); } } @@ -269,26 +385,40 @@ void LLFloaterTranslationSettings::onBtnGoogleVerify() std::string key = getEnteredGoogleKey(); if (!key.empty()) { - verifyKey(LLTranslate::SERVICE_GOOGLE, key); + verifyKey(LLTranslate::SERVICE_GOOGLE, LLSD(key)); } } + +void LLFloaterTranslationSettings::onBtnDeepLVerify() +{ + LLSD key = getEnteredDeepLKey(); + if (key.isMap()) + { + verifyKey(LLTranslate::SERVICE_DEEPL, key); + } +} + void LLFloaterTranslationSettings::onClose(bool app_quitting) { std::string service = gSavedSettings.getString("TranslationService"); - bool bing_selected = service == "bing"; + bool azure_selected = service == "azure"; bool google_selected = service == "google"; + bool deepl_selected = service == "deepl"; - bool service_verified = (bing_selected && mBingKeyVerified) || (google_selected && mGoogleKeyVerified); - gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified); - + bool service_verified = + (azure_selected && mAzureKeyVerified) + || (google_selected && mGoogleKeyVerified) + || (deepl_selected && mDeepLKeyVerified); + gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified); } void LLFloaterTranslationSettings::onBtnOK() { gSavedSettings.setBOOL("TranslateChat", mMachineTranslationCB->getValue().asBoolean()); gSavedSettings.setString("TranslateLanguage", mLanguageCombo->getSelectedValue().asString()); gSavedSettings.setString("TranslationService", getSelectedService()); - gSavedSettings.setString("BingTranslateAPIKey", getEnteredBingKey()); + gSavedSettings.setLLSD("AzureTranslateAPIKey", getEnteredAzureKey()); gSavedSettings.setString("GoogleTranslateAPIKey", getEnteredGoogleKey()); + gSavedSettings.setLLSD("DeepLTranslateAPIKey", getEnteredDeepLKey()); closeFloater(false); } diff --git a/indra/newview/llfloatertranslationsettings.h b/indra/newview/llfloatertranslationsettings.h index 2a15eacded..eff0803fdd 100644 --- a/indra/newview/llfloatertranslationsettings.h +++ b/indra/newview/llfloatertranslationsettings.h @@ -42,38 +42,48 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); - void setBingVerified(bool ok, bool alert); - void setGoogleVerified(bool ok, bool alert); + void setAzureVerified(bool ok, bool alert, S32 status); + void setGoogleVerified(bool ok, bool alert, S32 status); + void setDeepLVerified(bool ok, bool alert, S32 status); void onClose(bool app_quitting); private: std::string getSelectedService() const; - std::string getEnteredBingKey() const; + LLSD getEnteredAzureKey() const; std::string getEnteredGoogleKey() const; - void showAlert(const std::string& msg_name) const; + LLSD getEnteredDeepLKey() const; + void showAlert(const std::string& msg_name, S32 status) const; void updateControlsEnabledState(); - void verifyKey(int service, const std::string& key, bool alert = true); + void verifyKey(int service, const LLSD& key, bool alert = true); void onEditorFocused(LLFocusableElement* control); - void onBingKeyEdited(); + void onAzureKeyEdited(); void onGoogleKeyEdited(); - void onBtnBingVerify(); + void onDeepLKeyEdited(); + void onBtnAzureVerify(); void onBtnGoogleVerify(); + void onBtnDeepLVerify(); void onBtnOK(); - static void setVerificationStatus(int service, bool alert, bool ok); + static void setVerificationStatus(int service, bool alert, bool ok, S32 status); LLCheckBoxCtrl* mMachineTranslationCB; LLComboBox* mLanguageCombo; - LLLineEditor* mBingAPIKeyEditor; + LLComboBox* mAzureAPIEndpointEditor; + LLLineEditor* mAzureAPIKeyEditor; + LLLineEditor* mAzureAPIRegionEditor; LLLineEditor* mGoogleAPIKeyEditor; + LLComboBox* mDeepLAPIDomainCombo; + LLLineEditor* mDeepLAPIKeyEditor; LLRadioGroup* mTranslationServiceRadioGroup; - LLButton* mBingVerifyBtn; + LLButton* mAzureVerifyBtn; LLButton* mGoogleVerifyBtn; + LLButton* mDeepLVerifyBtn; LLButton* mOKBtn; - bool mBingKeyVerified; + bool mAzureKeyVerified; bool mGoogleKeyVerified; + bool mDeepLKeyVerified; }; #endif // LL_LLFLOATERTRANSLATIONSETTINGS_H diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 26288e6b0a..03205cfbda 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -32,7 +32,6 @@ #include "llappviewer.h" #include "llcallbacklist.h" #include "llinventorymodel.h" -#include "llinventoryobserver.h" #include "llinventorypanel.h" #include "llnotificationsutil.h" #include "llstartup.h" diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h index 2c45014321..14840f1b2e 100644 --- a/indra/newview/llmutelist.h +++ b/indra/newview/llmutelist.h @@ -99,6 +99,7 @@ public: BOOL isMuted(const LLUUID& id, const std::string& name = LLStringUtil::null, U32 flags = 0) const; // Workaround for username-based mute search, a lot of string conversions so use cautiously + // Expects lower case username BOOL isMuted(const std::string& username, U32 flags = 0) const; // Alternate (convenience) form for places we don't need to pass the name, but do need flags diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 178aba11a3..cbb87f63bb 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -831,7 +831,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) { //set state of UI to match state of texture entry(ies) (calls setEnabled, setValue, etc, but NOT setVisible) LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); - if( objectp + if (objectp && objectp->getPCode() == LL_PCODE_VOLUME && objectp->permModify()) { @@ -854,7 +854,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) } LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type"); - if(radio_mat_type) + if (radio_mat_type) { if (radio_mat_type->getSelectedIndex() < MATTYPE_DIFFUSE) { @@ -871,10 +871,10 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) childSetValue("checkbox_sync_settings", gSavedSettings.getBOOL("SyncMaterialSettings")); updateVisibility(); - bool identical = true; // true because it is anded below - bool identical_diffuse = false; - bool identical_norm = false; - bool identical_spec = false; + bool identical = true; // true because it is anded below + bool identical_diffuse = false; + bool identical_norm = false; + bool identical_spec = false; LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("texture control"); LLTextureCtrl* shinytexture_ctrl = getChild<LLTextureCtrl>("shinytexture control"); @@ -888,12 +888,12 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) { getChildView("color label")->setEnabled(editable); } - LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>("colorswatch"); + LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>("colorswatch"); - LLColor4 color = LLColor4::white; - bool identical_color = false; + LLColor4 color = LLColor4::white; + bool identical_color = false; - if(color_swatch) + if (color_swatch) { LLSelectedTE::getColor(color, identical_color); LLColor4 prev_color = color_swatch->get(); @@ -927,7 +927,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) LLCtrlSelectionInterface* combobox_shininess = childGetSelectionInterface("combobox shininess"); if (combobox_shininess) - { + { combobox_shininess->selectNthItem((S32)shiny); } @@ -947,8 +947,8 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) getChild<LLUICtrl>("shinycolorswatch")->setTentative(!identical_spec); LLColorSwatchCtrl* mShinyColorSwatch = getChild<LLColorSwatchCtrl>("shinycolorswatch"); - if(mShinyColorSwatch) - { + if (mShinyColorSwatch) + { mShinyColorSwatch->setValid(editable); mShinyColorSwatch->setEnabled( editable ); mShinyColorSwatch->setCanApplyImmediately( editable ); @@ -956,7 +956,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) U8 bumpy = 0; // Bumpy - { + { bool identical_bumpy = false; LLSelectedTE::getBumpmap(bumpy,identical_bumpy); @@ -966,18 +966,18 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) bumpy = norm_map_id.isNull() ? bumpy : BUMPY_TEXTURE; if (combobox_bumpiness) - { + { combobox_bumpiness->selectNthItem((S32)bumpy); - } + } else - { + { LL_WARNS() << "failed childGetSelectionInterface for 'combobox bumpiness'" << LL_ENDL; - } + } getChildView("combobox bumpiness")->setEnabled(editable); getChild<LLUICtrl>("combobox bumpiness")->setTentative(!identical_bumpy); getChildView("label bumpiness")->setEnabled(editable); - } + } // Texture { @@ -991,25 +991,25 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) bool identical_image_format = false; LLSelectedTE::getImageFormat(image_format, identical_image_format); - mIsAlpha = FALSE; - switch (image_format) - { - case GL_RGBA: - case GL_ALPHA: - { - mIsAlpha = TRUE; - } - break; - - case GL_RGB: break; - default: - { - LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL; - } - break; + mIsAlpha = FALSE; + switch (image_format) + { + case GL_RGBA: + case GL_ALPHA: + { + mIsAlpha = TRUE; + } + break; + + case GL_RGB: break; + default: + { + LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL; } + break; + } - if(LLViewerMedia::getInstance()->textureHasMedia(id)) + if (LLViewerMedia::getInstance()->textureHasMedia(id)) { getChildView("button align")->setEnabled(editable); } @@ -1046,7 +1046,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) updateAlphaControls(); if (texture_ctrl) - { + { if (identical_diffuse) { texture_ctrl->setTentative(FALSE); @@ -1060,8 +1060,8 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) texture_ctrl->setBakeTextureEnabled(TRUE); } else if (id.isNull()) - { - // None selected + { + // None selected texture_ctrl->setTentative(FALSE); texture_ctrl->setEnabled(FALSE); texture_ctrl->setImageAssetID(LLUUID::null); @@ -1071,10 +1071,10 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) getChildView("label maskcutoff")->setEnabled(FALSE); texture_ctrl->setBakeTextureEnabled(false); - } - else - { - // Tentative: multiple selected with different textures + } + else + { + // Tentative: multiple selected with different textures texture_ctrl->setTentative(TRUE); texture_ctrl->setEnabled(editable); texture_ctrl->setImageAssetID(id); @@ -1085,7 +1085,6 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) texture_ctrl->setBakeTextureEnabled(TRUE); } - } if (shinytexture_ctrl) @@ -1343,15 +1342,14 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) combobox_texgen->selectNthItem(((S32)selected_texgen) >> 1); } else - { + { LL_WARNS() << "failed childGetSelectionInterface for 'combobox texgen'" << LL_ENDL; - } + } getChildView("combobox texgen")->setEnabled(editable); getChild<LLUICtrl>("combobox texgen")->setTentative(!identical); getChildView("tex gen")->setEnabled(editable); - - } + } { U8 fullbright_flag = 0; @@ -1380,7 +1378,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) LLComboBox* mComboTexGen = getChild<LLComboBox>("combobox texgen"); if (mComboTexGen) - { + { S32 index = mComboTexGen ? mComboTexGen->getCurrentIndex() : 0; BOOL enabled = editable && (index != 1); BOOL identical_repeats = true; @@ -1390,26 +1388,26 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) LLSelectMgr::getInstance()->setTextureChannel(LLRender::eTexIndex(material_type)); switch (material_type) - { + { default: case MATTYPE_DIFFUSE: - { + { enabled = editable && !id.isNull(); identical_repeats = identical_diff_repeats; repeats = repeats_diff; - } + } break; case MATTYPE_SPECULAR: - { + { enabled = (editable && ((shiny == SHINY_TEXTURE) && !specmap_id.isNull())); identical_repeats = identical_spec_repeats; repeats = repeats_spec; - } + } break; case MATTYPE_NORMAL: - { + { enabled = (editable && ((bumpy == BUMPY_TEXTURE) && !normmap_id.isNull())); identical_repeats = identical_norm_repeats; repeats = repeats_norm; @@ -1458,14 +1456,14 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) if (!mIsAlpha) { // ... unless there is no alpha channel in the texture, in which case alpha mode MUST ebe none alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE; - } + } combobox_alphamode->selectNthItem(alpha_mode); - } - else - { + } + else + { LL_WARNS() << "failed childGetSelectionInterface for 'combobox alphamode'" << LL_ENDL; - } + } getChild<LLUICtrl>("maskcutoff")->setValue(material->getAlphaMaskCutoff()); updateAlphaControls(); @@ -1477,15 +1475,15 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) texture_ctrl->setImageAssetID(material->getSpecularID()); if (!material->getSpecularID().isNull() && (shiny == SHINY_TEXTURE)) - { + { material->getSpecularOffset(offset_x,offset_y); material->getSpecularRepeat(repeat_x,repeat_y); if (identical_planar_texgen) - { + { repeat_x *= 2.0f; repeat_y *= 2.0f; - } + } rot = material->getSpecularRotation(); getChild<LLUICtrl>("shinyScaleU")->setValue(repeat_x); @@ -1497,7 +1495,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) getChild<LLUICtrl>("environment")->setValue(material->getEnvironmentIntensity()); updateShinyControls(!material->getSpecularID().isNull(), true); - } + } // Assert desired colorswatch color to match material AFTER updateShinyControls // to avoid getting overwritten with the default on some UI state changes. @@ -1559,14 +1557,14 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) // Disable non-UICtrls LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("texture control"); - if(texture_ctrl) + if (texture_ctrl) { texture_ctrl->setImageAssetID( LLUUID::null ); texture_ctrl->setEnabled( FALSE ); // this is a LLUICtrl, but we don't want it to have keyboard focus so we add it as a child, not a ctrl. // texture_ctrl->setValid(FALSE); } LLColorSwatchCtrl* mColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch"); - if(mColorSwatch) + if (mColorSwatch) { mColorSwatch->setEnabled( FALSE ); mColorSwatch->setFallbackImage(LLUI::getUIImage("locked_image.j2c") ); @@ -1609,7 +1607,6 @@ void LLPanelFace::updateCopyTexButton() && (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1)); std::string tooltip = (objectp && objectp->isInventoryPending()) ? LLTrans::getString("LoadingContents") : getString("paste_options"); mMenuClipboardTexture->setToolTip(tooltip); - } void LLPanelFace::refresh() diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 44bc442bbb..aaf8eddaf7 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -134,8 +134,7 @@ protected: void sendTexGen(); // applies and sends bump map void sendShiny(U32 shininess); // applies and sends shininess void sendFullbright(); // applies and sends full bright - void sendGlow(); - void sendMedia(); + void sendGlow(); void alignTestureLayer(); void updateCopyTexButton(); @@ -240,7 +239,6 @@ protected: private: - bool isAlpha() { return mIsAlpha; } // Convenience funcs to keep the visual flack to a minimum @@ -249,10 +247,10 @@ private: LLUUID getCurrentSpecularMap(); U32 getCurrentShininess(); U32 getCurrentBumpiness(); - U8 getCurrentDiffuseAlphaMode(); - U8 getCurrentAlphaMaskCutoff(); - U8 getCurrentEnvIntensity(); - U8 getCurrentGlossiness(); + U8 getCurrentDiffuseAlphaMode(); + U8 getCurrentAlphaMaskCutoff(); + U8 getCurrentEnvIntensity(); + U8 getCurrentGlossiness(); F32 getCurrentBumpyRot(); F32 getCurrentBumpyScaleU(); F32 getCurrentBumpyScaleV(); @@ -328,7 +326,7 @@ private: U32 new_alpha_mode = new_material->getDiffuseAlphaMode(); LLUUID new_normal_map_id = new_material->getNormalID(); - LLUUID new_spec_map_id = new_material->getSpecularID(); + LLUUID new_spec_map_id = new_material->getSpecularID(); if ((new_alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) && !is_alpha_face) { @@ -540,7 +538,6 @@ public: class LLSelectedTE { public: - static void getFace(class LLFace*& face_to_return, bool& identical_face); static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face); static void getTexId(LLUUID& id, bool& identical); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 1348996136..a3bbd00601 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1370,7 +1370,8 @@ void LLPanelObjectInventory::reset() LLEditMenuHandler::gEditMenuHandler = mFolders; } - LLRect scroller_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + int offset = hasBorder() ? getBorder()->getBorderWidth() << 1 : 0; + LLRect scroller_rect(0, getRect().getHeight() - offset, getRect().getWidth() - offset, 0); LLScrollContainer::Params scroll_p; scroll_p.name("task inventory scroller"); scroll_p.rect(scroller_rect); diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index a49effc342..c67be5bb28 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -160,6 +160,7 @@ void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id) 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()); + avatar_data->customer_type = result["customer_type"].asString(); avatar_data->flags = 0; @@ -1052,6 +1053,8 @@ void LLPanelProfileSecondLife::resetData() mCantEditObjectsIcon->setEnabled(false); childSetVisible("partner_layout", FALSE); + childSetVisible("badge_layout", FALSE); + childSetVisible("partner_spacer_layout", TRUE); } void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avatar_data) @@ -1259,6 +1262,59 @@ void LLPanelProfileSecondLife::fillAccountStatus(const LLAvatarData* avatar_data std::string caption_text = getString("CaptionTextAcctInfo", args); getChild<LLUICtrl>("account_info")->setValue(caption_text); + + const S32 LINDEN_EMPLOYEE_INDEX = 3; + LLDate sl_release; + sl_release.fromYMDHMS(2003, 6, 23, 0, 0, 0); + std::string customer_lower = avatar_data->customer_type; + LLStringUtil::toLower(customer_lower); + if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) + { + getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Linden"); + getChild<LLUICtrl>("badge_text")->setValue(getString("BadgeLinden")); + childSetVisible("badge_layout", TRUE); + childSetVisible("partner_spacer_layout", FALSE); + } + else if (avatar_data->born_on < sl_release) + { + getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Beta"); + getChild<LLUICtrl>("badge_text")->setValue(getString("BadgeBeta")); + childSetVisible("badge_layout", TRUE); + childSetVisible("partner_spacer_layout", FALSE); + } + else if (customer_lower == "beta_lifetime") + { + getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Beta_Lifetime"); + getChild<LLUICtrl>("badge_text")->setValue(getString("BadgeBetaLifetime")); + childSetVisible("badge_layout", TRUE); + childSetVisible("partner_spacer_layout", FALSE); + } + else if (customer_lower == "lifetime") + { + getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Lifetime"); + getChild<LLUICtrl>("badge_text")->setValue(getString("BadgeLifetime")); + childSetVisible("badge_layout", TRUE); + childSetVisible("partner_spacer_layout", FALSE); + } + else if (customer_lower == "secondlifetime_premium") + { + getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Premium_Lifetime"); + getChild<LLUICtrl>("badge_text")->setValue(getString("BadgePremiumLifetime")); + childSetVisible("badge_layout", TRUE); + childSetVisible("partner_spacer_layout", FALSE); + } + else if (customer_lower == "secondlifetime_premium_plus") + { + getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Pplus_Lifetime"); + getChild<LLUICtrl>("badge_text")->setValue(getString("BadgePremiumPlusLifetime")); + childSetVisible("badge_layout", TRUE); + childSetVisible("partner_spacer_layout", FALSE); + } + else + { + childSetVisible("badge_layout", FALSE); + childSetVisible("partner_spacer_layout", TRUE); + } } void LLPanelProfileSecondLife::fillRightsData() @@ -1413,7 +1469,7 @@ void LLPanelProfileSecondLife::updateOnlineStatus() } else { - childSetVisible("frind_layout", false); + childSetVisible("friend_layout", false); childSetVisible("online_layout", false); childSetVisible("offline_layout", false); } @@ -1421,7 +1477,7 @@ void LLPanelProfileSecondLife::updateOnlineStatus() void LLPanelProfileSecondLife::processOnlineStatus(bool is_friend, bool show_online, bool online) { - childSetVisible("frind_layout", is_friend); + childSetVisible("friend_layout", is_friend); childSetVisible("online_layout", online && show_online); childSetVisible("offline_layout", !online && show_online); } diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp index 45d0252e4f..db3a3c6de5 100644 --- a/indra/newview/llpanelprofilepicks.cpp +++ b/indra/newview/llpanelprofilepicks.cpp @@ -529,6 +529,7 @@ void LLPanelProfilePick::setAvatarId(const LLUUID& avatar_id) pick_name = parcel->getName(); pick_desc = parcel->getDesc(); snapshot_id = parcel->getSnapshotID(); + mPickDescription->setParseHTML(false); } LLViewerRegion* region = gAgent.getRegion(); diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index 062150dc56..5242c4fef9 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -557,7 +557,7 @@ void LLPanelWearing::onRemoveAttachment() { LLSelectMgr::getInstance()->deselectAll(); LLSelectMgr::getInstance()->selectObjectAndFamily(mAttachmentsMap[item->getUUID()]); - LLSelectMgr::getInstance()->sendDropAttachment(); + LLSelectMgr::getInstance()->sendDetach(); } } diff --git a/indra/newview/llscripteditor.cpp b/indra/newview/llscripteditor.cpp index 140cbbedbe..3278bd3aa9 100644 --- a/indra/newview/llscripteditor.cpp +++ b/indra/newview/llscripteditor.cpp @@ -187,7 +187,7 @@ void LLScriptEditor::drawSelectionBackground() // Draw selection even if we don't have keyboard focus for search/replace if( hasSelection() && !mLineInfoList.empty()) { - std::vector<LLRect> selection_rects = getSelctionRects(); + std::vector<LLRect> selection_rects = getSelectionRects(); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); const LLColor4& color = mReadOnly ? mReadOnlyFgColor : mFgColor; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index edd46f7423..9f9e117760 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1395,8 +1395,16 @@ bool idle_startup() } else if (regionp->capabilitiesError()) { - // Try to connect despite capabilities' error state - LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED); + LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); } else { @@ -1902,6 +1910,7 @@ bool idle_startup() LLNotificationsUtil::add("InventoryUnusable"); } + LLInventoryModelBackgroundFetch::instance().start(); gInventory.createCommonSystemCategories(); LLInventoryModelBackgroundFetch::instance().start(); diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index 34d3ed8bb1..c37c955e8d 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -41,8 +41,8 @@ #include "llurlregistry.h" -static const std::string BING_NOTRANSLATE_OPENING_TAG("<div class=\"notranslate\">"); -static const std::string BING_NOTRANSLATE_CLOSING_TAG("</div>"); +static const std::string AZURE_NOTRANSLATE_OPENING_TAG("<div translate=\"no\">"); +static const std::string AZURE_NOTRANSLATE_CLOSING_TAG("</div>"); /** * Handler of an HTTP machine translation service. @@ -80,7 +80,18 @@ public: * @param[in] key Key to verify. */ virtual std::string getKeyVerificationURL( - const std::string &key) const = 0; + const LLSD &key) const = 0; + + /** + * Check API verification response. + * + * @param[out] bool true if valid. + * @param[in] response + * @param[in] status + */ + virtual bool checkVerificationResponse( + const LLSD &response, + int status) const = 0; /** * Parse translation response. @@ -92,6 +103,7 @@ public: * @param[out] err_msg Error message (in case of error). */ virtual bool parseResponse( + const LLSD& http_response, int& status, const std::string& body, std::string& translation, @@ -105,14 +117,30 @@ public: virtual LLTranslate::EService getCurrentService() = 0; - virtual void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) = 0; + virtual void verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) = 0; virtual void translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure); virtual ~LLTranslationAPIHandler() {} - void verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc); + void verifyKeyCoro(LLTranslate::EService service, LLSD key, LLTranslate::KeyVerificationResult_fn fnc); void translateMessageCoro(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure); + + virtual void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const = 0; + virtual void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD &key) const = 0; + virtual LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url, + const std::string & msg, + const std::string& from_lang, + const std::string& to_lang) const = 0; + virtual LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url) const = 0; }; void LLTranslationAPIHandler::translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure) @@ -122,8 +150,7 @@ void LLTranslationAPIHandler::translateMessage(LanguagePair_t fromTo, std::strin } - -void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc) +void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, LLSD key, LLTranslate::KeyVerificationResult_fn fnc) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t @@ -140,8 +167,7 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std:: LLVersionInfo::instance().getPatch(), LLVersionInfo::instance().getBuild()); - httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); - httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); + initHttpHeader(httpHeaders, user_agent, key); httpOpts->setFollowRedirects(true); httpOpts->setSSLVerifyPeer(false); @@ -153,17 +179,29 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std:: return; } - LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts, httpHeaders); + std::string::size_type delim_pos = url.find("://"); + if (delim_pos == std::string::npos) + { + LL_INFOS("Translate") << "URL is missing a scheme" << LL_ENDL; + return; + } + + LLSD result = verifyAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url); LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); bool bOk = true; - if (!status) + int parseResult = status.getType(); + if (!checkVerificationResponse(httpResults, parseResult)) + { bOk = false; + } if (!fnc.empty()) - fnc(service, bOk); + { + fnc(service, bOk, parseResult); + } } void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::string msg, @@ -184,8 +222,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s LLVersionInfo::instance().getPatch(), LLVersionInfo::instance().getBuild()); - httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); - httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); + initHttpHeader(httpHeaders, user_agent); httpOpts->setSSLVerifyPeer(false); std::string url = this->getTranslateURL(fromTo.first, fromTo.second, msg); @@ -195,7 +232,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s return; } - LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders); + LLSD result = sendMessageAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url, msg, fromTo.first, fromTo.second); if (LLApp::isQuitting()) { @@ -216,7 +253,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s try { - res = this->parseResponse(parseResult, body, translation, detected_lang, err_msg); + res = this->parseResponse(httpResults, parseResult, body, translation, detected_lang, err_msg); } catch (std::out_of_range&) { @@ -242,6 +279,11 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s } else { + if (err_msg.empty() && httpResults.has("error_body")) + { + err_msg = httpResults["error_body"].asString(); + } + if (err_msg.empty()) { err_msg = LLTrans::getString("TranslationResponseParseError"); @@ -262,23 +304,44 @@ class LLGoogleTranslationHandler : public LLTranslationAPIHandler LOG_CLASS(LLGoogleTranslationHandler); public: - /*virtual*/ std::string getTranslateURL( + std::string getTranslateURL( const std::string &from_lang, const std::string &to_lang, - const std::string &text) const; - /*virtual*/ std::string getKeyVerificationURL( - const std::string &key) const; - /*virtual*/ bool parseResponse( + const std::string &text) const override; + std::string getKeyVerificationURL( + const LLSD &key) const override; + bool checkVerificationResponse( + const LLSD &response, + int status) const override; + bool parseResponse( + const LLSD& http_response, int& status, const std::string& body, std::string& translation, std::string& detected_lang, - std::string& err_msg) const; - /*virtual*/ bool isConfigured() const; - - /*virtual*/ LLTranslate::EService getCurrentService() { return LLTranslate::EService::SERVICE_GOOGLE; } - - /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc); + std::string& err_msg) const override; + bool isConfigured() const override; + + LLTranslate::EService getCurrentService() override { return LLTranslate::EService::SERVICE_GOOGLE; } + + void verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) override; + + void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override; + void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD &key) const override; + LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url, + const std::string & msg, + const std::string& from_lang, + const std::string& to_lang) const override; + + LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url) const override; private: static void parseErrorResponse( @@ -311,15 +374,24 @@ std::string LLGoogleTranslationHandler::getTranslateURL( // virtual std::string LLGoogleTranslationHandler::getKeyVerificationURL( - const std::string& key) const + const LLSD& key) const { - std::string url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=") - + key + "&target=en"; + std::string url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=") + + key.asString() +"&target=en"; return url; } +//virtual +bool LLGoogleTranslationHandler::checkVerificationResponse( + const LLSD &response, + int status) const +{ + return status == HTTP_OK; +} + // virtual bool LLGoogleTranslationHandler::parseResponse( + const LLSD& http_response, int& status, const std::string& body, std::string& translation, @@ -407,75 +479,196 @@ bool LLGoogleTranslationHandler::parseTranslation( // static std::string LLGoogleTranslationHandler::getAPIKey() { - return gSavedSettings.getString("GoogleTranslateAPIKey"); + static LLCachedControl<std::string> google_key(gSavedSettings, "GoogleTranslateAPIKey"); + return google_key; } /*virtual*/ -void LLGoogleTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) +void LLGoogleTranslationHandler::verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) { LLCoros::instance().launch("Google /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, this, LLTranslate::SERVICE_GOOGLE, key, fnc)); } +/*virtual*/ +void LLGoogleTranslationHandler::initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const +{ + headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); + headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); +} + +/*virtual*/ +void LLGoogleTranslationHandler::initHttpHeader( + LLCore::HttpHeaders::ptr_t headers, + const std::string& user_agent, + const LLSD &key) const +{ + headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); + headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); +} + +LLSD LLGoogleTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url, + const std::string & msg, + const std::string& from_lang, + const std::string& to_lang) const +{ + return adapter->getRawAndSuspend(request, url, options, headers); +} + +LLSD LLGoogleTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url) const +{ + return adapter->getAndSuspend(request, url, options, headers); +} //========================================================================= /// Microsoft Translator v2 API handler. -class LLBingTranslationHandler : public LLTranslationAPIHandler +class LLAzureTranslationHandler : public LLTranslationAPIHandler { - LOG_CLASS(LLBingTranslationHandler); + LOG_CLASS(LLAzureTranslationHandler); public: - /*virtual*/ std::string getTranslateURL( + std::string getTranslateURL( const std::string &from_lang, const std::string &to_lang, - const std::string &text) const; - /*virtual*/ std::string getKeyVerificationURL( - const std::string &key) const; - /*virtual*/ bool parseResponse( + const std::string &text) const override; + std::string getKeyVerificationURL( + const LLSD &key) const override; + bool checkVerificationResponse( + const LLSD &response, + int status) const override; + bool parseResponse( + const LLSD& http_response, int& status, const std::string& body, std::string& translation, std::string& detected_lang, - std::string& err_msg) const; - /*virtual*/ bool isConfigured() const; - - /*virtual*/ LLTranslate::EService getCurrentService() { return LLTranslate::EService::SERVICE_BING; } - - /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc); + std::string& err_msg) const override; + bool isConfigured() const override; + + LLTranslate::EService getCurrentService() override { return LLTranslate::EService::SERVICE_AZURE; } + + void verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) override; + + void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override; + void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD &key) const override; + LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url, + const std::string & msg, + const std::string& from_lang, + const std::string& to_lang) const override; + + LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url) const override; private: - static std::string getAPIKey(); + static std::string parseErrorResponse( + const std::string& body); + static LLSD getAPIKey(); static std::string getAPILanguageCode(const std::string& lang); }; //------------------------------------------------------------------------- // virtual -std::string LLBingTranslationHandler::getTranslateURL( +std::string LLAzureTranslationHandler::getTranslateURL( const std::string &from_lang, const std::string &to_lang, const std::string &text) const { - std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=") - + getAPIKey() + "&text=" + LLURI::escape(text) + "&to=" + getAPILanguageCode(to_lang); - if (!from_lang.empty()) - { - url += "&from=" + getAPILanguageCode(from_lang); - } + std::string url; + LLSD key = getAPIKey(); + if (key.isMap()) + { + std::string endpoint = key["endpoint"].asString(); + + if (*endpoint.rbegin() != '/') + { + endpoint += "/"; + } + url = endpoint + std::string("translate?api-version=3.0&to=") + + getAPILanguageCode(to_lang); + } return url; } // virtual -std::string LLBingTranslationHandler::getKeyVerificationURL( - const std::string& key) const +std::string LLAzureTranslationHandler::getKeyVerificationURL( + const LLSD& key) const { - std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=") - + key; + std::string url; + if (key.isMap()) + { + std::string endpoint = key["endpoint"].asString(); + if (*endpoint.rbegin() != '/') + { + endpoint += "/"; + } + url = endpoint + std::string("translate?api-version=3.0&to=en"); + } return url; } +//virtual +bool LLAzureTranslationHandler::checkVerificationResponse( + const LLSD &response, + int status) const +{ + if (status == HTTP_UNAUTHORIZED) + { + LL_DEBUGS("Translate") << "Key unathorised" << LL_ENDL; + return false; + } + + if (status == HTTP_NOT_FOUND) + { + LL_DEBUGS("Translate") << "Either endpoint doesn't have requested resource" << LL_ENDL; + return false; + } + + if (status != HTTP_BAD_REQUEST) + { + LL_DEBUGS("Translate") << "Unexpected error code" << LL_ENDL; + return false; + } + + if (!response.has("error_body")) + { + LL_DEBUGS("Translate") << "Unexpected response, no error returned" << LL_ENDL; + return false; + } + + // Expected: "{\"error\":{\"code\":400000,\"message\":\"One of the request inputs is not valid.\"}}" + // But for now just verify response is a valid json + + Json::Value root; + Json::Reader reader; + + if (!reader.parse(response["error_body"].asString(), root)) + { + LL_DEBUGS("Translate") << "Failed to parse error_body:" << reader.getFormatedErrorMessages() << LL_ENDL; + return false; + } + + return true; +} + // virtual -bool LLBingTranslationHandler::parseResponse( +bool LLAzureTranslationHandler::parseResponse( + const LLSD& http_response, int& status, const std::string& body, std::string& translation, @@ -484,65 +677,443 @@ bool LLBingTranslationHandler::parseResponse( { if (status != HTTP_OK) { - static const std::string MSG_BEGIN_MARKER = "Message: "; - size_t begin = body.find(MSG_BEGIN_MARKER); - if (begin != std::string::npos) - { - begin += MSG_BEGIN_MARKER.size(); - } - else - { - begin = 0; - err_msg.clear(); - } - size_t end = body.find("</p>", begin); - err_msg = body.substr(begin, end-begin); - LLStringUtil::replaceString(err_msg, "
", ""); // strip CR + if (http_response.has("error_body")) + err_msg = parseErrorResponse(http_response["error_body"].asString()); return false; } - // Sample response: <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Hola</string> - size_t begin = body.find(">"); - if (begin == std::string::npos || begin >= (body.size() - 1)) - { - begin = 0; - } - else - { - ++begin; - } + //Example: + // "[{\"detectedLanguage\":{\"language\":\"en\",\"score\":1.0},\"translations\":[{\"text\":\"Hello, what is your name?\",\"to\":\"en\"}]}]" - size_t end = body.find("</string>", begin); + Json::Value root; + Json::Reader reader; - detected_lang = ""; // unsupported by this API - translation = body.substr(begin, end-begin); - LLStringUtil::replaceString(translation, "
", ""); // strip CR - return true; + if (!reader.parse(body, root)) + { + err_msg = reader.getFormatedErrorMessages(); + return false; + } + + if (!root.isArray()) // empty response? should not happen + { + return false; + } + + // Request succeeded, extract translation from the response. + + const Json::Value& data = root[0U]; + if (!data.isObject() + || !data.isMember("detectedLanguage") + || !data.isMember("translations")) + { + return false; + } + + const Json::Value& detectedLanguage = data["detectedLanguage"]; + if (!detectedLanguage.isObject() || !detectedLanguage.isMember("language")) + { + return false; + } + detected_lang = detectedLanguage["language"].asString(); + + const Json::Value& translations = data["translations"]; + if (!translations.isArray() || translations.size() == 0) + { + return false; + } + + const Json::Value& first = translations[0U]; + if (!first.isObject() || !first.isMember("text")) + { + return false; + } + + translation = first["text"].asString(); + + return true; } // virtual -bool LLBingTranslationHandler::isConfigured() const +bool LLAzureTranslationHandler::isConfigured() const { - return !getAPIKey().empty(); + return getAPIKey().isMap(); +} + +//static +std::string LLAzureTranslationHandler::parseErrorResponse( + const std::string& body) +{ + // Expected: "{\"error\":{\"code\":400000,\"message\":\"One of the request inputs is not valid.\"}}" + // But for now just verify response is a valid json with an error + + Json::Value root; + Json::Reader reader; + + if (!reader.parse(body, root)) + { + return std::string(); + } + + if (!root.isObject() || !root.isMember("error")) + { + return std::string(); + } + + const Json::Value& error_map = root["error"]; + + if (!error_map.isObject() || !error_map.isMember("message")) + { + return std::string(); + } + + return error_map["message"].asString(); } // static -std::string LLBingTranslationHandler::getAPIKey() +LLSD LLAzureTranslationHandler::getAPIKey() { - return gSavedSettings.getString("BingTranslateAPIKey"); + static LLCachedControl<LLSD> azure_key(gSavedSettings, "AzureTranslateAPIKey"); + return azure_key; } // static -std::string LLBingTranslationHandler::getAPILanguageCode(const std::string& lang) +std::string LLAzureTranslationHandler::getAPILanguageCode(const std::string& lang) { return lang == "zh" ? "zh-CHT" : lang; // treat Chinese as Traditional Chinese } /*virtual*/ -void LLBingTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) +void LLAzureTranslationHandler::verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) +{ + LLCoros::instance().launch("Azure /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, + this, LLTranslate::SERVICE_AZURE, key, fnc)); +} +/*virtual*/ +void LLAzureTranslationHandler::initHttpHeader( + LLCore::HttpHeaders::ptr_t headers, + const std::string& user_agent) const +{ + initHttpHeader(headers, user_agent, getAPIKey()); +} + +/*virtual*/ +void LLAzureTranslationHandler::initHttpHeader( + LLCore::HttpHeaders::ptr_t headers, + const std::string& user_agent, + const LLSD &key) const +{ + headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_JSON); + headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); + + if (key.has("id")) + { + // Token based autorization + headers->append("Ocp-Apim-Subscription-Key", key["id"].asString()); + } + if (key.has("region")) + { + // ex: "westeurope" + headers->append("Ocp-Apim-Subscription-Region", key["region"].asString()); + } +} + +LLSD LLAzureTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url, + const std::string & msg, + const std::string& from_lang, + const std::string& to_lang) const +{ + LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray); + LLCore::BufferArrayStream outs(rawbody.get()); + outs << "[{\"text\":\""; + outs << msg; + outs << "\"}]"; + + return adapter->postRawAndSuspend(request, url, rawbody, options, headers); +} + +LLSD LLAzureTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url) const +{ + LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray); + LLCore::BufferArrayStream outs(rawbody.get()); + outs << "[{\"intentionally_invalid_400\"}]"; + + return adapter->postRawAndSuspend(request, url, rawbody, options, headers); +} + +//========================================================================= +/// DeepL Translator API handler. +class LLDeepLTranslationHandler: public LLTranslationAPIHandler +{ + LOG_CLASS(LLDeepLTranslationHandler); + +public: + std::string getTranslateURL( + const std::string& from_lang, + const std::string& to_lang, + const std::string& text) const override; + std::string getKeyVerificationURL( + const LLSD& key) const override; + bool checkVerificationResponse( + const LLSD& response, + int status) const override; + bool parseResponse( + const LLSD& http_response, + int& status, + const std::string& body, + std::string& translation, + std::string& detected_lang, + std::string& err_msg) const override; + bool isConfigured() const override; + + LLTranslate::EService getCurrentService() override + { + return LLTranslate::EService::SERVICE_DEEPL; + } + + void verifyKey(const LLSD& key, LLTranslate::KeyVerificationResult_fn fnc) override; + + void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override; + void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD& key) const override; + LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string& url, + const std::string& msg, + const std::string& from_lang, + const std::string& to_lang) const override; + + LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string& url) const override; +private: + static std::string parseErrorResponse( + const std::string& body); + static LLSD getAPIKey(); + static std::string getAPILanguageCode(const std::string& lang); +}; + +//------------------------------------------------------------------------- +// virtual +std::string LLDeepLTranslationHandler::getTranslateURL( + const std::string& from_lang, + const std::string& to_lang, + const std::string& text) const +{ + std::string url; + LLSD key = getAPIKey(); + if (key.isMap()) + { + url = key["domain"].asString(); + + if (*url.rbegin() != '/') + { + url += "/"; + } + url += std::string("v2/translate"); + } + return url; +} + + +// virtual +std::string LLDeepLTranslationHandler::getKeyVerificationURL( + const LLSD& key) const +{ + std::string url; + if (key.isMap()) + { + url = key["domain"].asString(); + + if (*url.rbegin() != '/') + { + url += "/"; + } + url += std::string("v2/translate"); + } + return url; +} + +//virtual +bool LLDeepLTranslationHandler::checkVerificationResponse( + const LLSD& response, + int status) const +{ + // Might need to parse body to make sure we got + // a valid response and not a message + return status == HTTP_OK; +} + +// virtual +bool LLDeepLTranslationHandler::parseResponse( + const LLSD& http_response, + int& status, + const std::string& body, + std::string& translation, + std::string& detected_lang, + std::string& err_msg) const +{ + if (status != HTTP_OK) + { + if (http_response.has("error_body")) + err_msg = parseErrorResponse(http_response["error_body"].asString()); + return false; + } + + //Example: + // "{\"translations\":[{\"detected_source_language\":\"EN\",\"text\":\"test\"}]}" + + Json::Value root; + Json::Reader reader; + + if (!reader.parse(body, root)) + { + err_msg = reader.getFormatedErrorMessages(); + return false; + } + + if (!root.isObject() + || !root.isMember("translations")) // empty response? should not happen + { + return false; + } + + // Request succeeded, extract translation from the response. + const Json::Value& translations = root["translations"]; + if (!translations.isArray() || translations.size() == 0) + { + return false; + } + + const Json::Value& data= translations[0U]; + if (!data.isObject() + || !data.isMember("detected_source_language") + || !data.isMember("text")) + { + return false; + } + + detected_lang = data["detected_source_language"].asString(); + LLStringUtil::toLower(detected_lang); + translation = data["text"].asString(); + + return true; +} + +// virtual +bool LLDeepLTranslationHandler::isConfigured() const +{ + return getAPIKey().isMap(); +} + +//static +std::string LLDeepLTranslationHandler::parseErrorResponse( + const std::string& body) +{ + // Example: "{\"message\":\"One of the request inputs is not valid.\"}" + + Json::Value root; + Json::Reader reader; + + if (!reader.parse(body, root)) + { + return std::string(); + } + + if (!root.isObject() || !root.isMember("message")) + { + return std::string(); + } + + return root["message"].asString(); +} + +// static +LLSD LLDeepLTranslationHandler::getAPIKey() +{ + static LLCachedControl<LLSD> deepl_key(gSavedSettings, "DeepLTranslateAPIKey"); + return deepl_key; +} + +// static +std::string LLDeepLTranslationHandler::getAPILanguageCode(const std::string& lang) +{ + return lang == "zh" ? "zh-CHT" : lang; // treat Chinese as Traditional Chinese +} + +/*virtual*/ +void LLDeepLTranslationHandler::verifyKey(const LLSD& key, LLTranslate::KeyVerificationResult_fn fnc) +{ + LLCoros::instance().launch("DeepL /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, + this, LLTranslate::SERVICE_DEEPL, key, fnc)); +} +/*virtual*/ +void LLDeepLTranslationHandler::initHttpHeader( + LLCore::HttpHeaders::ptr_t headers, + const std::string& user_agent) const { - LLCoros::instance().launch("Bing /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, - this, LLTranslate::SERVICE_BING, key, fnc)); + initHttpHeader(headers, user_agent, getAPIKey()); +} + +/*virtual*/ +void LLDeepLTranslationHandler::initHttpHeader( + LLCore::HttpHeaders::ptr_t headers, + const std::string& user_agent, + const LLSD& key) const +{ + headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/x-www-form-urlencoded"); + headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); + + if (key.has("id")) + { + std::string authkey = "DeepL-Auth-Key " + key["id"].asString(); + headers->append(HTTP_OUT_HEADER_AUTHORIZATION, authkey); + } +} + +LLSD LLDeepLTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string& url, + const std::string& msg, + const std::string& from_lang, + const std::string& to_lang) const +{ + LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray); + LLCore::BufferArrayStream outs(rawbody.get()); + outs << "text="; + std::string escaped_string = LLURI::escape(msg); + outs << escaped_string; + outs << "&target_lang="; + std::string lang = to_lang; + LLStringUtil::toUpper(lang); + outs << lang; + + return adapter->postRawAndSuspend(request, url, rawbody, options, headers); +} + +LLSD LLDeepLTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string& url) const +{ + LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray); + LLCore::BufferArrayStream outs(rawbody.get()); + outs << "text=&target_lang=EN"; + + return adapter->postRawAndSuspend(request, url, rawbody, options, headers); } //========================================================================= @@ -569,58 +1140,78 @@ void LLTranslate::translateMessage(const std::string &from_lang, const std::stri std::string LLTranslate::addNoTranslateTags(std::string mesg) { - if (getPreferredHandler().getCurrentService() != SERVICE_BING) + if (getPreferredHandler().getCurrentService() == SERVICE_GOOGLE) + { + return mesg; + } + + if (getPreferredHandler().getCurrentService() == SERVICE_DEEPL) { return mesg; } - std::string upd_msg(mesg); - LLUrlMatch match; - S32 dif = 0; - //surround all links (including SLURLs) with 'no-translate' tags to prevent unnecessary translation - while (LLUrlRegistry::instance().findUrl(mesg, match)) + if (getPreferredHandler().getCurrentService() == SERVICE_AZURE) { - upd_msg.insert(dif + match.getStart(), BING_NOTRANSLATE_OPENING_TAG); - upd_msg.insert(dif + BING_NOTRANSLATE_OPENING_TAG.size() + match.getEnd() + 1, BING_NOTRANSLATE_CLOSING_TAG); - mesg.erase(match.getStart(), match.getEnd() - match.getStart()); - dif += match.getEnd() - match.getStart() + BING_NOTRANSLATE_OPENING_TAG.size() + BING_NOTRANSLATE_CLOSING_TAG.size(); + // https://learn.microsoft.com/en-us/azure/cognitive-services/translator/prevent-translation + std::string upd_msg(mesg); + LLUrlMatch match; + S32 dif = 0; + //surround all links (including SLURLs) with 'no-translate' tags to prevent unnecessary translation + while (LLUrlRegistry::instance().findUrl(mesg, match)) + { + upd_msg.insert(dif + match.getStart(), AZURE_NOTRANSLATE_OPENING_TAG); + upd_msg.insert(dif + AZURE_NOTRANSLATE_OPENING_TAG.size() + match.getEnd() + 1, AZURE_NOTRANSLATE_CLOSING_TAG); + mesg.erase(match.getStart(), match.getEnd() - match.getStart()); + dif += match.getEnd() - match.getStart() + AZURE_NOTRANSLATE_OPENING_TAG.size() + AZURE_NOTRANSLATE_CLOSING_TAG.size(); + } + return upd_msg; } - return upd_msg; + return mesg; } std::string LLTranslate::removeNoTranslateTags(std::string mesg) { - if (getPreferredHandler().getCurrentService() != SERVICE_BING) + if (getPreferredHandler().getCurrentService() == SERVICE_GOOGLE) { return mesg; } - std::string upd_msg(mesg); - LLUrlMatch match; - S32 opening_tag_size = BING_NOTRANSLATE_OPENING_TAG.size(); - S32 closing_tag_size = BING_NOTRANSLATE_CLOSING_TAG.size(); - S32 dif = 0; - //remove 'no-translate' tags we added to the links before - while (LLUrlRegistry::instance().findUrl(mesg, match)) + if (getPreferredHandler().getCurrentService() == SERVICE_DEEPL) { - if (upd_msg.substr(dif + match.getStart() - opening_tag_size, opening_tag_size) == BING_NOTRANSLATE_OPENING_TAG) - { - upd_msg.erase(dif + match.getStart() - opening_tag_size, opening_tag_size); - dif -= opening_tag_size; + return mesg; + } - if (upd_msg.substr(dif + match.getEnd() + 1, closing_tag_size) == BING_NOTRANSLATE_CLOSING_TAG) + if (getPreferredHandler().getCurrentService() == SERVICE_AZURE) + { + std::string upd_msg(mesg); + LLUrlMatch match; + S32 opening_tag_size = AZURE_NOTRANSLATE_OPENING_TAG.size(); + S32 closing_tag_size = AZURE_NOTRANSLATE_CLOSING_TAG.size(); + S32 dif = 0; + //remove 'no-translate' tags we added to the links before + while (LLUrlRegistry::instance().findUrl(mesg, match)) + { + if (upd_msg.substr(dif + match.getStart() - opening_tag_size, opening_tag_size) == AZURE_NOTRANSLATE_OPENING_TAG) { - upd_msg.replace(dif + match.getEnd() + 1, closing_tag_size, " "); - dif -= closing_tag_size - 1; + upd_msg.erase(dif + match.getStart() - opening_tag_size, opening_tag_size); + dif -= opening_tag_size; + + if (upd_msg.substr(dif + match.getEnd() + 1, closing_tag_size) == AZURE_NOTRANSLATE_CLOSING_TAG) + { + upd_msg.replace(dif + match.getEnd() + 1, closing_tag_size, " "); + dif -= closing_tag_size - 1; + } } + mesg.erase(match.getStart(), match.getUrl().size()); + dif += match.getUrl().size(); } - mesg.erase(match.getStart(), match.getUrl().size()); - dif += match.getUrl().size(); + return upd_msg; } - return upd_msg; + + return mesg; } /*static*/ -void LLTranslate::verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc) +void LLTranslate::verifyKey(EService service, const LLSD &key, KeyVerificationResult_fn fnc) { LLTranslationAPIHandler& handler = getHandler(service); @@ -686,13 +1277,21 @@ LLSD LLTranslate::asLLSD() const // static LLTranslationAPIHandler& LLTranslate::getPreferredHandler() { - EService service = SERVICE_BING; + EService service = SERVICE_AZURE; std::string service_str = gSavedSettings.getString("TranslationService"); if (service_str == "google") { service = SERVICE_GOOGLE; } + if (service_str == "azure") + { + service = SERVICE_AZURE; + } + if (service_str == "deepl") + { + service = SERVICE_DEEPL; + } return getHandler(service); } @@ -701,12 +1300,19 @@ LLTranslationAPIHandler& LLTranslate::getPreferredHandler() LLTranslationAPIHandler& LLTranslate::getHandler(EService service) { static LLGoogleTranslationHandler google; - static LLBingTranslationHandler bing; + static LLAzureTranslationHandler azure; + static LLDeepLTranslationHandler deepl; - if (service == SERVICE_GOOGLE) - { - return google; - } + switch (service) + { + case SERVICE_AZURE: + return azure; + case SERVICE_GOOGLE: + return google; + case SERVICE_DEEPL: + return deepl; + } + + return azure; - return bing; } diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index 58707e2d36..4a5d80737c 100644 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -59,11 +59,12 @@ class LLTranslate: public LLSingleton<LLTranslate> public : typedef enum e_service { - SERVICE_BING, + SERVICE_AZURE, SERVICE_GOOGLE, + SERVICE_DEEPL, } EService; - typedef boost::function<void(EService, bool)> KeyVerificationResult_fn; + typedef boost::function<void(EService, bool, S32)> KeyVerificationResult_fn; typedef boost::function<void(std::string , std::string )> TranslationSuccess_fn; typedef boost::function<void(int, std::string)> TranslationFailure_fn; @@ -78,12 +79,12 @@ public : static void translateMessage(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, TranslationSuccess_fn success, TranslationFailure_fn failure); /** - * Verify given API key of a translation service. - * - * @param receiver Object to pass verification result to. - * @param key Key to verify. - */ - static void verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc); + * Verify given API key of a translation service. + * + * @param receiver Object to pass verification result to. + * @param key Key to verify. + */ + static void verifyKey(EService service, const LLSD &key, KeyVerificationResult_fn fnc); /** * @return translation target language diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index 6bab2c2100..226e0a9a56 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -1597,7 +1597,8 @@ bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down) { - BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down); + bool is_toolmgr_action = false; + BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down, is_toolmgr_action); if (clicktype != CLICK_NONE) { @@ -1616,7 +1617,7 @@ BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, // If the first LMB click is handled by the menu, skip the following double click static bool skip_double_click = false; - if (clicktype == CLICK_LEFT && down ) + if (clicktype == CLICK_LEFT && down && !is_toolmgr_action) { skip_double_click = handled; } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 0df29c79ac..5b32ccf9e2 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -276,10 +276,6 @@ void handle_object_owner_permissive(void*); void handle_object_lock(void*); void handle_object_asset_ids(void*); void force_take_copy(void*); -#ifdef _CORY_TESTING -void force_export_copy(void*); -void force_import_geometry(void*); -#endif void handle_force_parcel_owner_to_me(void*); void handle_force_parcel_to_content(void*); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index ac6b8b2aa7..17e89e1850 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -355,9 +355,6 @@ void LLMediaFilePicker::notify(const std::vector<std::string>& filenames) static std::string SOUND_EXTENSIONS = "wav"; static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png"; static std::string ANIM_EXTENSIONS = "bvh anim"; -#ifdef _CORY_TESTING -static std::string GEOMETRY_EXTENSIONS = "slg"; -#endif static std::string XML_EXTENSIONS = "xml"; static std::string SLOBJECT_EXTENSIONS = "slobject"; #endif @@ -379,10 +376,6 @@ std::string build_extensions_string(LLFilePicker::ELoadFilter filter) return SLOBJECT_EXTENSIONS; case LLFilePicker::FFLOAD_MODEL: return MODEL_EXTENSIONS; -#ifdef _CORY_TESTING - case LLFilePicker::FFLOAD_GEOMETRY: - return GEOMETRY_EXTENSIONS; -#endif case LLFilePicker::FFLOAD_XML: return XML_EXTENSIONS; case LLFilePicker::FFLOAD_ALL: diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 519166af63..1607296194 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -124,7 +124,7 @@ SimMeasurement<> SIM_TIME_DILATION("simtimedilation", "Simulator time scale", SIM_MAIN_AGENTS("simmainagents", "Number of avatars in current region", LL_SIM_STAT_NUMAGENTMAIN), SIM_CHILD_AGENTS("simchildagents", "Number of avatars in neighboring regions", LL_SIM_STAT_NUMAGENTCHILD), SIM_OBJECTS("simobjects", "", LL_SIM_STAT_NUMTASKS), - SIM_ACTIVE_OBJECTS("simactiveobjects", "Number of scripted and/or mocing objects", LL_SIM_STAT_NUMTASKSACTIVE), + SIM_ACTIVE_OBJECTS("simactiveobjects", "Number of scripted and/or moving objects", LL_SIM_STAT_NUMTASKSACTIVE), SIM_ACTIVE_SCRIPTS("simactivescripts", "Number of scripted objects", LL_SIM_STAT_NUMSCRIPTSACTIVE), SIM_IN_PACKETS_PER_SEC("siminpps", "", LL_SIM_STAT_INPPS), SIM_OUT_PACKETS_PER_SEC("simoutpps", "", LL_SIM_STAT_OUTPPS), diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 8a11c5cf8f..c458c75a40 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -402,9 +402,6 @@ void LLViewerTextureManager::init() LLViewerFetchedTexture::sDefaultImagep->dontDiscard(); LLViewerFetchedTexture::sDefaultImagep->setCategory(LLGLTexture::OTHER); - LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); - LLViewerFetchedTexture::sSmokeImagep->setNoDelete(); - image_raw = new LLImageRaw(32,32,3); data = image_raw->getData(); diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index e58c58194c..60c7fb6b8c 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -228,6 +228,8 @@ void LLViewerTextureList::doPrefetchImages() LLViewerTextureManager::getFetchedTexture(IMG_SHOT); LLViewerTextureManager::getFetchedTexture(IMG_SMOKE_POOF); + LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); + LLViewerFetchedTexture::sSmokeImagep->setNoDelete(); LLStandardBumpmap::addstandard(); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index b9fcc25310..e8fd74b37b 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1050,7 +1050,7 @@ void LLViewerWindow::handlePieMenu(S32 x, S32 y, MASK mask) } } -BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down) +BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down, bool& is_toolmgr_action) { const char* buttonname = ""; const char* buttonstatestr = ""; @@ -1199,6 +1199,7 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) ) { LLViewerEventRecorder::instance().clear_xui(); + is_toolmgr_action = true; return TRUE; } diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 1927e01ddb..92905ef21a 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -179,7 +179,7 @@ public: void reshapeStatusBarContainer(); - BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down); + BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down, bool &is_toolmgr_action); // // LLWindowCallback interface implementation diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index c73f96da2d..3725510b6a 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -276,13 +276,13 @@ static void killGateway() /////////////////////////////////////////////////////////////////////////////////////////////// bool LLVivoxVoiceClient::sShuttingDown = false; +bool LLVivoxVoiceClient::sConnected = false; +LLPumpIO *LLVivoxVoiceClient::sPump = nullptr; LLVivoxVoiceClient::LLVivoxVoiceClient() : mSessionTerminateRequested(false), mRelogRequested(false), - mConnected(false), mTerminateDaemon(false), - mPump(NULL), mSpatialJoiningNum(0), mTuningMode(false), @@ -350,7 +350,11 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mIsProcessingChannels(false), mIsCoroutineActive(false), mVivoxPump("vivoxClientPump") -{ +{ + sShuttingDown = false; + sConnected = false; + sPump = nullptr; + mSpeakerVolume = scale_speaker_volume(0); mVoiceVersion.serverVersion = ""; @@ -392,7 +396,7 @@ LLVivoxVoiceClient::~LLVivoxVoiceClient() void LLVivoxVoiceClient::init(LLPumpIO *pump) { // constructor will set up LLVoiceClient::getInstance() - mPump = pump; + sPump = pump; // LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro", // boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance())); @@ -413,10 +417,10 @@ void LLVivoxVoiceClient::terminate() logoutOfVivox(false); } - if(mConnected) + if(sConnected) { breakVoiceConnection(false); - mConnected = false; + sConnected = false; } else { @@ -425,7 +429,7 @@ void LLVivoxVoiceClient::terminate() } sShuttingDown = true; - mPump = NULL; + sPump = NULL; } //--------------------------------------------------- @@ -471,7 +475,7 @@ bool LLVivoxVoiceClient::writeString(const std::string &str) bool result = false; LL_DEBUGS("LowVoice") << "sending:\n" << str << LL_ENDL; - if(mConnected) + if(sConnected) { apr_status_t err; apr_size_t size = (apr_size_t)str.size(); @@ -1051,7 +1055,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() int retryCount(0); LLVoiceVivoxStats::getInstance()->reset(); - while (!mConnected && !sShuttingDown && retryCount++ <= DAEMON_CONNECT_RETRY_MAX) + while (!sConnected && !sShuttingDown && retryCount++ <= DAEMON_CONNECT_RETRY_MAX) { LLVoiceVivoxStats::getInstance()->connectionAttemptStart(); LL_DEBUGS("Voice") << "Attempting to connect to vivox daemon: " << mDaemonHost << LL_ENDL; @@ -1061,23 +1065,23 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); } - mConnected = mSocket->blockingConnect(mDaemonHost); - LLVoiceVivoxStats::getInstance()->connectionAttemptEnd(mConnected); - if (!mConnected) + sConnected = mSocket->blockingConnect(mDaemonHost); + LLVoiceVivoxStats::getInstance()->connectionAttemptEnd(sConnected); + if (!sConnected) { llcoro::suspendUntilTimeout(DAEMON_CONNECT_THROTTLE_SECONDS); } } //--------------------------------------------------------------------- - if (sShuttingDown && !mConnected) + if (sShuttingDown && !sConnected) { return false; } llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS); - while (!mPump && !sShuttingDown) + while (!sPump && !sShuttingDown) { // Can't use the pump until we have it available. llcoro::suspend(); } @@ -1099,7 +1103,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() readChain.push_back(LLIOPipe::ptr_t(new LLVivoxProtocolParser())); - mPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS); + sPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS); //--------------------------------------------------------------------- @@ -1321,9 +1325,9 @@ bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait) // the message, yet we need to receive "connector shutdown response". // Either wait a bit and emulate it or check gMessageSystem for specific message _sleep(1000); - if (mConnected) + if (sConnected) { - mConnected = false; + sConnected = false; LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false))); mVivoxPump.post(vivoxevent); } @@ -1335,7 +1339,7 @@ bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait) LL_DEBUGS("Voice") << "closing SLVoice socket" << LL_ENDL; closeSocket(); // Need to do this now -- bad things happen if the destructor does it later. cleanUp(); - mConnected = false; + sConnected = false; return retval; } @@ -2516,7 +2520,7 @@ bool LLVivoxVoiceClient::performMicTuning() void LLVivoxVoiceClient::closeSocket(void) { mSocket.reset(); - mConnected = false; + sConnected = false; mConnectorEstablished = false; mAccountLoggedIn = false; } @@ -3017,7 +3021,7 @@ bool LLVivoxVoiceClient::deviceSettingsAvailable() { bool result = true; - if(!mConnected) + if(!sConnected) result = false; if(mRenderDevices.empty()) @@ -3816,7 +3820,7 @@ void LLVivoxVoiceClient::connectorShutdownResponse(int statusCode, std::string & // Should this ever fail? do we care if it does? } - mConnected = false; + sConnected = false; mShutdownComplete = true; LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false))); @@ -7389,7 +7393,7 @@ LLIOPipe::EStatus LLVivoxProtocolParser::process_impl( LL_DEBUGS("VivoxProtocolParser") << "at end, mInput is: " << mInput << LL_ENDL; - if(!LLVivoxVoiceClient::getInstance()->mConnected) + if(!LLVivoxVoiceClient::sConnected) { // If voice has been disabled, we just want to close the socket. This does so. LL_INFOS("Voice") << "returning STATUS_STOP" << LL_ENDL; diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 0a785401c1..e3ab99c675 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -666,12 +666,10 @@ private: LLHost mDaemonHost; LLSocket::ptr_t mSocket; - bool mConnected; // We should kill the voice daemon in case of connection alert bool mTerminateDaemon; - LLPumpIO *mPump; friend class LLVivoxProtocolParser; std::string mAccountName; @@ -916,7 +914,10 @@ private: bool mIsProcessingChannels; bool mIsCoroutineActive; - static bool sShuttingDown; // corutines can last longer than vivox so we need a static variable as a shutdown flag + // This variables can last longer than vivox in coroutines so we need them as static + static bool sShuttingDown; + static bool sConnected; + static LLPumpIO* sPump; LLEventMailDrop mVivoxPump; }; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 51925b4129..bf9a4dfa12 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5296,13 +5296,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, if (mat) { + BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) || (facep->getTextureEntry()->getColor().mV[3] < 0.999f) ? TRUE : FALSE; if (type == LLRenderPass::PASS_ALPHA) { - shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND); + shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND, is_alpha); } else { - shader_mask = mat->getShaderMask(); + shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_DEFAULT, is_alpha); } } @@ -5857,15 +5858,20 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } else { - if (te->getColor().mV[3] > 0.f || te->getGlow() > 0.f) - { //only treat as alpha in the pipeline if < 100% transparent - drawablep->setState(LLDrawable::HAS_ALPHA); - add_face(sAlphaFaces, alpha_count, facep); - } - else if (LLDrawPoolAlpha::sShowDebugAlpha) - { - add_face(sAlphaFaces, alpha_count, facep); - } + if (te->getColor().mV[3] > 0.f || te->getGlow() > 0.f) + { //only treat as alpha in the pipeline if < 100% transparent + drawablep->setState(LLDrawable::HAS_ALPHA); + add_face(sAlphaFaces, alpha_count, facep); + } + else if (LLDrawPoolAlpha::sShowDebugAlpha || + (gPipeline.sRenderHighlight && !drawablep->getParent() && + //only root objects are highlighted with red color in this case + drawablep->getVObj() && drawablep->getVObj()->flagScripted() && + (LLPipeline::getRenderScriptedBeacons() || + (LLPipeline::getRenderScriptedTouchBeacons() && drawablep->getVObj()->flagHandleTouch())))) + { //draw the transparent face for debugging purposes using a custom texture + add_face(sAlphaFaces, alpha_count, facep); + } } } else @@ -6692,7 +6698,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace LLRenderPass::PASS_NORMSPEC_EMISSIVE, }; - U32 mask = mat->getShaderMask(); + U32 mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_DEFAULT, is_alpha); llassert(mask < sizeof(pass)/sizeof(U32)); diff --git a/indra/newview/skins/default/textures/icons/profile_badge_beta.png b/indra/newview/skins/default/textures/icons/profile_badge_beta.png Binary files differnew file mode 100644 index 0000000000..7c8a723c47 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/profile_badge_beta.png diff --git a/indra/newview/skins/default/textures/icons/profile_badge_beta_lifetime.png b/indra/newview/skins/default/textures/icons/profile_badge_beta_lifetime.png Binary files differnew file mode 100644 index 0000000000..7c38e9e2ae --- /dev/null +++ b/indra/newview/skins/default/textures/icons/profile_badge_beta_lifetime.png diff --git a/indra/newview/skins/default/textures/icons/profile_badge_lifetime.png b/indra/newview/skins/default/textures/icons/profile_badge_lifetime.png Binary files differnew file mode 100644 index 0000000000..475edd080e --- /dev/null +++ b/indra/newview/skins/default/textures/icons/profile_badge_lifetime.png diff --git a/indra/newview/skins/default/textures/icons/profile_badge_linden.png b/indra/newview/skins/default/textures/icons/profile_badge_linden.png Binary files differnew file mode 100644 index 0000000000..1b6ac03e86 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/profile_badge_linden.png diff --git a/indra/newview/skins/default/textures/icons/profile_badge_pplus_lifetime.png b/indra/newview/skins/default/textures/icons/profile_badge_pplus_lifetime.png Binary files differnew file mode 100644 index 0000000000..4286995202 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/profile_badge_pplus_lifetime.png diff --git a/indra/newview/skins/default/textures/icons/profile_badge_premium_lifetime.png b/indra/newview/skins/default/textures/icons/profile_badge_premium_lifetime.png Binary files differnew file mode 100644 index 0000000000..47e93c4fac --- /dev/null +++ b/indra/newview/skins/default/textures/icons/profile_badge_premium_lifetime.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index d8a2a6324c..aa99fe38cd 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -523,7 +523,13 @@ with the same filename but different name <texture name="Play_Off" file_name="icons/Play_Off.png" preload="false" /> <texture name="Play_Over" file_name="icons/Play_Over.png" preload="false" /> <texture name="Play_Press" file_name="icons/Play_Press.png" preload="false" /> - + + <texture name="Profile_Badge_Beta" file_name="icons/profile_badge_beta.png" preload="true"/> + <texture name="Profile_Badge_Beta_Lifetime" file_name="icons/profile_badge_beta_lifetime.png" preload="true"/> + <texture name="Profile_Badge_Lifetime" file_name="icons/profile_badge_lifetime.png" preload="true"/> + <texture name="Profile_Badge_Linden" file_name="icons/profile_badge_linden.png" preload="true"/> + <texture name="Profile_Badge_Pplus_Lifetime" file_name="icons/profile_badge_pplus_lifetime.png" preload="true"/> + <texture name="Profile_Badge_Premium_Lifetime" file_name="icons/profile_badge_premium_lifetime.png" preload="true"/> <texture name="Profile_Group_Visibility_Off" file_name="icons/profile_group_visibility_eye_off.png" preload="true"/> <texture name="Profile_Group_Visibility_Off_Pressed" file_name="icons/profile_group_visibility_eye_off_pressed.png" preload="true"/> <texture name="Profile_Group_Visibility_On" file_name="icons/profile_group_visibility_eye_on.png" preload="true"/> diff --git a/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml index 37efbe654e..b757f4eab8 100644 --- a/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml @@ -414,7 +414,7 @@ name="frame_stats" label="Frame breakdown" show_label="true"> - <stat_bar name="packet_loss" + <stat_bar name="scenery_frame_pct" label="Scenery" orientation="horizontal" unit_label=" %" @@ -422,7 +422,7 @@ bar_max="100" tick_spacing="0.5" show_bar="false"/> - <stat_bar name="packet_loss" + <stat_bar name="avatar_frame_pct" label="Avatar" orientation="horizontal" unit_label=" %" @@ -430,7 +430,7 @@ bar_max="100" tick_spacing="0.5" show_bar="false"/> - <stat_bar name="packet_loss" + <stat_bar name="ui_frame_pct" label="UI" orientation="horizontal" unit_label=" %" @@ -438,7 +438,7 @@ bar_max="100" tick_spacing="0.5" show_bar="false"/> - <stat_bar name="packet_loss" + <stat_bar name="huds_frame_pct" label="HUDs" orientation="horizontal" unit_label=" %" @@ -446,7 +446,7 @@ bar_max="100" tick_spacing="0.5" show_bar="false"/> - <stat_bar name="packet_loss" + <stat_bar name="swap_frame_pct" label="Swap" orientation="horizontal" unit_label=" %" @@ -454,7 +454,7 @@ bar_max="100" tick_spacing="0.5" show_bar="false"/> - <stat_bar name="packet_loss" + <stat_bar name="idle_frame_pct" label="Tasks" orientation="horizontal" unit_label=" %" diff --git a/indra/newview/skins/default/xui/en/floater_translation_settings.xml b/indra/newview/skins/default/xui/en/floater_translation_settings.xml index a212ce7889..3f3331b468 100644 --- a/indra/newview/skins/default/xui/en/floater_translation_settings.xml +++ b/indra/newview/skins/default/xui/en/floater_translation_settings.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater legacy_header_height="18" - height="310" + height="470" layout="topleft" name="floater_translation_settings" help_topic="translation_settings" @@ -9,11 +9,13 @@ title="CHAT TRANSLATION SETTINGS" width="485"> - <string name="bing_api_key_not_verified">Bing appID not verified. Please try again.</string> - <string name="google_api_key_not_verified">Google API key not verified. Please try again.</string> + <string name="azure_api_key_not_verified">Azure service identifier not verified. Status: [STATUS]. Please check your settings and try again.</string> + <string name="google_api_key_not_verified">Google API key not verified. Status: [STATUS]. Please check your key and try again.</string> + <string name="deepl_api_key_not_verified">DeepL Auth Key key not verified. Status: [STATUS]. Please check your key and try again.</string> - <string name="bing_api_key_verified">Bing appID verified.</string> + <string name="azure_api_key_verified">Azure service identifier verified.</string> <string name="google_api_key_verified">Google API key verified.</string> + <string name="deepl_api_key_verified">DeepL API key verified.</string> <check_box height="16" @@ -128,25 +130,86 @@ <radio_group follows="top|left" - height="80" + height="260" layout="topleft" left_delta="10" name="translation_service_rg" top_pad="20" width="320"> <radio_item - initial_value="bing" - label="Bing Translator" + initial_value="azure" + label="Azure Translator" layout="topleft" - name="bing" /> + name="azure" /> <radio_item initial_value="google" label="Google Translate" layout="topleft" name="google" - top_pad="55" /> + top_pad="115" /> + <radio_item + initial_value="deepl" + label="DeepL Translator" + layout="topleft" + name="deepl" + top_pad="61" /> </radio_group> + <text + follows="top|right" + height="20" + layout="topleft" + left="185" + length="1" + name="google_links_text" + top_pad="-262" + type="string" + width="100"> + [https://learn.microsoft.com/en-us/azure/cognitive-services/translator/create-translator-resource Setup] + </text> + + <text + type="string" + length="1" + follows="top|right" + height="20" + layout="topleft" + left="70" + name="azure_api_endoint_label" + top_pad="8" + width="85"> + Endpoint: + </text> + + <combo_box + allow_text_entry="true" + follows="left|top" + name="azure_api_endpoint_combo" + height="23" + left_pad="10" + right="-10" + top_delta="-4" + max_chars="512" + value="https://api.cognitive.microsofttranslator.com" + combo_button.scale_image="true"> + <combo_box.item + label="https://api.cognitive.microsofttranslator.com" + name="global" + value="https://api.cognitive.microsofttranslator.com" /> + <combo_box.item + label="https://api-apc.cognitive.microsofttranslator.com" + name="api-apc" + value="https://api-apc.cognitive.microsofttranslator.com" /> + <combo_box.item + label="https://api-eur.cognitive.microsofttranslator.com" + name="api-eur" + value="https://api-eur.cognitive.microsofttranslator.com" /> + <combo_box.item + label="https://api-nam.cognitive.microsofttranslator.com" + name="api-nam" + value="https://api-nam.cognitive.microsofttranslator.com" /> + </combo_box> + <text type="string" length="1" @@ -154,30 +217,52 @@ height="20" layout="topleft" left="70" - name="bing_api_key_label" - top_pad="-55" + name="azure_api_key_label" + top_pad="10" width="85"> - Bing [http://www.bing.com/developers/createapp.aspx AppID]: + Azure Key: </text> <line_editor - default_text="Enter Bing AppID and click "Verify"" + default_text="Enter Translator Key and click "Verify"" follows="top|left" height="20" layout="topleft" left_pad="10" max_length_chars="50" top_delta="-4" - name="bing_api_key" + name="azure_api_key" width="210" /> - <button - follows="left|top" - height="23" - label="Verify" - layout="topleft" - left_pad="10" - name="verify_bing_api_key_btn" - top_delta="-2" - width="90" /> + <text + type="string" + length="1" + follows="top|right" + height="20" + layout="topleft" + left="70" + name="azure_api_region_label" + top_pad="11" + width="85"> + Region: + </text> + <line_editor + default_text="Can be left empty for global services" + follows="top|left" + height="20" + layout="topleft" + left_pad="10" + max_length_chars="50" + top_delta="-4" + name="azure_api_region" + width="210" /> + <button + follows="left|top" + height="23" + label="Verify" + layout="topleft" + left_pad="10" + name="verify_azure_api_key_btn" + top_delta="-2" + width="90" /> <text follows="top|right" @@ -186,7 +271,7 @@ left="70" length="1" name="google_api_key_label" - top_pad="50" + top_pad="53" type="string" width="85"> Google [http://code.google.com/apis/language/translate/v2/getting_started.html#auth API key]: @@ -209,7 +294,7 @@ left_pad="10" name="verify_google_api_key_btn" top_delta="-2" - width="90" /> + width="90" /> <text follows="top|right" @@ -224,6 +309,87 @@ [http://code.google.com/apis/language/translate/v2/pricing.html Pricing] | [https://code.google.com/apis/console Stats] </text> + <text + type="string" + length="1" + follows="top|right" + height="20" + layout="topleft" + left="70" + name="deepl_api_domain_label" + top_pad="80" + width="85"> + Endpoint: + </text> + + <combo_box + allow_text_entry="false" + follows="left|top" + name="deepl_api_domain_combo" + height="23" + left_pad="10" + width="140" + top_delta="-4" + max_chars="512" + value="https://api-free.deepl.com" + combo_button.scale_image="true"> + <combo_box.item + label="DeepL Free" + name="global" + value="https://api-free.deepl.com" /> + <combo_box.item + label="DeepL Pro" + name="api-apc" + value="https://api.deepl.com" /> + </combo_box> + + <text + follows="top|right" + height="20" + layout="topleft" + left="70" + length="1" + name="deepl_api_key_label" + top_pad="11" + type="string" + width="85"> + DeepL API key: + </text> + + <line_editor + default_text="Enter DeepL API key and click "Verify"" + follows="top|left" + height="20" + layout="topleft" + left_pad="10" + max_length_chars="50" + top_delta="-4" + name="deepl_api_key" + width="210" /> + + <button + follows="left|top" + height="23" + label="Verify" + layout="topleft" + left_pad="10" + name="verify_deepl_api_key_btn" + top_delta="-2" + width="90" /> + + <text + follows="top|right" + height="20" + layout="topleft" + left="185" + length="1" + name="deepl_links_text" + top_delta="-53" + type="string" + width="100"> + [https://www.deepl.com/pro/select-country?cta=header-prices Pricing] + </text> + <button follows="left|top" height="23" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index aa8e6176e1..ef720e65e3 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6441,6 +6441,14 @@ Your trash is overflowing. This may cause problems logging in. </notification> <notification + icon="notifytip.tga" + name="InventoryLimitReachedAIS" + type="notifytip"> +Your inventory is experiencing issues. Please, contact support. + <tag>fail</tag> + </notification> + + <notification icon="alertmodal.tga" name="InventoryLimitReachedAISAlert" type="alertmodal"> diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml index ebedbf20c7..fea7d1bcb8 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml @@ -27,6 +27,26 @@ Account: [ACCTTYPE] [PAYMENTINFO] </string> + + <!--Badges--> + <string + name="BadgeBeta" + value="Original Beta Tester" /> + <string + name="BadgeBetaLifetime" + value="Beta Lifetime member" /> + <string + name="BadgeLifetime" + value="Lifetime member" /> + <string + name="BadgeLinden" + value="Linden Lab employee" /> + <string + name="BadgePremiumLifetime" + value="Premium lifetime" /> + <string + name="BadgePremiumPlusLifetime" + value="Premium Plus lifetime" /> <layout_stack name="image_stack" @@ -156,9 +176,39 @@ Account: [ACCTTYPE] user_resize="false" visible="true"> </layout_panel> - + + <layout_panel + name="badge_layout" + follows="all" + layout="topleft" + height="40" + auto_resize="false" + user_resize="false" + visible="false"> + <icon + name="badge_icon" + image_name="Beta_Tester" + layout="topleft" + follows="left|top" + top="10" + left="5" + height="18" + width="18"/> + <text + name="badge_text" + value="Badge Tester" + top="13" + left_pad="3" + right="-1" + height="16" + follows="left|top|right" + layout="topleft" + translate="false" + visible="true"/> + </layout_panel> + <layout_panel - name="frind_layout" + name="friend_layout" follows="all" layout="topleft" height="16" @@ -166,7 +216,7 @@ Account: [ACCTTYPE] user_resize="false" visible="false"> <text - name="frind_text" + name="friend_text" value="You are friends" text_color="ConversationFriendColor" top="0" diff --git a/indra/newview/skins/default/xui/pt/panel_edit_hair.xml b/indra/newview/skins/default/xui/pt/panel_edit_hair.xml index 13f1f892f9..e9750a1c2e 100644 --- a/indra/newview/skins/default/xui/pt/panel_edit_hair.xml +++ b/indra/newview/skins/default/xui/pt/panel_edit_hair.xml @@ -7,7 +7,7 @@ <accordion name="wearable_accordion"> <accordion_tab name="hair_color_tab" title="Cor"/> <accordion_tab name="hair_style_tab" title="Estilo"/> - <accordion_tab name="hair_eyebrows_tab" title="Sombrancelhas"/> + <accordion_tab name="hair_eyebrows_tab" title="Sobrancelhas"/> <accordion_tab name="hair_facial_tab" title="Faciais"/> </accordion> </panel> |