diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index 0efaf94fa6..d09310a3c4 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -2057,7 +2057,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.mKeys.size(), "num_pos_keys"); // Fix LL merge bug + 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 2299471dd2..039cee9144 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 fc78662f09..284bfb2afa 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 #include // Forward declarations -class LLErrorThread; class LLLiveFile; #if LL_LINUX #include @@ -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 1ae337979b..39cf95a837 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -286,7 +286,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 221ccf9811..0000000000 --- a/indra/llcommon/llerrorthread.cpp +++ /dev/null @@ -1,135 +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. - - // Do not log as this can lead to deadlocks during startup. - // 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/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 7b0d4e4af2..bb0f4440c9 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -320,6 +320,17 @@ void LLLayoutStack::draw() } } +void LLLayoutStack::deleteAllChildren() +{ + mPanels.clear(); + LLView::deleteAllChildren(); + + // Not really needed since nothing is left to + // display, but for the sake of consistency + updateFractionalSizes(); + mNeedsLayout = true; +} + void LLLayoutStack::removeChild(LLView* view) { LLLayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast(view)); @@ -327,21 +338,14 @@ void LLLayoutStack::removeChild(LLView* view) if (embedded_panelp) { mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp)); - // delete embedded_panelp; // Fix crash when removing layout panels from a stack + LLView::removeChild(view); updateFractionalSizes(); mNeedsLayout = true; } - - LLView::removeChild(view); - - // Fix crash when removing layout panels from a stack - if (embedded_panelp) - { - // only delete the panel after it was removed from LLView to prevent - // LLView::removeChild() to run into an already deleted pointer - delete embedded_panelp; - } - // + else + { + LLView::removeChild(view); + } } BOOL LLLayoutStack::postBuild() diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index 87a9dd9921..142712b5f5 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -72,6 +72,7 @@ public: virtual ~LLLayoutStack(); /*virtual*/ void draw(); + /*virtual*/ void deleteAllChildren(); /*virtual*/ void removeChild(LLView*); /*virtual*/ BOOL postBuild(); /*virtual*/ bool addChild(LLView* child, S32 tab_group = 0); diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 18b789da24..7ec9f3028c 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -1905,6 +1905,13 @@ bool LLMenuGL::addContextChild(LLView* view, S32 tab_group) return false; } + +void LLMenuGL::deleteAllChildren() +{ + mItems.clear(); + LLUICtrl::deleteAllChildren(); +} + void LLMenuGL::removeChild( LLView* ctrl) { // previously a dynamic_cast with if statement to check validity diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 760d3eff6c..9caf356183 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -443,6 +443,7 @@ public: /*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha); /*virtual*/ void setVisible(BOOL visible); /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); + /*virtual*/ void deleteAllChildren(); /*virtual*/ void removeChild( LLView* ctrl); /*virtual*/ BOOL postBuild(); diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index df6d8ef5b8..a5d6c2345a 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -626,8 +626,10 @@ void LLView::deleteAllChildren() while (!mChildList.empty()) { - LLView* viewp = mChildList.front(); - delete viewp; // will remove the child from mChildList + LLView* viewp = mChildList.front(); + viewp->mParentView = NULL; + delete viewp; + mChildList.pop_front(); } } diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 1d940630f9..83ffbcea56 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -16246,6 +16246,17 @@ Change of this parameter will affect the layout of buttons in notification toast Value + DeepLTranslateAPIKey + + Comment + DeepL Translation service data to use with the DeepL Translator API + Persist + 1 + Type + LLSD + Value + + TutorialURL Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 9939b9df8c..404c1735e6 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4335,8 +4335,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) @@ -4437,163 +4435,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("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 323cd21c5a..7356c12a79 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 c5d90770d7..c5f243b09c 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -128,8 +128,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); unsetenv( "LD_PRELOAD" ); // Get rid of any preloading, we do not want this to happen during startup of plugins. 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 f3b43244c4..bc2ab87a97 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -472,8 +472,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/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp index f20d17b700..d1cbf6c834 100644 --- a/indra/newview/llfloatertranslationsettings.cpp +++ b/indra/newview/llfloatertranslationsettings.cpp @@ -50,6 +50,7 @@ LLFloaterTranslationSettings::LLFloaterTranslationSettings(const LLSD& key) , mMachineTranslationCB(NULL) , mAzureKeyVerified(false) , mGoogleKeyVerified(false) +, mDeepLKeyVerified(false) { } @@ -63,8 +64,11 @@ BOOL LLFloaterTranslationSettings::postBuild() mAzureAPIKeyEditor = getChild("azure_api_key"); mAzureAPIRegionEditor = getChild("azure_api_region"); mGoogleAPIKeyEditor = getChild("google_api_key"); + mDeepLAPIDomainCombo = getChild("deepl_api_domain_combo"); + mDeepLAPIKeyEditor = getChild("deepl_api_key"); mAzureVerifyBtn = getChild("verify_azure_api_key_btn"); mGoogleVerifyBtn = getChild("verify_google_api_key_btn"); + mDeepLVerifyBtn = getChild("verify_deepl_api_key_btn"); mOKBtn = getChild("ok_btn"); mMachineTranslationCB->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::updateControlsEnabledState, this)); @@ -73,18 +77,37 @@ BOOL LLFloaterTranslationSettings::postBuild() getChild("cancel_btn")->setClickedCallback(boost::bind(&LLFloater::closeFloater, this, false)); 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(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this)); - mAzureAPIEndpointEditor->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this)); + mAzureAPIEndpointEditor->setFocusLostCallback([this](LLFocusableElement*) + { + setAzureVerified(false, false, 0); + }); + mAzureAPIEndpointEditor->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) + { + setAzureVerified(false, false, 0); + }); 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; } @@ -133,6 +156,20 @@ 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(); } @@ -158,6 +195,17 @@ void LLFloaterTranslationSettings::setGoogleVerified(bool ok, bool alert, S32 st 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(); @@ -183,6 +231,17 @@ std::string LLFloaterTranslationSettings::getEnteredGoogleKey() const return mGoogleAPIKeyEditor->getTentative() ? LLStringUtil::null : mGoogleAPIKeyEditor->getText(); } +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; @@ -202,29 +261,42 @@ void LLFloaterTranslationSettings::updateControlsEnabledState() std::string service = getSelectedService(); bool azure_selected = service == "azure"; bool google_selected = service == "google"; + bool deepl_selected = service == "deepl"; mTranslationServiceRadioGroup->setEnabled(on); mLanguageCombo->setEnabled(on); - getChild("azure_api_endoint_label")->setEnabled(on); - mAzureAPIEndpointEditor->setEnabled(on); + // MS Azure + getChild("azure_api_endoint_label")->setEnabled(on); + mAzureAPIEndpointEditor->setEnabled(on && azure_selected); getChild("azure_api_key_label")->setEnabled(on); - mAzureAPIKeyEditor->setEnabled(on); + mAzureAPIKeyEditor->setEnabled(on && azure_selected); getChild("azure_api_region_label")->setEnabled(on); - mAzureAPIRegionEditor->setEnabled(on); + mAzureAPIRegionEditor->setEnabled(on && azure_selected); - getChild("google_api_key_label")->setEnabled(on); - mGoogleAPIKeyEditor->setEnabled(on); + mAzureVerifyBtn->setEnabled(on && azure_selected && + !mAzureKeyVerified && getEnteredAzureKey().isMap()); - mAzureAPIKeyEditor->setEnabled(on && azure_selected); - mGoogleAPIKeyEditor->setEnabled(on && google_selected); + // Google + getChild("google_api_key_label")->setEnabled(on); + mGoogleAPIKeyEditor->setEnabled(on && google_selected); - mAzureVerifyBtn->setEnabled(on && azure_selected && - !mAzureKeyVerified && getEnteredAzureKey().isMap()); mGoogleVerifyBtn->setEnabled(on && google_selected && !mGoogleKeyVerified && !getEnteredGoogleKey().empty()); - bool service_verified = (azure_selected && mAzureKeyVerified) || (google_selected && mGoogleKeyVerified); + // DeepL + getChild("deepl_api_domain_label")->setEnabled(on); + mDeepLAPIDomainCombo->setEnabled(on && deepl_selected); + getChild("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); @@ -250,6 +322,9 @@ void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, b case LLTranslate::SERVICE_GOOGLE: floater->setGoogleVerified(ok, alert, status); break; + case LLTranslate::SERVICE_DEEPL: + floater->setDeepLVerified(ok, alert, status); + break; } } @@ -276,8 +351,7 @@ void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control) void LLFloaterTranslationSettings::onAzureKeyEdited() { if (mAzureAPIKeyEditor->isDirty() - || mAzureAPIRegionEditor->isDirty() - || mAzureAPIEndpointEditor->getValue().isString()) + || mAzureAPIRegionEditor->isDirty()) { // todo: verify mAzureAPIEndpointEditor url setAzureVerified(false, false, 0); @@ -292,6 +366,14 @@ void LLFloaterTranslationSettings::onGoogleKeyEdited() } } +void LLFloaterTranslationSettings::onDeepLKeyEdited() +{ + if (mDeepLAPIKeyEditor->isDirty()) + { + setDeepLVerified(false, false, 0); + } +} + void LLFloaterTranslationSettings::onBtnAzureVerify() { LLSD key = getEnteredAzureKey(); @@ -309,15 +391,28 @@ void LLFloaterTranslationSettings::onBtnGoogleVerify() 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 azure_selected = service == "azure"; bool google_selected = service == "google"; + bool deepl_selected = service == "deepl"; - bool service_verified = (azure_selected && mAzureKeyVerified) || (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() { @@ -326,6 +421,7 @@ void LLFloaterTranslationSettings::onBtnOK() gSavedSettings.setString("TranslationService", getSelectedService()); 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 f039d90e27..eff0803fdd 100644 --- a/indra/newview/llfloatertranslationsettings.h +++ b/indra/newview/llfloatertranslationsettings.h @@ -44,12 +44,14 @@ public: 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; LLSD getEnteredAzureKey() const; std::string getEnteredGoogleKey() const; + LLSD getEnteredDeepLKey() const; void showAlert(const std::string& msg_name, S32 status) const; void updateControlsEnabledState(); void verifyKey(int service, const LLSD& key, bool alert = true); @@ -57,25 +59,31 @@ private: void onEditorFocused(LLFocusableElement* control); void onAzureKeyEdited(); void onGoogleKeyEdited(); + void onDeepLKeyEdited(); void onBtnAzureVerify(); void onBtnGoogleVerify(); + void onBtnDeepLVerify(); void onBtnOK(); static void setVerificationStatus(int service, bool alert, bool ok, S32 status); LLCheckBoxCtrl* mMachineTranslationCB; LLComboBox* mLanguageCombo; - LLComboBox* mAzureAPIEndpointEditor;; + LLComboBox* mAzureAPIEndpointEditor; LLLineEditor* mAzureAPIKeyEditor; LLLineEditor* mAzureAPIRegionEditor; LLLineEditor* mGoogleAPIKeyEditor; + LLComboBox* mDeepLAPIDomainCombo; + LLLineEditor* mDeepLAPIKeyEditor; LLRadioGroup* mTranslationServiceRadioGroup; LLButton* mAzureVerifyBtn; LLButton* mGoogleVerifyBtn; + LLButton* mDeepLVerifyBtn; LLButton* mOKBtn; bool mAzureKeyVerified; bool mGoogleKeyVerified; + bool mDeepLKeyVerified; }; #endif // LL_LLFLOATERTRANSLATIONSETTINGS_H diff --git a/indra/newview/llinspecttoast.cpp b/indra/newview/llinspecttoast.cpp index 68801b0895..6f93a78ca6 100644 --- a/indra/newview/llinspecttoast.cpp +++ b/indra/newview/llinspecttoast.cpp @@ -47,6 +47,7 @@ public: /*virtual*/ void onOpen(const LLSD& notification_id); /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); + /*virtual*/ void deleteAllChildren(); /*virtual*/ void removeChild(LLView* child); private: void onToastDestroy(LLToast * toast); @@ -122,6 +123,12 @@ BOOL LLInspectToast::handleToolTip(S32 x, S32 y, MASK mask) return LLFloater::handleToolTip(x, y, mask); } +void LLInspectToast::deleteAllChildren() +{ + mPanel = NULL; + LLInspect::deleteAllChildren(); +} + // virtual void LLInspectToast::removeChild(LLView* child) { diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index d64416048c..5f931893b4 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -662,7 +662,11 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( } } - if(rv.isNull() && create_folder && root_id.notNull()) + if(rv.isNull() + && root_id.notNull() + && create_folder + && preferred_type != LLFolderType::FT_MARKETPLACE_LISTINGS + && preferred_type != LLFolderType::FT_OUTBOX) { if (isInventoryUsable()) diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index a485420721..d0f87ac5dc 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -133,7 +133,9 @@ public: LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers, const std::string & url, - const std::string & msg) const = 0; + 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, @@ -230,7 +232,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s return; } - LLSD result = sendMessageAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url, msg); + LLSD result = sendMessageAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url, msg, fromTo.first, fromTo.second); if (LLApp::isQuitting()) { @@ -331,7 +333,9 @@ public: LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers, const std::string & url, - const std::string & msg) const override; + 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, @@ -508,7 +512,9 @@ LLSD LLGoogleTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCorou LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers, const std::string & url, - const std::string & msg) const + const std::string & msg, + const std::string& from_lang, + const std::string& to_lang) const { return adapter->getRawAndSuspend(request, url, options, headers); } @@ -558,7 +564,9 @@ public: LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers, const std::string & url, - const std::string & msg) const override; + 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, @@ -728,7 +736,7 @@ bool LLAzureTranslationHandler::parseResponse( // virtual bool LLAzureTranslationHandler::isConfigured() const { - return !getAPIKey().isMap(); + return getAPIKey().isMap(); } //static @@ -814,7 +822,9 @@ LLSD LLAzureTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCorout LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers, const std::string & url, - const std::string & msg) const + 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()); @@ -838,6 +848,259 @@ LLSD LLAzureTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAd 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 +{ + 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) +{ + // DeepL doesn't seem to have any error handling beyoun http codes + return std::string(); +} + +// static +LLSD LLDeepLTranslationHandler::getAPIKey() +{ + static LLCachedControl 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 +{ + 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); +} + //========================================================================= LLTranslate::LLTranslate(): mCharsSeen(0), @@ -867,6 +1130,11 @@ std::string LLTranslate::addNoTranslateTags(std::string mesg) return mesg; } + if (getPreferredHandler().getCurrentService() == SERVICE_DEEPL) + { + return mesg; + } + if (getPreferredHandler().getCurrentService() == SERVICE_AZURE) { // https://learn.microsoft.com/en-us/azure/cognitive-services/translator/prevent-translation @@ -892,6 +1160,10 @@ std::string LLTranslate::removeNoTranslateTags(std::string mesg) { return mesg; } + if (getPreferredHandler().getCurrentService() == SERVICE_DEEPL) + { + return mesg; + } if (getPreferredHandler().getCurrentService() == SERVICE_AZURE) { @@ -997,6 +1269,14 @@ LLTranslationAPIHandler& LLTranslate::getPreferredHandler() { service = SERVICE_GOOGLE; } + if (service_str == "azure") + { + service = SERVICE_AZURE; + } + if (service_str == "deepl") + { + service = SERVICE_DEEPL; + } return getHandler(service); } @@ -1006,11 +1286,18 @@ LLTranslationAPIHandler& LLTranslate::getHandler(EService service) { static LLGoogleTranslationHandler google; 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 azure; } diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index ffbbb05e62..4a5d80737c 100644 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -61,6 +61,7 @@ public : typedef enum e_service { SERVICE_AZURE, SERVICE_GOOGLE, + SERVICE_DEEPL, } EService; typedef boost::function KeyVerificationResult_fn; 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 63a1cb2149..a984a8ab76 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 @@ Azure service identifier not verified. Status: [STATUS]. Please check your settings and try again. Google API key not verified. Status: [STATUS]. Please check your key and try again. + DeepL Auth Key key not verified. Status: [STATUS]. Please check your key and try again. Azure service identifier verified. Google API key verified. + DeepL API key verified. + [https://learn.microsoft.com/en-us/azure/cognitive-services/translator/create-translator-resource Setup] @@ -286,7 +294,7 @@ left_pad="10" name="verify_google_api_key_btn" top_delta="-2" - width="90" /> + width="90" /> + + Domain: + + + + + + + + + DeepL API key: + + + + +