Merge branch 'main' into DRTVWR-539

# Conflicts:
#	indra/integration_tests/llui_libtest/CMakeLists.txt
#	indra/newview/llfloateravatarrendersettings.cpp
master
Mnikolenko Productengine 2023-03-31 17:16:26 +03:00
commit 41d24952ff
76 changed files with 1382 additions and 534 deletions

View File

@ -2701,9 +2701,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>2e8d817e7837dd6f4284b13fa3f5c15e</string>
<string>9e1b5515ab59b4e9cfeef6626d65d03d</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104765/917714/viewer_manager-3.0.575083-darwin64-575083.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/108609/945996/viewer_manager-3.0.577252-darwin64-577252.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -2713,9 +2713,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>3efa80faaf537e39a77218cd6efa9409</string>
<string>a3c599595ecc8fb987a5499fca42520a</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104766/917721/viewer_manager-3.0.575083-windows-575083.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/108610/946003/viewer_manager-3.0.577252-windows-577252.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@ -2726,7 +2726,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>source_type</key>
<string>hg</string>
<key>version</key>
<string>3.0.575083</string>
<string>3.0.577252</string>
</map>
<key>vlc-bin</key>
<map>

View File

@ -272,6 +272,14 @@ public:
boost::bind(&ReadPipeImpl::tick, this, _1));
}
~ReadPipeImpl()
{
if (mConnection.connected())
{
mConnection.disconnect();
}
}
// Much of the implementation is simply connecting the abstract virtual
// methods with implementation data concealed from the base class.
virtual std::istream& get_istream() { return mStream; }

View File

@ -38,7 +38,6 @@ from io import StringIO
from http.server import HTTPServer, BaseHTTPRequestHandler
from llbase.fastest_elementtree import parse as xml_parse
from llbase import llsd
# we're in llcorehttp/tests ; testrunner.py is found in llmessage/tests

View File

@ -35,7 +35,6 @@
#include "llassettype.h"
#include "lldir.h"
#include <boost/filesystem.hpp>
#include <boost/range/iterator_range.hpp>
#include <chrono>
#include "lldiskcache.h"
@ -100,19 +99,20 @@ void LLDiskCache::purge()
#endif
if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed())
{
for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path, ec), {}))
boost::filesystem::directory_iterator iter(cache_path, ec);
while (iter != boost::filesystem::directory_iterator() && !ec.failed())
{
if (boost::filesystem::is_regular_file(entry, ec) && !ec.failed())
if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed())
{
if (entry.path().string().find(mCacheFilenamePrefix) != std::string::npos)
if ((*iter).path().string().find(mCacheFilenamePrefix) != std::string::npos)
{
uintmax_t file_size = boost::filesystem::file_size(entry, ec);
uintmax_t file_size = boost::filesystem::file_size(*iter, ec);
if (ec.failed())
{
continue;
}
const std::string file_path = entry.path().string();
const std::time_t file_time = boost::filesystem::last_write_time(entry, ec);
const std::string file_path = (*iter).path().string();
const std::time_t file_time = boost::filesystem::last_write_time(*iter, ec);
if (ec.failed())
{
continue;
@ -121,6 +121,7 @@ void LLDiskCache::purge()
file_info.push_back(file_info_t(file_time, { file_size, file_path }));
}
}
iter.increment(ec);
}
}
@ -348,19 +349,21 @@ void LLDiskCache::clearCache()
#endif
if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed())
{
for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path, ec), {}))
boost::filesystem::directory_iterator iter(cache_path, ec);
while (iter != boost::filesystem::directory_iterator() && !ec.failed())
{
if (boost::filesystem::is_regular_file(entry, ec) && !ec.failed())
if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed())
{
if (entry.path().string().find(mCacheFilenamePrefix) != std::string::npos)
if ((*iter).path().string().find(mCacheFilenamePrefix) != std::string::npos)
{
boost::filesystem::remove(entry, ec);
boost::filesystem::remove(*iter, ec);
if (ec.failed())
{
LL_WARNS() << "Failed to delete cache file " << entry << ": " << ec.message() << LL_ENDL;
LL_WARNS() << "Failed to delete cache file " << *iter << ": " << ec.message() << LL_ENDL;
}
}
}
iter.increment(ec);
}
}
}
@ -379,20 +382,22 @@ void LLDiskCache::removeOldVFSFiles()
#endif
if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed())
{
for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path, ec), {}))
boost::filesystem::directory_iterator iter(cache_path, ec);
while (iter != boost::filesystem::directory_iterator() && !ec.failed())
{
if (boost::filesystem::is_regular_file(entry, ec) && !ec.failed())
if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed())
{
if ((entry.path().string().find(CACHE_FORMAT) != std::string::npos) ||
(entry.path().string().find(DB_FORMAT) != std::string::npos))
if (((*iter).path().string().find(CACHE_FORMAT) != std::string::npos) ||
((*iter).path().string().find(DB_FORMAT) != std::string::npos))
{
boost::filesystem::remove(entry, ec);
boost::filesystem::remove(*iter, ec);
if (ec.failed())
{
LL_WARNS() << "Failed to delete cache file " << entry << ": " << ec.message() << LL_ENDL;
LL_WARNS() << "Failed to delete cache file " << *iter << ": " << ec.message() << LL_ENDL;
}
}
}
iter.increment(ec);
}
}
}
@ -418,19 +423,21 @@ uintmax_t LLDiskCache::dirFileSize(const std::string dir)
#endif
if (boost::filesystem::is_directory(dir_path, ec) && !ec.failed())
{
for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(dir_path, ec), {}))
boost::filesystem::directory_iterator iter(dir_path, ec);
while (iter != boost::filesystem::directory_iterator() && !ec.failed())
{
if (boost::filesystem::is_regular_file(entry, ec) && !ec.failed())
if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed())
{
if (entry.path().string().find(mCacheFilenamePrefix) != std::string::npos)
if ((*iter).path().string().find(mCacheFilenamePrefix) != std::string::npos)
{
uintmax_t file_size = boost::filesystem::file_size(entry, ec);
uintmax_t file_size = boost::filesystem::file_size(*iter, ec);
if (!ec.failed())
{
total_file_size += file_size;
}
}
}
iter.increment(ec);
}
}

View File

@ -89,6 +89,8 @@ const U64 REGION_FLAGS_ALLOW_VOICE = (1 << 28);
const U64 REGION_FLAGS_BLOCK_PARCEL_SEARCH = (1 << 29);
const U64 REGION_FLAGS_DENY_AGEUNVERIFIED = (1 << 30);
const U64 REGION_FLAGS_DENY_BOTS = (1 << 31);
const U64 REGION_FLAGS_DEFAULT = REGION_FLAGS_ALLOW_LANDMARK |
REGION_FLAGS_ALLOW_SET_HOME |
REGION_FLAGS_ALLOW_PARCEL_CHANGES |

View File

@ -162,6 +162,11 @@ LLPluginProcessParent::~LLPluginProcessParent()
{ // If we are quitting, the network sockets will already have been destroyed.
killSockets();
}
if (mPolling.connected())
{
mPolling.disconnect();
}
}
/*static*/

View File

@ -759,11 +759,13 @@ void LLFloater::closeFloater(bool app_quitting)
}
// now close dependent floater
for(handle_set_iter_t dependent_it = mDependents.begin();
dependent_it != mDependents.end(); )
while(mDependents.size() > 0)
{
handle_set_iter_t dependent_it = mDependents.begin();
LLFloater* floaterp = dependent_it->get();
dependent_it = mDependents.erase(dependent_it);
// normally removeDependentFloater will do this, but in
// case floaterp is somehow invalid or orphaned, erase now
mDependents.erase(dependent_it);
if (floaterp)
{
floaterp->mDependeeHandle = LLHandle<LLFloater>();

View File

@ -206,6 +206,7 @@ bool LLUrlEntryBase::isWikiLinkCorrect(const std::string &labeled_url) const
{
return (chr == L'\u02D0') // "Modifier Letter Colon"
|| (chr == L'\uFF1A') // "Fullwidth Colon"
|| (chr == L'\u2236') // "Ratio"
|| (chr == L'\uFE55'); // "Small Colon"
},
L'\u003A'); // Colon

View File

@ -169,7 +169,7 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it)
{
//Skip for url entry icon if content is not trusted
if(!is_content_trusted && (mUrlEntryIcon == *it))
if((mUrlEntryIcon == *it) && ((text.find("Hand") != std::string::npos) || !is_content_trusted))
{
continue;
}

View File

@ -215,6 +215,7 @@ NSWindowRef createNSWindow(int x, int y, int width, int height)
styleMask:NSTitledWindowMask | NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTexturedBackgroundWindowMask backing:NSBackingStoreBuffered defer:NO];
[window makeKeyAndOrderFront:nil];
[window setAcceptsMouseMovedEvents:TRUE];
[window setRestorable:FALSE]; // Viewer manages state from own settings
return window;
}

View File

@ -3905,42 +3905,48 @@ void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
sLanguageTextInputAllowed = b;
if ( sLanguageTextInputAllowed )
{
// Allowing: Restore the previous IME status, so that the user has a feeling that the previous
// text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps
// using same Input Locale (aka Keyboard Layout).
if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale)
{
HIMC himc = LLWinImm::getContext(mWindowHandle);
LLWinImm::setOpenStatus(himc, TRUE);
LLWinImm::setConversionStatus(himc, sWinIMEConversionMode, sWinIMESentenceMode);
LLWinImm::releaseContext(mWindowHandle, himc);
}
}
else
{
// Disallowing: Turn off the IME so that succeeding key events bypass IME and come to us directly.
// However, do it after saving the current IME status. We need to restore the status when
// allowing language text input again.
sWinInputLocale = GetKeyboardLayout(0);
sWinIMEOpened = LLWinImm::isIME(sWinInputLocale);
if (sWinIMEOpened)
{
HIMC himc = LLWinImm::getContext(mWindowHandle);
sWinIMEOpened = LLWinImm::getOpenStatus(himc);
if (sWinIMEOpened)
{
LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode);
if (sLanguageTextInputAllowed)
{
mWindowThread->post([=]()
{
// Allowing: Restore the previous IME status, so that the user has a feeling that the previous
// text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps
// using same Input Locale (aka Keyboard Layout).
if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale)
{
HIMC himc = LLWinImm::getContext(mWindowHandle);
LLWinImm::setOpenStatus(himc, TRUE);
LLWinImm::setConversionStatus(himc, sWinIMEConversionMode, sWinIMESentenceMode);
LLWinImm::releaseContext(mWindowHandle, himc);
}
});
}
else
{
mWindowThread->post([=]()
{
// Disallowing: Turn off the IME so that succeeding key events bypass IME and come to us directly.
// However, do it after saving the current IME status. We need to restore the status when
// allowing language text input again.
sWinInputLocale = GetKeyboardLayout(0);
sWinIMEOpened = LLWinImm::isIME(sWinInputLocale);
if (sWinIMEOpened)
{
HIMC himc = LLWinImm::getContext(mWindowHandle);
sWinIMEOpened = LLWinImm::getOpenStatus(himc);
if (sWinIMEOpened)
{
LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode);
// We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's
// keyboard hooking, because Some IME reacts only on the former and some other on the latter...
LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode);
LLWinImm::setOpenStatus(himc, FALSE);
}
LLWinImm::releaseContext(mWindowHandle, himc);
}
}
// We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's
// keyboard hooking, because Some IME reacts only on the former and some other on the latter...
LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode);
LLWinImm::setOpenStatus(himc, FALSE);
}
LLWinImm::releaseContext(mWindowHandle, himc);
}
});
}
}
void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds,
@ -4137,6 +4143,10 @@ void LLWindowWin32::handleStartCompositionMessage()
void LLWindowWin32::handleCompositionMessage(const U32 indexes)
{
if (!mPreeditor)
{
return;
}
BOOL needs_update = FALSE;
LLWString result_string;
LLWString preedit_string;
@ -4435,7 +4445,7 @@ BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *res
LLWString context = find_context(wtext, preedit, preedit_length, &context_offset);
preedit -= context_offset;
preedit_length = llmin(preedit_length, (S32)context.length() - preedit);
if (preedit_length && preedit >= 0)
if (preedit_length > 0 && preedit >= 0)
{
// IMR_DOCUMENTFEED may be called when we have an active preedit.
// We should pass the context string *excluding* the preedit string.

View File

@ -1 +1 @@
6.6.10
6.6.11

View File

@ -220,6 +220,17 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>FetchGroupChatHistory</key>
<map>
<key>Comment</key>
<string>Fetch recent messages from group chat servers when a group window opens</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>VoiceCallsFriendsOnly</key>
<map>
<key>Comment</key>

View File

@ -133,7 +133,6 @@ LLAgentCamera::LLAgentCamera() :
mCameraFOVZoomFactor(0.f),
mCameraCurrentFOVZoomFactor(0.f),
mCameraFocusOffset(),
mCameraFOVDefault(DEFAULT_FIELD_OF_VIEW),
mCameraCollidePlane(),
@ -155,7 +154,6 @@ LLAgentCamera::LLAgentCamera() :
mFocusObject(NULL),
mFocusObjectDist(0.f),
mFocusObjectOffset(),
mFocusDotRadius( 0.1f ), // meters
mTrackFocusObject(TRUE),
mAtKey(0), // Either 1, 0, or -1... indicates that movement-key is pressed
@ -2361,6 +2359,11 @@ void LLAgentCamera::changeCameraToCustomizeAvatar()
gAgent.standUp(); // force stand up
gViewerWindow->getWindow()->resetBusyCount();
if (LLSelectMgr::getInstance()->getSelection()->isAttachment())
{
LLSelectMgr::getInstance()->deselectAll();
}
if (gFaceEditToolset)
{
LLToolMgr::getInstance()->setCurrentToolset(gFaceEditToolset);

View File

@ -152,7 +152,6 @@ private:
F32 mTargetCameraDistance; // Target camera offset from avatar
F32 mCameraFOVZoomFactor; // Amount of fov zoom applied to camera when zeroing in on an object
F32 mCameraCurrentFOVZoomFactor; // Interpolated fov zoom
F32 mCameraFOVDefault; // Default field of view that is basis for FOV zoom effect
LLVector4 mCameraCollidePlane; // Colliding plane for camera
F32 mCameraZoomFraction; // Mousewheel driven fraction of zoom
LLVector3 mCameraPositionAgent; // Camera position in agent coordinates
@ -167,7 +166,6 @@ private:
// Follow
//--------------------------------------------------------------------
public:
void setUsingFollowCam(bool using_follow_cam);
bool isfollowCamLocked();
private:
LLFollowCam mFollowCam; // Ventrella
@ -233,7 +231,6 @@ private:
LLPointer<LLViewerObject> mFocusObject;
F32 mFocusObjectDist;
LLVector3 mFocusObjectOffset;
F32 mFocusDotRadius; // Meters
BOOL mTrackFocusObject;
//--------------------------------------------------------------------

View File

@ -53,7 +53,16 @@ void LLAgentUI::buildSLURL(LLSLURL& slurl, const bool escaped /*= true*/)
LLViewerRegion *regionp = gAgent.getRegion();
if (regionp)
{
return_slurl = LLSLURL(regionp->getName(), gAgent.getPositionGlobal());
// Make sure coordinates are within current region
LLVector3d global_pos = gAgent.getPositionGlobal();
LLVector3d region_origin = regionp->getOriginGlobal();
// -1 otherwise slurl will fmod 256 to 0.
// And valid slurl range is supposed to be 0..255
F64 max_val = REGION_WIDTH_METERS - 1;
global_pos.mdV[VX] = llclamp(global_pos[VX], region_origin[VX], region_origin[VX] + max_val);
global_pos.mdV[VY] = llclamp(global_pos[VY], region_origin[VY], region_origin[VY] + max_val);
return_slurl = LLSLURL(regionp->getName(), global_pos);
}
slurl = return_slurl;
}

View File

@ -5483,7 +5483,8 @@ void LLAppViewer::disconnectViewer()
{
gInventory.cache(gInventory.getRootFolderID(), gAgent.getID());
if (gInventory.getLibraryRootFolderID().notNull()
&& gInventory.getLibraryOwnerID().notNull())
&& gInventory.getLibraryOwnerID().notNull()
&& !mSecondInstance) // agent is unique, library isn't
{
gInventory.cache(
gInventory.getLibraryRootFolderID(),

View File

@ -79,7 +79,9 @@ static S32 cube_channel = -1;
static S32 diffuse_channel = -1;
static S32 bump_channel = -1;
#define LL_BUMPLIST_MULTITHREADED 0 // TODO -- figure out why this doesn't work
// Enabled after changing LLViewerTexture::mNeedsCreateTexture to an
// LLAtomicBool; this should work just fine, now. HB
#define LL_BUMPLIST_MULTITHREADED 1
// static

View File

@ -74,6 +74,7 @@ bool LLEstateInfoModel::getDenyAgeUnverified() const { return getFlag(REGION_FL
bool LLEstateInfoModel::getAllowVoiceChat() const { return getFlag(REGION_FLAGS_ALLOW_VOICE); }
bool LLEstateInfoModel::getAllowAccessOverride() const { return getFlag(REGION_FLAGS_ALLOW_ACCESS_OVERRIDE); }
bool LLEstateInfoModel::getAllowEnvironmentOverride() const { return getFlag(REGION_FLAGS_ALLOW_ENVIRONMENT_OVERRIDE); }
bool LLEstateInfoModel::getDenyScriptedAgents() const { return getFlag(REGION_FLAGS_DENY_BOTS); }
void LLEstateInfoModel::setUseFixedSun(bool val) { setFlag(REGION_FLAGS_SUN_FIXED, val); }
void LLEstateInfoModel::setIsExternallyVisible(bool val) { setFlag(REGION_FLAGS_EXTERNALLY_VISIBLE, val); }
@ -83,6 +84,7 @@ void LLEstateInfoModel::setDenyAgeUnverified(bool val) { setFlag(REGION_FLAGS_D
void LLEstateInfoModel::setAllowVoiceChat(bool val) { setFlag(REGION_FLAGS_ALLOW_VOICE, val); }
void LLEstateInfoModel::setAllowAccessOverride(bool val) { setFlag(REGION_FLAGS_ALLOW_ACCESS_OVERRIDE, val); }
void LLEstateInfoModel::setAllowEnvironmentOverride(bool val) { setFlag(REGION_FLAGS_ALLOW_ENVIRONMENT_OVERRIDE, val); }
void LLEstateInfoModel::setDenyScriptedAgents(bool val) { setFlag(REGION_FLAGS_DENY_BOTS, val); }
void LLEstateInfoModel::update(const strings_t& strings)
{
@ -148,6 +150,7 @@ void LLEstateInfoModel::commitEstateInfoCapsCoro(std::string url)
body["allow_direct_teleport"] = getAllowDirectTeleport();
body["deny_anonymous"] = getDenyAnonymous();
body["deny_age_unverified"] = getDenyAgeUnverified();
body["block_bots"] = getDenyScriptedAgents();
body["allow_voice_chat"] = getAllowVoiceChat();
body["override_public_access"] = getAllowAccessOverride();
@ -222,6 +225,7 @@ std::string LLEstateInfoModel::getInfoDump()
dump["allow_direct_teleport"] = getAllowDirectTeleport();
dump["deny_anonymous" ] = getDenyAnonymous();
dump["deny_age_unverified" ] = getDenyAgeUnverified();
dump["block_bots" ] = getDenyScriptedAgents();
dump["allow_voice_chat" ] = getAllowVoiceChat();
dump["override_public_access"] = getAllowAccessOverride();
dump["override_environment"] = getAllowEnvironmentOverride();

View File

@ -57,6 +57,7 @@ public:
bool getAllowVoiceChat() const;
bool getAllowAccessOverride() const;
bool getAllowEnvironmentOverride() const;
bool getDenyScriptedAgents() const;
const std::string& getName() const { return mName; }
const LLUUID& getOwnerID() const { return mOwnerID; }
@ -72,6 +73,7 @@ public:
void setAllowVoiceChat(bool val);
void setAllowAccessOverride(bool val);
void setAllowEnvironmentOverride(bool val);
void setDenyScriptedAgents(bool val);
void setSunHour(F32 sun_hour) { mSunHour = sun_hour; }

View File

@ -428,13 +428,18 @@ void LLFloaterAvatarPicker::findCoro(std::string url, LLUUID queryID, std::strin
if (status || (status == LLCore::HttpStatus(HTTP_BAD_REQUEST)))
{
LLFloaterAvatarPicker* floater =
LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", name);
if (floater)
{
result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
floater->processResponse(queryID, result);
}
result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
}
else
{
result["failure_reason"] = status.toString();
}
LLFloaterAvatarPicker* floater =
LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", name);
if (floater)
{
floater->processResponse(queryID, result);
}
}
@ -672,59 +677,67 @@ void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD&
{
LLScrollListCtrl* search_results = getChild<LLScrollListCtrl>("SearchResults");
LLSD agents = content["agents"];
// clear "Searching" label on first results
search_results->deleteAllItems();
// clear "Searching" label on first results
search_results->deleteAllItems();
if (content.has("failure_reason"))
{
getChild<LLScrollListCtrl>("SearchResults")->setCommentText(content["failure_reason"].asString());
getChildView("ok_btn")->setEnabled(false);
}
else
{
LLSD agents = content["agents"];
LLSD item;
LLSD::array_const_iterator it = agents.beginArray();
for ( ; it != agents.endArray(); ++it)
{
const LLSD& row = *it;
if (row["id"].asUUID() != gAgent.getID() || !mExcludeAgentFromSearchResults)
{
item["id"] = row["id"];
LLSD& columns = item["columns"];
columns[0]["column"] = "name";
columns[0]["value"] = row["display_name"];
columns[1]["column"] = "username";
columns[1]["value"] = row["username"];
search_results->addElement(item);
LLSD item;
LLSD::array_const_iterator it = agents.beginArray();
for (; it != agents.endArray(); ++it)
{
const LLSD& row = *it;
if (row["id"].asUUID() != gAgent.getID() || !mExcludeAgentFromSearchResults)
{
item["id"] = row["id"];
LLSD& columns = item["columns"];
columns[0]["column"] = "name";
columns[0]["value"] = row["display_name"];
columns[1]["column"] = "username";
columns[1]["value"] = row["username"];
search_results->addElement(item);
// add the avatar name to our list
LLAvatarName avatar_name;
avatar_name.fromLLSD(row);
sAvatarNameMap[row["id"].asUUID()] = avatar_name;
}
}
// add the avatar name to our list
LLAvatarName avatar_name;
avatar_name.fromLLSD(row);
sAvatarNameMap[row["id"].asUUID()] = avatar_name;
}
}
if (search_results->isEmpty())
{
std::string name = "'" + getChild<LLUICtrl>("Edit")->getValue().asString() + "'";
LLSD item;
item["id"] = LLUUID::null;
item["columns"][0]["column"] = "name";
item["columns"][0]["value"] = name;
item["columns"][1]["column"] = "username";
item["columns"][1]["value"] = getString("not_found_text");
search_results->addElement(item);
search_results->setEnabled(false);
getChildView("ok_btn")->setEnabled(false);
}
else
{
getChildView("ok_btn")->setEnabled(true);
search_results->setEnabled(true);
search_results->sortByColumnIndex(1, TRUE);
std::string text = getChild<LLUICtrl>("Edit")->getValue().asString();
if (!search_results->selectItemByLabel(text, TRUE, 1))
{
search_results->selectFirstItem();
}
onList();
search_results->setFocus(TRUE);
}
if (search_results->isEmpty())
{
std::string name = "'" + getChild<LLUICtrl>("Edit")->getValue().asString() + "'";
LLSD item;
item["id"] = LLUUID::null;
item["columns"][0]["column"] = "name";
item["columns"][0]["value"] = name;
item["columns"][1]["column"] = "username";
item["columns"][1]["value"] = getString("not_found_text");
search_results->addElement(item);
search_results->setEnabled(false);
getChildView("ok_btn")->setEnabled(false);
}
else
{
getChildView("ok_btn")->setEnabled(true);
search_results->setEnabled(true);
search_results->sortByColumnIndex(1, TRUE);
std::string text = getChild<LLUICtrl>("Edit")->getValue().asString();
if (!search_results->selectItemByLabel(text, TRUE, 1))
{
search_results->selectFirstItem();
}
onList();
search_results->setFocus(TRUE);
}
}
}
}

View File

@ -47,6 +47,7 @@ public:
virtual ~LLFloaterDisplayName() { }
/*virtual*/ BOOL postBuild();
void onSave();
void onReset();
void onCancel();
/*virtual*/ void onOpen(const LLSD& key);
@ -101,6 +102,7 @@ void LLFloaterDisplayName::onOpen(const LLSD& key)
BOOL LLFloaterDisplayName::postBuild()
{
getChild<LLUICtrl>("reset_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onReset, this));
getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onCancel, this));
getChild<LLUICtrl>("save_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onSave, this));
@ -156,6 +158,20 @@ void LLFloaterDisplayName::onCancel()
setVisible(false);
}
void LLFloaterDisplayName::onReset()
{
LLAvatarName av_name;
if (!LLAvatarNameCache::get(gAgent.getID(), &av_name))
{
return;
}
getChild<LLUICtrl>("display_name_editor")->setValue(av_name.getCompleteName());
getChild<LLUICtrl>("display_name_confirm")->clear();
getChild<LLUICtrl>("display_name_confirm")->setFocus(TRUE);
}
void LLFloaterDisplayName::onSave()
{
std::string display_name_utf8 = getChild<LLUICtrl>("display_name_editor")->getValue().asString();

View File

@ -1880,6 +1880,7 @@ BOOL LLPanelEstateInfo::postBuild()
initCtrl("allow_direct_teleport");
initCtrl("limit_payment");
initCtrl("limit_age_verified");
initCtrl("limit_bots");
initCtrl("voice_chat_check");
initCtrl("parcel_access_override");
@ -1903,12 +1904,14 @@ void LLPanelEstateInfo::refresh()
getChildView("Only Allow")->setEnabled(public_access);
getChildView("limit_payment")->setEnabled(public_access);
getChildView("limit_age_verified")->setEnabled(public_access);
getChildView("limit_bots")->setEnabled(public_access);
// if this is set to false, then the limit fields are meaningless and should be turned off
if (public_access == false)
{
getChild<LLUICtrl>("limit_payment")->setValue(false);
getChild<LLUICtrl>("limit_age_verified")->setValue(false);
getChild<LLUICtrl>("limit_bots")->setValue(false);
}
}
@ -1925,6 +1928,7 @@ void LLPanelEstateInfo::refreshFromEstate()
getChild<LLUICtrl>("limit_payment")->setValue(estate_info.getDenyAnonymous());
getChild<LLUICtrl>("limit_age_verified")->setValue(estate_info.getDenyAgeUnverified());
getChild<LLUICtrl>("parcel_access_override")->setValue(estate_info.getAllowAccessOverride());
getChild<LLUICtrl>("limit_bots")->setValue(estate_info.getDenyScriptedAgents());
// Ensure appriopriate state of the management UI
updateControls(gAgent.getRegion());
@ -1968,6 +1972,7 @@ bool LLPanelEstateInfo::callbackChangeLindenEstate(const LLSD& notification, con
estate_info.setDenyAgeUnverified(getChild<LLUICtrl>("limit_age_verified")->getValue().asBoolean());
estate_info.setAllowVoiceChat(getChild<LLUICtrl>("voice_chat_check")->getValue().asBoolean());
estate_info.setAllowAccessOverride(getChild<LLUICtrl>("parcel_access_override")->getValue().asBoolean());
estate_info.setDenyScriptedAgents(getChild<LLUICtrl>("limit_bots")->getValue().asBoolean());
// JIGGLYPUFF
//estate_info.setAllowAccessOverride(getChild<LLUICtrl>("")->getValue().asBoolean());
// send the update to sim

View File

@ -56,7 +56,6 @@ const F32 HORIZONTAL_PADDING = 16.f;
const F32 VERTICAL_PADDING = 12.f;
const F32 LINE_PADDING = 3.f; // aka "leading"
const F32 BUFFER_SIZE = 2.f;
const F32 HUD_TEXT_MAX_WIDTH = 190.f;
const S32 NUM_OVERLAP_ITERATIONS = 10;
const F32 POSITION_DAMPING_TC = 0.2f;
const F32 MAX_STABLE_CAMERA_VELOCITY = 0.1f;
@ -67,6 +66,8 @@ const F32 LOD_2_SCREEN_COVERAGE = 0.40f;
std::set<LLPointer<LLHUDNameTag> > LLHUDNameTag::sTextObjects;
std::vector<LLPointer<LLHUDNameTag> > LLHUDNameTag::sVisibleTextObjects;
BOOL LLHUDNameTag::sDisplayText = TRUE ;
const F32 LLHUDNameTag::NAMETAG_MAX_WIDTH = 298.f;
const F32 LLHUDNameTag::HUD_TEXT_MAX_WIDTH = 190.f;
bool llhudnametag_further_away::operator()(const LLPointer<LLHUDNameTag>& lhs, const LLPointer<LLHUDNameTag>& rhs) const
{
@ -414,7 +415,8 @@ void LLHUDNameTag::addLine(const std::string &text_utf8,
const LLColor4& color,
const LLFontGL::StyleFlags style,
const LLFontGL* font,
const bool use_ellipses)
const bool use_ellipses,
F32 max_pixels)
{
LLWString wline = utf8str_to_wstring(text_utf8);
if (!wline.empty())
@ -431,7 +433,7 @@ void LLHUDNameTag::addLine(const std::string &text_utf8,
tokenizer tokens(wline, sep);
tokenizer::iterator iter = tokens.begin();
const F32 max_pixels = HUD_TEXT_MAX_WIDTH;
max_pixels = llmin(max_pixels, NAMETAG_MAX_WIDTH);
while (iter != tokens.end())
{
U32 line_length = 0;
@ -488,7 +490,7 @@ void LLHUDNameTag::setLabel(const std::string &label_utf8)
addLabel(label_utf8);
}
void LLHUDNameTag::addLabel(const std::string& label_utf8)
void LLHUDNameTag::addLabel(const std::string& label_utf8, F32 max_pixels)
{
LLWString wstr = utf8string_to_wstring(label_utf8);
if (!wstr.empty())
@ -502,13 +504,15 @@ void LLHUDNameTag::addLabel(const std::string& label_utf8)
tokenizer tokens(wstr, sep);
tokenizer::iterator iter = tokens.begin();
max_pixels = llmin(max_pixels, NAMETAG_MAX_WIDTH);
while (iter != tokens.end())
{
U32 line_length = 0;
do
{
S32 segment_length = mFontp->maxDrawableChars(iter->substr(line_length).c_str(),
HUD_TEXT_MAX_WIDTH, wstr.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
max_pixels, wstr.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
LLHUDTextSegment segment(iter->substr(line_length, segment_length), LLFontGL::NORMAL, mColor, mFontp);
mLabelSegments.push_back(segment);
line_length += segment_length;
@ -695,7 +699,7 @@ void LLHUDNameTag::updateSize()
const LLFontGL* fontp = iter->mFont;
height += fontp->getLineHeight();
height += LINE_PADDING;
width = llmax(width, llmin(iter->getWidth(fontp), HUD_TEXT_MAX_WIDTH));
width = llmax(width, llmin(iter->getWidth(fontp), NAMETAG_MAX_WIDTH));
++iter;
}
@ -709,7 +713,7 @@ void LLHUDNameTag::updateSize()
while (iter != mLabelSegments.end())
{
height += mFontp->getLineHeight();
width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH));
width = llmax(width, llmin(iter->getWidth(mFontp), NAMETAG_MAX_WIDTH));
++iter;
}

View File

@ -85,6 +85,9 @@ public:
ALIGN_VERT_CENTER
} EVertAlignment;
static const F32 NAMETAG_MAX_WIDTH; // 298px, made to fit 31 M's
static const F32 HUD_TEXT_MAX_WIDTH; // 190px
public:
// Set entire string, eliminating existing lines
void setString(const std::string& text_utf8);
@ -92,11 +95,17 @@ public:
void clearString();
// Add text a line at a time, allowing custom formatting
void addLine(const std::string &text_utf8, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL, const LLFontGL* font = NULL, const bool use_ellipses = false);
void addLine(
const std::string &text_utf8,
const LLColor4& color,
const LLFontGL::StyleFlags style = LLFontGL::NORMAL,
const LLFontGL* font = NULL,
const bool use_ellipses = false,
F32 max_pixels = HUD_TEXT_MAX_WIDTH);
// For bubble chat, set the part above the chat text
void setLabel(const std::string& label_utf8);
void addLabel(const std::string& label_utf8);
void addLabel(const std::string& label_utf8, F32 max_pixels = HUD_TEXT_MAX_WIDTH);
// Sets the default font for lines with no font specified
void setFont(const LLFontGL* font);

View File

@ -453,7 +453,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
BOOL is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL) ? false : true;
BOOL accept_im_from_only_friend = gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly");
BOOL is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT &&
LLMuteList::getInstance()->isLinden(name);
LLMuteList::isLinden(name);
chat.mMuted = is_muted;
chat.mFromID = from_id;
@ -521,7 +521,9 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
dialog,
parent_estate_id,
region_id,
position);
position,
false, // is_region_msg
timestamp);
if (!gIMMgr->isDNDMessageSend(session_id))
{
@ -592,7 +594,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
parent_estate_id,
region_id,
position,
region_message);
region_message,
timestamp);
}
else
{
@ -1111,7 +1114,9 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
IM_SESSION_INVITE,
parent_estate_id,
region_id,
position);
position,
false, // is_region_msg
timestamp);
}
else
{
@ -1131,12 +1136,14 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
from_id,
name,
buffer,
IM_OFFLINE == offline,
ll_safe_string((char*)binary_bucket),
(IM_OFFLINE == offline),
ll_safe_string((char*)binary_bucket), // session name
IM_SESSION_INVITE,
parent_estate_id,
region_id,
position);
position,
false, // is_region_msg
timestamp);
}
break;

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,7 @@ class LLAvatarName;
class LLFriendObserver;
class LLCallDialogManager;
class LLIMSpeakerMgr;
/**
* Timeout Timer for outgoing Ad-Hoc/Group IM sessions which being initialized by the server
*/
@ -63,11 +64,14 @@ private:
class LLIMModel : public LLSingleton<LLIMModel>
{
LLSINGLETON(LLIMModel);
public:
struct LLIMSession : public boost::signals2::trackable
typedef std::list<LLSD> chat_message_list_t;
struct LLIMSession : public boost::signals2::trackable
{
typedef enum e_session_type
typedef enum e_session_type
{ // for now we have 4 predefined types for a session
P2P_SESSION,
GROUP_SESSION,
@ -75,15 +79,23 @@ public:
NONE_SESSION,
} SType;
LLIMSession(const LLUUID& session_id, const std::string& name,
LLIMSession(const LLUUID& session_id, const std::string& name,
const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg);
virtual ~LLIMSession();
void sessionInitReplyReceived(const LLUUID& new_session_id);
void addMessagesFromHistory(const std::list<LLSD>& history);
void addMessage(const std::string& from, const LLUUID& from_id, const std::string& utf8_text, const std::string& time, const bool is_history = false, bool is_region_msg = false);
void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction);
void addMessagesFromHistoryCache(const std::list<LLSD>& history); // From local file
void addMessagesFromServerHistory(const LLSD& history, const std::string& target_from, const std::string& target_message, U32 timestamp); // From chat server
void addMessage(const std::string& from,
const LLUUID& from_id,
const std::string& utf8_text,
const std::string& time,
const bool is_history,
const bool is_region_msg,
U32 timestamp);
void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction);
/** @deprecated */
static void chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata);
@ -112,6 +124,10 @@ public:
uuid_vec_t mInitialTargetIDs;
std::string mHistoryFileName;
// Saved messages from the last minute of history read from the local group chat cache file
std::string mLastHistoryCacheDateTime;
chat_message_list_t mLastHistoryCacheMsgs;
// connection to voice channel state change signal
boost::signals2::connection mVoiceChannelStateChangeConnection;
@ -121,7 +137,7 @@ public:
// does include all incoming messages
S32 mNumUnread;
std::list<LLSD> mMsgs;
chat_message_list_t mMsgs;
LLVoiceChannel* mVoiceChannel;
LLIMSpeakerMgr* mSpeakers;
@ -208,29 +224,43 @@ public:
* and also saved into a file if log2file is specified.
* It sends new message signal for each added message.
*/
bool addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& other_participant_id, const std::string& utf8_text, bool log2file = true, bool is_region_msg = false);
void addMessage(const LLUUID& session_id,
const std::string& from,
const LLUUID& other_participant_id,
const std::string& utf8_text,
bool log2file = true,
bool is_region_msg = false,
U32 time_stamp = 0);
void processAddingMessage(const LLUUID& session_id,
const std::string& from,
const LLUUID& from_id,
const std::string& utf8_text,
bool log2file,
bool is_region_msg,
U32 time_stamp);
/**
* Similar to addMessage(...) above but won't send a signal about a new message added
*/
LLIMModel::LLIMSession* addMessageSilently(const LLUUID& session_id, const std::string& from, const LLUUID& from_id,
const std::string& utf8_text, bool log2file = true, bool is_region_msg = false);
LLIMModel::LLIMSession* addMessageSilently(const LLUUID& session_id, const std::string& from, const LLUUID& from_id,
const std::string& utf8_text, bool log2file = true, bool is_region_msg = false, U32 timestamp = 0);
/**
* Add a system message to an IM Model
*/
bool proccessOnlineOfflineNotification(const LLUUID& session_id, const std::string& utf8_text);
void proccessOnlineOfflineNotification(const LLUUID& session_id, const std::string& utf8_text);
/**
* Get a session's name.
* For a P2P chat - it's an avatar's name,
* Get a session's name.
* For a P2P chat - it's an avatar's name,
* For a group chat - it's a group's name
* For an incoming ad-hoc chat - is received from the server and is in a from of "<Avatar's name> Conference"
* It is updated in LLIMModel::LLIMSession's constructor to localize the "Conference".
*/
const std::string getName(const LLUUID& session_id) const;
/**
/**
* Get number of unread messages in a session with session_id
* Returns -1 if the session with session_id doesn't exist
*/
@ -282,7 +312,7 @@ public:
bool logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text);
private:
/**
* Populate supplied std::list with messages starting from index specified by start_index without
* emitting no unread messages signal.
@ -292,7 +322,7 @@ private:
/**
* Add message to a list of message associated with session specified by session_id
*/
bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text, bool is_region_msg = false);
bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text, bool is_region_msg, U32 timestamp);
};
@ -334,7 +364,8 @@ public:
U32 parent_estate_id = 0,
const LLUUID& region_id = LLUUID::null,
const LLVector3& position = LLVector3::zero,
bool is_region_msg = false);
bool is_region_msg = false,
U32 timestamp = 0);
void addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args);

View File

@ -529,7 +529,11 @@ BOOL get_is_item_worn(const LLUUID& id)
const LLViewerInventoryItem* item = gInventory.getItem(id);
if (!item)
return FALSE;
if (item->getIsLinkType() && !gInventory.getItem(item->getLinkedUUID()))
{
return FALSE;
}
// Consider the item as worn if it has links in COF.
if (LLAppearanceMgr::instance().isLinkedInCOF(id))
{
@ -787,7 +791,7 @@ void show_item_original(const LLUUID& item_uuid)
LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
if (main_inventory)
{
main_inventory->resetFilters();
main_inventory->resetAllItemsFilters();
}
reset_inventory_filter();
@ -795,6 +799,7 @@ void show_item_original(const LLUUID& item_uuid)
{
LLFloaterReg::toggleInstanceOrBringToFront("inventory");
}
sidepanel_inventory->showInventoryPanel();
const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
if (gInventory.isObjectDescendentOf(gInventory.getLinkedItemID(item_uuid), inbox_id))
@ -2650,7 +2655,12 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
}
else
{
std::copy(selected_uuid_set.begin(), selected_uuid_set.end(), std::back_inserter(ids));
for (std::set<LLFolderViewItem*>::iterator it = selected_items.begin(), end_it = selected_items.end();
it != end_it;
++it)
{
ids.push_back(static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID());
}
}
// Check for actions that get handled in bulk
@ -2711,7 +2721,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
}
else if ("ungroup_folder_items" == action)
{
if (selected_uuid_set.size() == 1)
if (ids.size() == 1)
{
LLInventoryCategory* inv_cat = gInventory.getCategory(*ids.begin());
if (!inv_cat || LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))

View File

@ -1636,6 +1636,9 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo
LL_WARNS(LOG_INV) << "Deleting non-existent object [ id: " << id << " ] " << LL_ENDL;
return;
}
//collect the links before removing the item from mItemMap
LLInventoryModel::item_array_t links = collectLinksTo(id);
LL_DEBUGS(LOG_INV) << "Deleting inventory object " << id << LL_ENDL;
mLastItem = NULL;
@ -1693,7 +1696,7 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo
// update is getting broken link info separately.
if (fix_broken_links && !is_link_type)
{
updateLinkedObjectsFromPurge(id);
rebuildLinkItems(links);
}
obj = nullptr; // delete obj
if (do_notify_observers)
@ -1702,26 +1705,25 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo
}
}
void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id)
void LLInventoryModel::rebuildLinkItems(LLInventoryModel::item_array_t& items)
{
LLInventoryModel::item_array_t item_array = collectLinksTo(baseobj_id);
// REBUILD is expensive, so clear the current change list first else
// everything else on the changelist will also get rebuilt.
if (item_array.size() > 0)
{
notifyObservers();
for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
iter != item_array.end();
iter++)
{
const LLViewerInventoryItem *linked_item = (*iter);
const LLUUID &item_id = linked_item->getUUID();
if (item_id == baseobj_id) continue;
addChangedMask(LLInventoryObserver::REBUILD, item_id);
}
notifyObservers();
}
// REBUILD is expensive, so clear the current change list first else
// everything else on the changelist will also get rebuilt.
if (items.size() > 0)
{
notifyObservers();
for (LLInventoryModel::item_array_t::const_iterator iter = items.begin();
iter != items.end();
iter++)
{
const LLViewerInventoryItem *linked_item = (*iter);
if (linked_item)
{
addChangedMask(LLInventoryObserver::REBUILD, linked_item->getUUID());
}
}
notifyObservers();
}
}
// Add/remove an observer. If the observer is destroyed, be sure to
@ -1951,18 +1953,20 @@ void LLInventoryModel::cache(
items,
INCLUDE_TRASH,
can_cache);
std::string inventory_filename = getInvCacheAddres(agent_id);
saveToFile(inventory_filename, categories, items);
std::string gzip_filename(inventory_filename);
// Use temporary file to avoid potential conflicts with other
// instances (even a 'read only' instance unzips into a file)
std::string temp_file = gDirUtilp->getTempFilename();
saveToFile(temp_file, categories, items);
std::string gzip_filename = getInvCacheAddres(agent_id);
gzip_filename.append(".gz");
if(gzip_file(inventory_filename, gzip_filename))
if(gzip_file(temp_file, gzip_filename))
{
LL_DEBUGS(LOG_INV) << "Successfully compressed " << inventory_filename << LL_ENDL;
LLFile::remove(inventory_filename);
LL_DEBUGS(LOG_INV) << "Successfully compressed " << temp_file << " to " << gzip_filename << LL_ENDL;
LLFile::remove(temp_file);
}
else
{
LL_WARNS(LOG_INV) << "Unable to compress " << inventory_filename << LL_ENDL;
LL_WARNS(LOG_INV) << "Unable to compress " << temp_file << " into " << gzip_filename << LL_ENDL;
}
}
@ -3035,6 +3039,7 @@ bool LLInventoryModel::saveToFile(const std::string& filename,
return false;
}
}
fileXML.flush();
fileXML.close();

View File

@ -445,7 +445,7 @@ public:
void checkTrashOverflow();
protected:
void updateLinkedObjectsFromPurge(const LLUUID& baseobj_id);
void rebuildLinkItems(LLInventoryModel::item_array_t& items);
//--------------------------------------------------------------------
// Reorder

View File

@ -363,7 +363,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
//If there are items in mFetchQueue, we want to check the time since the last bulkFetch was
//sent. If it exceeds our retry time, go ahead and fire off another batch.
LLViewerRegion * region(gAgent.getRegion());
if (! region || gDisconnected)
if (! region || gDisconnected || LLApp::isExiting())
{
return;
}

View File

@ -1627,6 +1627,7 @@ void LLInventoryPanel::purgeSelectedItems()
if (inventory_selected.empty()) return;
LLSD args;
S32 count = inventory_selected.size();
std::vector<LLUUID> selected_items;
for (std::set<LLFolderViewItem*>::const_iterator it = inventory_selected.begin(), end_it = inventory_selected.end();
it != end_it;
++it)
@ -1636,27 +1637,23 @@ void LLInventoryPanel::purgeSelectedItems()
LLInventoryModel::item_array_t items;
gInventory.collectDescendents(item_id, cats, items, LLInventoryModel::INCLUDE_TRASH);
count += items.size() + cats.size();
selected_items.push_back(item_id);
}
args["COUNT"] = count;
LLNotificationsUtil::add("PurgeSelectedItems", args, LLSD(), boost::bind(&LLInventoryPanel::callbackPurgeSelectedItems, this, _1, _2));
LLNotificationsUtil::add("PurgeSelectedItems", args, LLSD(), boost::bind(callbackPurgeSelectedItems, _1, _2, selected_items));
}
void LLInventoryPanel::callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response)
// static
void LLInventoryPanel::callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response, const std::vector<LLUUID> inventory_selected)
{
if (!mFolderRoot.get()) return;
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option == 0)
{
const std::set<LLFolderViewItem*> inventory_selected = mFolderRoot.get()->getSelectionList();
if (inventory_selected.empty()) return;
std::set<LLFolderViewItem*>::const_iterator it = inventory_selected.begin();
const std::set<LLFolderViewItem*>::const_iterator it_end = inventory_selected.end();
for (; it != it_end; ++it)
for (auto it : inventory_selected)
{
LLUUID item_id = static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID();
remove_inventory_object(item_id, NULL);
remove_inventory_object(it, NULL);
}
}
}

View File

@ -260,7 +260,7 @@ public:
// Clean up stuff when the folder root gets deleted
void clearFolderRoot();
void callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response);
static void callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response, const std::vector<LLUUID> inventory_selected);
protected:
void openStartFolderOrMyInventory(); // open the first level of inventory

View File

@ -62,6 +62,7 @@
const S32 LOG_RECALL_SIZE = 2048;
const std::string LL_IM_TIME("time");
const std::string LL_IM_DATE_TIME("datetime");
const std::string LL_IM_TEXT("message");
const std::string LL_IM_FROM("from");
const std::string LL_IM_FROM_ID("from_id");
@ -133,14 +134,14 @@ void append_to_last_message(std::list<LLSD>& messages, const std::string& line)
messages.back()[LL_IM_TEXT] = im_text;
}
std::string remove_utf8_bom(const char* buf)
const char* remove_utf8_bom(const char* buf)
{
std::string res(buf);
if (res[0] == (char)0xEF && res[1] == (char)0xBB && res[2] == (char)0xBF)
{
res.erase(0, 3);
const char* start = buf;
if (start[0] == (char)0xEF && start[1] == (char)0xBB && start[2] == (char)0xBF)
{ // If string starts with the magic bytes, return pointer after it.
start += 3;
}
return res;
return start;
}
class LLLogChatTimeScanner: public LLSingleton<LLLogChatTimeScanner>
@ -315,7 +316,7 @@ std::string LLLogChat::cleanFileName(std::string filename)
return filename;
}
std::string LLLogChat::timestamp(bool withdate)
std::string LLLogChat::timestamp2LogString(U32 timestamp, bool withdate)
{
std::string timeStr;
if (withdate)
@ -333,7 +334,14 @@ std::string LLLogChat::timestamp(bool withdate)
}
LLSD substitution;
substitution["datetime"] = (S32)time_corrected();
if (timestamp == 0)
{
substitution["datetime"] = (S32)time_corrected();
}
else
{ // timestamp is correct utc already
substitution["datetime"] = (S32)timestamp;
}
LLStringUtil::format (timeStr, substitution);
return timeStr;
@ -355,7 +363,7 @@ void LLLogChat::saveHistory(const std::string& filename,
llassert(tmp_filename.size());
return;
}
llofstream file(LLLogChat::makeLogFileName(filename).c_str(), std::ios_base::app);
if (!file.is_open())
{
@ -366,7 +374,7 @@ void LLLogChat::saveHistory(const std::string& filename,
LLSD item;
if (gSavedPerAccountSettings.getBOOL("LogTimestamp"))
item["time"] = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate"));
item["time"] = LLLogChat::timestamp2LogString(0, gSavedPerAccountSettings.getBOOL("LogTimestampDate"));
item["from_id"] = from_id;
item["message"] = line;
@ -374,7 +382,7 @@ void LLLogChat::saveHistory(const std::string& filename,
//adding "Second Life:" for all system messages to make chat log history parsing more reliable
if (from.empty() && from_id.isNull())
{
item["from"] = SYSTEM_FROM;
item["from"] = SYSTEM_FROM;
}
else
{
@ -393,37 +401,60 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m
{
if (file_name.empty())
{
LL_WARNS("LLLogChat::loadChatHistory") << "Session name is Empty!" << LL_ENDL;
LL_WARNS("LLLogChat::loadChatHistory") << "Local history file name is empty!" << LL_ENDL;
return ;
}
bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false;
LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/
// Stat the file to find it and get the last history entry time
llstat stat_data;
std::string log_file_name = LLLogChat::makeLogFileName(file_name);
LL_DEBUGS("ChatHistory") << "First attempt to stat chat history file " << log_file_name << LL_ENDL;
S32 no_stat = LLFile::stat(log_file_name, &stat_data);
if (no_stat)
{
if (is_group)
{
std::string old_name(file_name);
old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size()); // trim off " (group)"
log_file_name = LLLogChat::makeLogFileName(old_name);
LL_DEBUGS("ChatHistory") << "Attempting to stat adjusted chat history file " << log_file_name << LL_ENDL;
no_stat = LLFile::stat(log_file_name, &stat_data);
if (!no_stat)
{ // Found it without "(group)", copy to new naming style. We already have the mod time in stat_data
log_file_name = LLLogChat::makeLogFileName(file_name);
LL_DEBUGS("ChatHistory") << "Attempt to stat copied history file " << log_file_name << LL_ENDL;
LLFile::copy(LLLogChat::makeLogFileName(old_name), log_file_name);
}
}
if (no_stat)
{
log_file_name = LLLogChat::oldLogFileName(file_name);
LL_DEBUGS("ChatHistory") << "Attempt to stat old history file name " << log_file_name << LL_ENDL;
no_stat = LLFile::stat(log_file_name, &stat_data);
if (no_stat)
{
LL_DEBUGS("ChatHistory") << "No previous conversation log file found for " << file_name << LL_ENDL;
return; //No previous conversation with this name.
}
}
}
// If we got here, we managed to stat the file.
// Open the file to read
LLFILE* fptr = LLFile::fopen(log_file_name, "r"); /*Flawfinder: ignore*/
if (!fptr)
{
if (is_group)
{
std::string old_name(file_name);
old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size());
fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "r");
if (fptr)
{
fclose(fptr);
LLFile::copy(LLLogChat::makeLogFileName(old_name), LLLogChat::makeLogFileName(file_name));
}
fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");
}
if (!fptr)
{
fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/
if (!fptr)
{
return; //No previous conversation with this name.
}
}
{ // Ok, this is strange but not really tragic in the big picture of things
LL_WARNS("ChatHistory") << "Unable to read file " << log_file_name << " after stat was successful" << LL_ENDL;
return;
}
S32 save_num_messages = messages.size();
char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/
char *bptr;
S32 len;
@ -441,6 +472,7 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m
while (fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr))
{
len = strlen(buffer) - 1; /*Flawfinder: ignore*/
// backfill any end of line characters with nulls
for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0';
if (firstline)
@ -473,6 +505,10 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m
}
}
fclose(fptr);
LL_DEBUGS("ChatHistory") << "Read " << (messages.size() - save_num_messages)
<< " messages of chat history from " << log_file_name
<< " file mod time " << (F64)stat_data.st_mtime << LL_ENDL;
}
bool LLLogChat::historyThreadsFinished(LLUUID session_id)
@ -837,7 +873,8 @@ bool LLLogChat::isTranscriptFileFound(std::string fullname)
{
//matching a timestamp
boost::match_results<std::string::const_iterator> matches;
if (ll_regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP))
std::string line(remove_utf8_bom(buffer));
if (ll_regex_match(line, matches, TIMESTAMP))
{
result = true;
}
@ -847,7 +884,7 @@ bool LLLogChat::isTranscriptFileFound(std::string fullname)
return result;
}
//*TODO mark object's names in a special way so that they will be distinguishable form avatar name
//*TODO mark object's names in a special way so that they will be distinguishable form avatar name
//which are more strict by its nature (only firstname and secondname)
//Example, an object's name can be written like "Object <actual_object's_name>"
void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const
@ -865,7 +902,7 @@ void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const
ostr << '[' << timestamp << ']' << TWO_SPACES;
}
//*TODO mark object's names in a special way so that they will be distinguishable form avatar name
//*TODO mark object's names in a special way so that they will be distinguishable from avatar name
//which are more strict by its nature (only firstname and secondname)
//Example, an object's name can be written like "Object <actual_object's_name>"
if (im[LL_IM_FROM].isDefined())
@ -928,7 +965,9 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params
timestamp.erase(0, 1);
timestamp.erase(timestamp.length()-1, 1);
if (cut_off_todays_date)
im[LL_IM_DATE_TIME] = timestamp; // Retain full date-time for merging chat histories
if (cut_off_todays_date)
{
LLLogChatTimeScanner::instance().checkAndCutOffDate(timestamp);
}
@ -936,9 +975,9 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params
im[LL_IM_TIME] = timestamp;
}
else
{
//timestamp is optional
im[LL_IM_TIME] = "";
{ //timestamp is optional
im[LL_IM_DATE_TIME] = "";
im[LL_IM_TIME] = "";
}
bool has_stuff = matches[IDX_STUFF].matched;

View File

@ -92,7 +92,7 @@ public:
LOG_END
};
static std::string timestamp(bool withdate = false);
static std::string timestamp2LogString(U32 timestamp, bool withdate);
static std::string makeLogFileName(std::string(filename));
static void renameLogFile(const std::string& old_filename, const std::string& new_filename);
/**
@ -201,6 +201,7 @@ extern const std::string GROUP_CHAT_SUFFIX;
// LLSD map lookup constants
extern const std::string LL_IM_TIME; //("time");
extern const std::string LL_IM_DATE_TIME; //("datetime");
extern const std::string LL_IM_TEXT; //("message");
extern const std::string LL_IM_FROM; //("from");
extern const std::string LL_IM_FROM_ID; //("from_id");

View File

@ -192,7 +192,7 @@ void LLMuteList::cleanupSingleton()
LLAvatarNameCache::getInstance()->setAccountNameChangedCallback(NULL);
}
BOOL LLMuteList::isLinden(const std::string& name) const
bool LLMuteList::isLinden(const std::string& name)
{
std::string username = boost::replace_all_copy(name, ".", " ");
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
@ -200,9 +200,9 @@ BOOL LLMuteList::isLinden(const std::string& name) const
tokenizer tokens(username, sep);
tokenizer::iterator token_iter = tokens.begin();
if (token_iter == tokens.end()) return FALSE;
if (token_iter == tokens.end()) return false;
token_iter++;
if (token_iter == tokens.end()) return FALSE;
if (token_iter == tokens.end()) return false;
std::string last_name = *token_iter;
LLStringUtil::toLower(last_name);

View File

@ -104,7 +104,7 @@ public:
// Alternate (convenience) form for places we don't need to pass the name, but do need flags
BOOL isMuted(const LLUUID& id, U32 flags) const { return isMuted(id, LLStringUtil::null, flags); };
BOOL isLinden(const std::string& name) const;
static bool isLinden(const std::string& name);
BOOL isLoaded() const { return mIsLoaded; }

View File

@ -275,7 +275,7 @@ void LLHandlerUtil::addNotifPanelToIM(const LLNotificationPtr& notification)
LLSD offer;
offer["notification_id"] = notification->getID();
offer["from"] = SYSTEM_FROM;
offer["time"] = LLLogChat::timestamp(false);
offer["time"] = LLLogChat::timestamp2LogString(0, false); // Use current time
offer["index"] = (LLSD::Integer)session->mMsgs.size();
session->mMsgs.push_front(offer);

View File

@ -1103,6 +1103,18 @@ void LLPanelLogin::onRememberPasswordCheck(void*)
if (sInstance)
{
gSavedSettings.setBOOL("UpdateRememberPasswordSetting", TRUE);
LLPointer<LLCredential> cred;
bool remember_user, remember_password;
getFields(cred, remember_user, remember_password);
std::string grid(LLGridManager::getInstance()->getGridId());
std::string user_id(cred->userID());
if (!remember_password)
{
gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid, user_id);
gSecAPIHandler->syncProtectedMap();
}
}
}

View File

@ -410,6 +410,18 @@ void LLPanelMainInventory::resetFilters()
setFilterTextFromFilter();
}
void LLPanelMainInventory::resetAllItemsFilters()
{
LLFloaterInventoryFinder *finder = getFinder();
getAllItemsPanel()->getFilter().resetDefault();
if (finder)
{
finder->updateElementsFromFilter();
}
setFilterTextFromFilter();
}
void LLPanelMainInventory::setSortBy(const LLSD& userdata)
{
U32 sort_order_mask = getActivePanel()->getSortOrder();

View File

@ -96,6 +96,7 @@ public:
void toggleFindOptions();
void resetFilters();
void resetAllItemsFilters();
protected:
//

View File

@ -39,6 +39,7 @@
#include "llagent.h"
#include "llviewerwindow.h"
#include "llviewermedia.h"
#include "llvovolume.h"
#include "llsdutil.h"
#include "llselectmgr.h"
#include "llbutton.h"
@ -452,10 +453,17 @@ bool LLPanelMediaSettingsGeneral::navigateHomeSelectedFace(bool only_if_current_
{
viewer_media_t media_impl =
LLViewerMedia::getInstance()->getMediaImplFromTextureID(object->getTE(face)->getMediaData()->getMediaID());
if(media_impl)
{
if (media_impl)
{
media_impl->setPriority(LLPluginClassMedia::PRIORITY_NORMAL);
media_impl->navigateHome();
if (!only_if_current_is_empty)
{
LLSD media_data;
media_data[LLMediaEntry::CURRENT_URL_KEY] = std::string();
object->getTE(face)->mergeIntoMediaData(media_data);
}
return true;
}
}
@ -471,6 +479,23 @@ bool LLPanelMediaSettingsGeneral::navigateHomeSelectedFace(bool only_if_current_
LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection();
selected_objects->getSelectedTEValue( &functor_navigate_media, all_face_media_navigated );
if (all_face_media_navigated)
{
struct functor_sync_to_server : public LLSelectedObjectFunctor
{
virtual bool apply(LLViewerObject* object)
{
LLVOVolume *volume = dynamic_cast<LLVOVolume*>(object);
if (volume)
{
volume->sendMediaDataUpdate();
}
return true;
}
} sendfunc;
selected_objects->applyToObjects(&sendfunc);
}
// Note: we don't update the 'current URL' field until the media data itself changes
return all_face_media_navigated;

View File

@ -75,6 +75,7 @@ LLToolCamera::LLToolCamera()
mOutsideSlopX(FALSE),
mOutsideSlopY(FALSE),
mValidClickPoint(FALSE),
mClickPickPending(false),
mValidSelection(FALSE),
mMouseSteering(FALSE),
mMouseUpX(0),
@ -127,6 +128,11 @@ BOOL LLToolCamera::handleMouseDown(S32 x, S32 y, MASK mask)
mValidClickPoint = FALSE;
// Sometimes Windows issues down and up events near simultaneously
// without giving async pick a chance to trigged
// Ex: mouse from numlock emulation
mClickPickPending = true;
// If mouse capture gets ripped away, claim we moused up
// at the point we moused down. JC
mMouseUpX = x;
@ -142,13 +148,15 @@ BOOL LLToolCamera::handleMouseDown(S32 x, S32 y, MASK mask)
void LLToolCamera::pickCallback(const LLPickInfo& pick_info)
{
if (!LLToolCamera::getInstance()->hasMouseCapture())
LLToolCamera* camera = LLToolCamera::getInstance();
if (!camera->mClickPickPending)
{
return;
}
camera->mClickPickPending = false;
LLToolCamera::getInstance()->mMouseDownX = pick_info.mMousePt.mX;
LLToolCamera::getInstance()->mMouseDownY = pick_info.mMousePt.mY;
camera->mMouseDownX = pick_info.mMousePt.mX;
camera->mMouseDownY = pick_info.mMousePt.mY;
gViewerWindow->moveCursorToCenter();
@ -158,7 +166,7 @@ void LLToolCamera::pickCallback(const LLPickInfo& pick_info)
// Check for hit the sky, or some other invalid point
if (!hit_obj && pick_info.mPosGlobal.isExactlyZero())
{
LLToolCamera::getInstance()->mValidClickPoint = FALSE;
camera->mValidClickPoint = FALSE;
return;
}
@ -168,7 +176,7 @@ void LLToolCamera::pickCallback(const LLPickInfo& pick_info)
LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
if (!selection->getObjectCount() || selection->getSelectType() != SELECT_TYPE_HUD)
{
LLToolCamera::getInstance()->mValidClickPoint = FALSE;
camera->mValidClickPoint = FALSE;
return;
}
}
@ -192,7 +200,7 @@ void LLToolCamera::pickCallback(const LLPickInfo& pick_info)
if( !good_customize_avatar_hit )
{
LLToolCamera::getInstance()->mValidClickPoint = FALSE;
camera->mValidClickPoint = FALSE;
return;
}
@ -237,7 +245,7 @@ void LLToolCamera::pickCallback(const LLPickInfo& pick_info)
}
LLToolCamera::getInstance()->mValidClickPoint = TRUE;
camera->mValidClickPoint = TRUE;
if( CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode() )
{
@ -284,32 +292,36 @@ BOOL LLToolCamera::handleMouseUp(S32 x, S32 y, MASK mask)
if (hasMouseCapture())
{
if (mValidClickPoint)
{
if( CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode() )
{
LLCoordGL mouse_pos;
LLVector3 focus_pos = gAgent.getPosAgentFromGlobal(gAgentCamera.getFocusGlobal());
BOOL success = LLViewerCamera::getInstance()->projectPosAgentToScreen(focus_pos, mouse_pos);
if (success)
{
LLUI::getInstance()->setMousePositionScreen(mouse_pos.mX, mouse_pos.mY);
}
}
else if (mMouseSteering)
{
LLUI::getInstance()->setMousePositionScreen(mMouseDownX, mMouseDownY);
}
else
{
gViewerWindow->moveCursorToCenter();
}
}
else
{
// not a valid zoomable object
LLUI::getInstance()->setMousePositionScreen(mMouseDownX, mMouseDownY);
}
// Do not move camera if we haven't gotten a pick
if (!mClickPickPending)
{
if (mValidClickPoint)
{
if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode())
{
LLCoordGL mouse_pos;
LLVector3 focus_pos = gAgent.getPosAgentFromGlobal(gAgentCamera.getFocusGlobal());
BOOL success = LLViewerCamera::getInstance()->projectPosAgentToScreen(focus_pos, mouse_pos);
if (success)
{
LLUI::getInstance()->setMousePositionScreen(mouse_pos.mX, mouse_pos.mY);
}
}
else if (mMouseSteering)
{
LLUI::getInstance()->setMousePositionScreen(mMouseDownX, mMouseDownY);
}
else
{
gViewerWindow->moveCursorToCenter();
}
}
else
{
// not a valid zoomable object
LLUI::getInstance()->setMousePositionScreen(mMouseDownX, mMouseDownY);
}
}
// calls releaseMouse() internally
setMouseCapture(FALSE);

View File

@ -49,6 +49,7 @@ public:
virtual LLTool* getOverrideTool(MASK mask) { return NULL; }
void setClickPickPending() { mClickPickPending = true; }
static void pickCallback(const LLPickInfo& pick_info);
BOOL mouseSteerMode() { return mMouseSteering; }
@ -65,6 +66,7 @@ protected:
BOOL mOutsideSlopX;
BOOL mOutsideSlopY;
BOOL mValidClickPoint;
bool mClickPickPending;
BOOL mValidSelection;
BOOL mMouseSteering;
S32 mMouseUpX; // needed for releaseMouse()

View File

@ -443,6 +443,7 @@ BOOL LLToolPie::handleLeftClickPick()
LLToolMgr::getInstance()->setTransientTool(LLToolCamera::getInstance());
gViewerWindow->hideCursor();
LLToolCamera::getInstance()->setMouseCapture(TRUE);
LLToolCamera::getInstance()->setClickPickPending();
LLToolCamera::getInstance()->pickCallback(mPick);
gAgentCamera.setFocusOnAvatar(TRUE, TRUE);

View File

@ -546,6 +546,18 @@ void LLBingTranslationHandler::verifyKey(const std::string &key, LLTranslate::Ke
}
//=========================================================================
LLTranslate::LLTranslate():
mCharsSeen(0),
mCharsSent(0),
mFailureCount(0),
mSuccessCount(0)
{
}
LLTranslate::~LLTranslate()
{
}
/*static*/
void LLTranslate::translateMessage(const std::string &from_lang, const std::string &to_lang,
const std::string &mesg, TranslationSuccess_fn success, TranslationFailure_fn failure)
@ -634,6 +646,43 @@ bool LLTranslate::isTranslationConfigured()
return getPreferredHandler().isConfigured();
}
void LLTranslate::logCharsSeen(size_t count)
{
mCharsSeen += count;
}
void LLTranslate::logCharsSent(size_t count)
{
mCharsSent += count;
}
void LLTranslate::logSuccess(S32 count)
{
mSuccessCount += count;
}
void LLTranslate::logFailure(S32 count)
{
mFailureCount += count;
}
LLSD LLTranslate::asLLSD() const
{
LLSD res;
bool on = gSavedSettings.getBOOL("TranslateChat");
res["on"] = on;
res["chars_seen"] = (S32) mCharsSeen;
if (on)
{
res["chars_sent"] = (S32) mCharsSent;
res["success_count"] = mSuccessCount;
res["failure_count"] = mFailureCount;
res["language"] = getTranslateLanguage();
res["service"] = gSavedSettings.getString("TranslationService");
}
return res;
}
// static
LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
{

View File

@ -30,6 +30,8 @@
#include "llbufferstream.h"
#include <boost/function.hpp>
#include "llsingleton.h"
namespace Json
{
class Value;
@ -48,8 +50,10 @@ class LLTranslationAPIHandler;
*
* API keys for translation are taken from saved settings.
*/
class LLTranslate
class LLTranslate: public LLSingleton<LLTranslate>
{
LLSINGLETON(LLTranslate);
~LLTranslate();
LOG_CLASS(LLTranslate);
public :
@ -94,9 +98,19 @@ public :
static std::string addNoTranslateTags(std::string mesg);
static std::string removeNoTranslateTags(std::string mesg);
void logCharsSeen(size_t count);
void logCharsSent(size_t count);
void logSuccess(S32 count);
void logFailure(S32 count);
LLSD asLLSD() const;
private:
static LLTranslationAPIHandler& getPreferredHandler();
static LLTranslationAPIHandler& getHandler(EService service);
size_t mCharsSeen;
size_t mCharsSent;
S32 mFailureCount;
S32 mSuccessCount;
};
#endif

View File

@ -704,7 +704,7 @@ LLUUID LLBufferedAssetUploadInfo::finishUpload(LLSD &result)
LLScriptAssetUpload::LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish):
LLBufferedAssetUploadInfo(itemId, LLAssetType::AT_LSL_TEXT, buffer, finish),
mExerienceId(),
mTargetType(LSL2),
mTargetType(MONO),
mIsRunning(false)
{
}
@ -725,7 +725,7 @@ LLSD LLScriptAssetUpload::generatePostBody()
if (getTaskId().isNull())
{
body["item_id"] = getItemId();
body["target"] = "lsl2";
body["target"] = "mono";
}
else
{

View File

@ -1907,7 +1907,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
log_message = LLTrans::getString("InvOfferDecline", log_message_args);
}
chat.mText = log_message;
if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269
if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::isLinden(mFromName) ) // muting for SL-42269
{
chat.mMuted = TRUE;
accept_to_trash = false; // will send decline message
@ -2426,6 +2426,7 @@ void translateSuccess(LLChat chat, LLSD toastArgs, std::string originalMsg, std:
chat.mText += " (" + LLTranslate::removeNoTranslateTags(translation) + ")";
}
LLTranslate::instance().logSuccess(1);
LLNotificationsUI::LLNotificationManager::instance().onChat(chat, toastArgs);
}
@ -2435,6 +2436,7 @@ void translateFailure(LLChat chat, LLSD toastArgs, int status, const std::string
LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages
chat.mText += " (" + msg + ")";
LLTranslate::instance().logFailure(1);
LLNotificationsUI::LLNotificationManager::instance().onChat(chat, toastArgs);
}
@ -2512,7 +2514,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
LLMute::flagTextChat)
|| LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagTextChat);
is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT &&
LLMuteList::getInstance()->isLinden(from_name);
LLMuteList::isLinden(from_name);
if (is_muted && (chat.mSourceType == CHAT_SOURCE_OBJECT))
{
@ -2669,6 +2671,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
LLSD args;
chat.mOwnerID = owner_id;
LLTranslate::instance().logCharsSeen(mesg.size());
if (gSavedSettings.getBOOL("TranslateChat") && chat.mSourceType != CHAT_SOURCE_SYSTEM)
{
if (chat.mChatStyle == CHAT_STYLE_IRC)
@ -2678,6 +2681,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
const std::string from_lang = ""; // leave empty to trigger autodetect
const std::string to_lang = LLTranslate::getTranslateLanguage();
LLTranslate::instance().logCharsSent(mesg.size());
LLTranslate::translateMessage(from_lang, to_lang, mesg,
boost::bind(&translateSuccess, chat, args, mesg, from_lang, _1, _2),
boost::bind(&translateFailure, chat, args, _1, _2));
@ -5819,8 +5823,12 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
{
count++;
known_questions |= script_perm.permbit;
// check whether permission question should cause special caution dialog
caution |= (script_perm.caution);
if (!LLMuteList::isLinden(owner_name))
{
// check whether permission question should cause special caution dialog
caution |= (script_perm.caution);
}
if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit)
continue;
@ -6346,7 +6354,7 @@ bool teleport_request_callback(const LLSD& notification, const LLSD& response)
LLAvatarName av_name;
LLAvatarNameCache::get(from_id, &av_name);
if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::getInstance()->isLinden(av_name.getUserName()))
if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::isLinden(av_name.getUserName()))
{
return false;
}

View File

@ -815,7 +815,10 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
{
virtual bool apply(LLViewerObject* objectp)
{
objectp->boostTexturePriority();
if (objectp)
{
objectp->boostTexturePriority();
}
return true;
}
} func;

View File

@ -65,6 +65,7 @@
#include "llvoicevivox.h"
#include "llinventorymodel.h"
#include "lluiusage.h"
#include "lltranslate.h"
namespace LLStatViewer
{
@ -591,6 +592,7 @@ void send_viewer_stats(bool include_preferences)
agent["meters_traveled"] = gAgent.getDistanceTraveled();
agent["regions_visited"] = gAgent.getRegionsVisited();
agent["mem_use"] = LLMemory::getCurrentRSS() / 1024.0;
agent["translation"] = LLTranslate::instance().asLLSD();
LLSD &system = body["system"];
@ -600,6 +602,7 @@ void send_viewer_stats(bool include_preferences)
system["cpu_sse"] = gSysCPU.getSSEVersions();
system["address_size"] = ADDRESS_SIZE;
system["os_bitness"] = LLOSInfo::instance().getOSBitness();
system["hardware_concurrency"] = (LLSD::Integer) std::thread::hardware_concurrency();
unsigned char MACAddress[MAC_ADDRESS_BYTES];
LLUUID::getNodeID(MACAddress);
std::string macAddressString = llformat("%02x-%02x-%02x-%02x-%02x-%02x",
@ -622,6 +625,7 @@ void send_viewer_stats(bool include_preferences)
gGLManager.asLLSD(system["gl"]);
S32 shader_level = 0;
if (LLPipeline::sRenderDeferred)
{

View File

@ -1118,7 +1118,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
mLoadedCallbackDesiredDiscardLevel = S8_MAX;
mPauseLoadedCallBacks = FALSE;
mNeedsCreateTexture = FALSE;
mNeedsCreateTexture = false;
mIsRawImageValid = FALSE;
mRawDiscardLevel = INVALID_DISCARD_LEVEL;
@ -1400,12 +1400,12 @@ void LLViewerFetchedTexture::addToCreateTexture()
{
//just update some variables, not to create a real GL texture.
createGLTexture(mRawDiscardLevel, mRawImage, 0, FALSE);
mNeedsCreateTexture = FALSE;
mNeedsCreateTexture = false;
destroyRawImage();
}
else if(!force_update && getDiscardLevel() > -1 && getDiscardLevel() <= mRawDiscardLevel)
{
mNeedsCreateTexture = FALSE;
mNeedsCreateTexture = false;
destroyRawImage();
}
else
@ -1441,7 +1441,7 @@ void LLViewerFetchedTexture::addToCreateTexture()
mRawDiscardLevel += i;
if(mRawDiscardLevel >= getDiscardLevel() && getDiscardLevel() > 0)
{
mNeedsCreateTexture = FALSE;
mNeedsCreateTexture = false;
destroyRawImage();
return;
}
@ -1473,7 +1473,7 @@ BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/)
destroyRawImage();
return FALSE;
}
mNeedsCreateTexture = FALSE;
mNeedsCreateTexture = false;
if (mRawImage.isNull())
{
@ -1609,14 +1609,14 @@ void LLViewerFetchedTexture::postCreateTexture()
destroyRawImage();
}
mNeedsCreateTexture = FALSE;
mNeedsCreateTexture = false;
}
void LLViewerFetchedTexture::scheduleCreateTexture()
{
if (!mNeedsCreateTexture)
{
mNeedsCreateTexture = TRUE;
mNeedsCreateTexture = true;
if (preCreateTexture())
{
#if LL_IMAGEGL_THREAD_CHECK
@ -1630,7 +1630,7 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
memcpy(data_copy, data, size);
}
#endif
mNeedsCreateTexture = TRUE;
mNeedsCreateTexture = true;
auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr;
if (mainq)
{

View File

@ -27,6 +27,7 @@
#ifndef LL_LLVIEWERTEXTURE_H
#define LL_LLVIEWERTEXTURE_H
#include "llatomic.h"
#include "llgltexture.h"
#include "lltimer.h"
#include "llframetimer.h"
@ -528,7 +529,9 @@ protected:
LLFrameTimer mStopFetchingTimer; // Time since mDecodePriority == 0.f.
BOOL mInImageList; // TRUE if image is in list (in which case don't reset priority!)
BOOL mNeedsCreateTexture;
// This needs to be atomic, since it is written both in the main thread
// and in the GL image worker thread... HB
LLAtomicBool mNeedsCreateTexture;
BOOL mForSculpt ; //a flag if the texture is used as sculpt data.
BOOL mIsFetched ; //is loaded from remote or from cache, not generated locally.

View File

@ -3547,14 +3547,15 @@ void LLVOAvatar::idleUpdateNameTagText(bool new_name)
void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font, const bool use_ellipses)
{
// extra width (NAMETAG_MAX_WIDTH) is for names only, not for chat
llassert(mNameText);
if (mVisibleChat)
{
mNameText->addLabel(line);
mNameText->addLabel(line, LLHUDNameTag::NAMETAG_MAX_WIDTH);
}
else
{
mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font, use_ellipses);
mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font, use_ellipses, LLHUDNameTag::NAMETAG_MAX_WIDTH);
}
mNameIsSet |= !line.empty();
}

View File

@ -4525,7 +4525,7 @@ void LLVivoxVoiceClient::messageEvent(
{
bool is_do_not_disturb = gAgent.isDoNotDisturb();
bool is_muted = LLMuteList::getInstance()->isMuted(session->mCallerID, session->mName, LLMute::flagTextChat);
bool is_linden = LLMuteList::getInstance()->isLinden(session->mName);
bool is_linden = LLMuteList::isLinden(session->mName);
LLChat chat;
chat.mMuted = is_muted && !is_linden;

View File

@ -1778,20 +1778,17 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
void LLPipeline::removeMutedAVsLights(LLVOAvatar* muted_avatar)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
light_set_t::iterator iter = gPipeline.mNearbyLights.begin();
while (iter != gPipeline.mNearbyLights.end())
{
if (iter->drawable->getVObj()->isAttachment() && iter->drawable->getVObj()->getAvatar() == muted_avatar)
{
gPipeline.mLights.erase(iter->drawable);
iter = gPipeline.mNearbyLights.erase(iter);
}
else
{
iter++;
}
}
for (light_set_t::iterator iter = gPipeline.mNearbyLights.begin();
iter != gPipeline.mNearbyLights.end(); iter++)
{
const LLViewerObject *vobj = iter->drawable->getVObj();
if (vobj && vobj->getAvatar()
&& vobj->isAttachment() && vobj->getAvatar() == muted_avatar)
{
gPipeline.mLights.erase(iter->drawable);
gPipeline.mNearbyLights.erase(iter);
}
}
}
U32 LLPipeline::addObject(LLViewerObject *vobj)

View File

@ -40,7 +40,7 @@
Klicken und ziehen, um Land auszuwählen
</floater.string>
<floater.string name="status_selectcount">
[OBJ_COUNT] Objekte ausgewählt, Auswirkung auf Land [LAND_IMPACT]
[OBJ_COUNT] Objekte ausgewählt, Auswirkung auf Land [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]
</floater.string>
<floater.string name="status_remaining_capacity">
Verbleibende Kapazität [LAND_CAPACITY].

View File

@ -56,7 +56,7 @@
max_length_chars="31"
height="20"
top_pad="5"
left="50" />
left_delta="0" />
<text
top_pad="15"
left="25"
@ -72,23 +72,33 @@
max_length_chars="31"
height="20"
top_pad="5"
left="50" />
left_delta="0" />
<button
label="Reset"
layout="topleft"
font="SansSerif"
width="120"
height="23"
top_pad="40"
left_delta="0"
name="reset_btn"
tool_tip="Use Username as a Display Name" />
<button
height="23"
label="Save"
layout="topleft"
font="SansSerif"
left="35"
left_pad="35"
name="save_btn"
tool_tip="Save your new Display Name"
top_pad="40"
top_delta="0"
width="120" />
<button
height="23"
label="Cancel"
font="SansSerif"
layout="topleft"
left_pad="125"
left_pad="5"
name="cancel_btn"
width="120" />
</floater>

View File

@ -323,7 +323,6 @@
follows="left|top"
decimal_digits="0"
increment="1"
control_name="Edit Cost"
name="Edit Cost"
label="Price:"
label_width="100"

View File

@ -1140,7 +1140,6 @@ even though the user gets a free copy.
decimal_digits="0"
increment="1"
left_pad="0"
control_name="Edit Cost"
name="Edit Cost"
label="L$"
label_width="15"

View File

@ -90,7 +90,7 @@
parameter="conversation_log" />
</menu_item_check>
<menu_item_separator layout="topleft" />
<menu_item_check name="Translate_chat" label="Translate Nearby chat">
<menu_item_check name="Translate_chat" label="Translate chat">
<menu_item_check.on_click
function="IMFloaterContainer.Action"
parameter="Translating.Toggle" />

View File

@ -92,10 +92,7 @@
label="Reset"
left_delta="233"
name="current_url_reset_btn"
width="110" >
<button.commit_callback
function="Media.ResetCurrentUrl"/>
</button>
width="110"/>
<check_box
bottom_delta="-25"
enabled="true"

View File

@ -82,7 +82,7 @@
<view_border
bevel_style="none"
follows="top|left"
height="185"
height="205"
layout="topleft"
left="10"
top_pad="5"
@ -125,6 +125,16 @@
tool_tip="Residents must have payment information on file to access this estate. See the [SUPPORT_SITE] for more information."
top_pad="2"
width="278" />
<check_box
follows="top|left"
height="18"
label="Must not be a scripted agent"
layout="topleft"
left_delta="0"
name="limit_bots"
tool_tip="Residents must not be a scripted agents (bots) to access this estate. See the [SUPPORT_SITE] for more information."
top_pad="2"
width="278" />
<check_box
height="18"
label="Parcel owners can be more restrictive"

View File

@ -450,7 +450,6 @@
follows="left|top"
decimal_digits="0"
increment="1"
control_name="Edit Cost"
name="Edit Cost"
label="Price: L$"
label_width="75"
@ -461,8 +460,72 @@
max_val="999999999"
top_pad="10"
tool_tip="Object cost." />
</panel>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left="10"
name="BaseMaskDebug"
text_color="White"
top_pad="30"
width="130">
B:
</text>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left_delta="60"
name="OwnerMaskDebug"
text_color="White"
top_delta="0"
width="270">
O:
</text>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left_delta="60"
name="GroupMaskDebug"
text_color="White"
top_delta="0"
width="210">
G:
</text>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left_delta="60"
name="EveryoneMaskDebug"
text_color="White"
top_delta="0"
width="150">
E:
</text>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left_delta="60"
name="NextMaskDebug"
text_color="White"
top_delta="0"
width="90">
N:
</text>
</panel>
</scroll_container>
<panel
height="30"

View File

@ -454,7 +454,6 @@
increment="1"
top_pad="10"
left="120"
control_name="Edit Cost"
name="Edit Cost"
label="Price: L$"
label_width="73"

View File

@ -126,8 +126,8 @@ http://secondlife.com/download
For more information, see our FAQ below:
http://secondlife.com/viewer-access-faq</string>
<string name="LoginFailed">Grid emergency login failure.
If you feel this is an error, please contact support@secondlife.com.</string>
<string name="LoginFailed">"Login process did not complete due to system issues. Try again in a few minutes.
If you feel this is an error, contact Support at https://support.secondlife.com"</string>
<string name="LoginIntermediateOptionalUpdateAvailable">Optional viewer update available: [VERSION]</string>
<string name="LoginFailedRequiredUpdate">Required viewer update: [VERSION]</string>
<string name="LoginFailedAlreadyLoggedIn">This agent is already logged in.

View File

@ -25,7 +25,7 @@
Pulsa y arrastra para seleccionar el terreno.
</floater.string>
<floater.string name="status_selectcount">
[OBJ_COUNT] objetos seleccionados, impacto en el terreno [LAND_IMPACT]
[OBJ_COUNT] objetos seleccionados, impacto en el terreno [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]
</floater.string>
<floater.string name="status_remaining_capacity">
Capacidad restante [LAND_CAPACITY].

View File

@ -40,7 +40,7 @@
Cliquez et faites glisser pour sélectionner le terrain.
</floater.string>
<floater.string name="status_selectcount">
[OBJ_COUNT] objets sélectionnés, impact sur le terrain [LAND_IMPACT]
[OBJ_COUNT] objets sélectionnés, impact sur le terrain [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]
</floater.string>
<floater.string name="status_remaining_capacity">
Capacité restante [LAND_CAPACITY].

View File

@ -40,7 +40,7 @@
Clicca e trascina per selezionare il terreno
</floater.string>
<floater.string name="status_selectcount">
[OBJ_COUNT] oggetti selezionati, impatto terreno [LAND_IMPACT]
[OBJ_COUNT] oggetti selezionati, impatto terreno [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]
</floater.string>
<floater.string name="status_remaining_capacity">
Capacità restante [LAND_CAPACITY].

View File

@ -40,7 +40,7 @@
土地をクリックし、ドラッグして選択
</floater.string>
<floater.string name="status_selectcount">
選択されているオブジェクトは [OBJ_COUNT] 個、土地の負荷は [LAND_IMPACT]
選択されているオブジェクトは [OBJ_COUNT] 個、土地の負荷は [LAND_IMPACT] [secondlife:///app/openfloater/object_weights 詳細]
</floater.string>
<floater.string name="status_remaining_capacity">
残りの許容数 [LAND_CAPACITY]。

View File

@ -40,7 +40,7 @@
Kliknij i przeciągnij, aby zaznaczyć teren
</floater.string>
<floater.string name="status_selectcount">
[OBJ_COUNT] zaznaczonych obiektów, wpływ na strefę: [LAND_IMPACT]
[OBJ_COUNT] zaznaczonych obiektów, wpływ na strefę: [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]
</floater.string>
<floater.string name="status_remaining_capacity">
Pojemność pozostała: [LAND_CAPACITY].

View File

@ -40,7 +40,7 @@
Clicar e arrastar para selecionar a terra
</floater.string>
<floater.string name="status_selectcount">
[OBJ_COUNT] objetos selecionados, impacto no terreno [LAND_IMPACT]
[OBJ_COUNT] objetos selecionados, impacto no terreno [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]
</floater.string>
<floater.string name="status_remaining_capacity">
Capacidade restante [LAND_CAPACITY].

View File

@ -40,7 +40,7 @@
Щелкните и перетащите для выделения земли
</floater.string>
<floater.string name="status_selectcount">
Выбрано объектов: [OBJ_COUNT], влияние на землю [LAND_IMPACT]
Выбрано объектов: [OBJ_COUNT], влияние на землю [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]
</floater.string>
<floater.string name="status_remaining_capacity">
Остаток емкости [LAND_CAPACITY].

View File

@ -40,7 +40,7 @@
Araziyi seçmek için tıklayın ve sürükleyin
</floater.string>
<floater.string name="status_selectcount">
[OBJ_COUNT] nesne seçili, [LAND_IMPACT] arazi etkisi
[OBJ_COUNT] nesne seçili, [LAND_IMPACT] arazi etkisi [secondlife:///app/openfloater/object_weights Ek bilgi]
</floater.string>
<floater.string name="status_remaining_capacity">
Kalan kapasite [LAND_CAPACITY].

View File

@ -40,7 +40,7 @@
按住並拖曳,可以選取土地
</floater.string>
<floater.string name="status_selectcount">
選取了 [OBJ_COUNT] 個物件,土地衝擊量 [LAND_IMPACT]
選取了 [OBJ_COUNT] 個物件,土地衝擊量 [LAND_IMPACT] [secondlife:///app/openfloater/object_weights 詳情]
</floater.string>
<floater.string name="status_remaining_capacity">
剩餘容納量 [LAND_CAPACITY]。