Files
SingularityViewer/indra/newview/llfloaterscriptlimits.cpp

1347 lines
38 KiB
C++

/**
* @file llfloaterscriptlimits.cpp
* @author Gabriel Lee
* @brief Implementation of the region info and controls floater and panels.
*
* $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 "llviewerprecompiledheaders.h"
#include "llfloaterscriptlimits.h"
// library includes
#include "llavatarnamecache.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
#include "message.h"
#include "llagent.h"
#include "llfloateravatarpicker.h"
#include "llfloaterland.h"
#include "llregionhandle.h"
#include "llscrolllistcolumn.h"
#include "llscrolllistctrl.h"
#include "llscrolllistitem.h"
#include "llparcel.h"
#include "lltabcontainer.h"
#include "lltracker.h"
#include "lltrans.h"
#include "llviewercontrol.h"
#include "lluictrlfactory.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
///----------------------------------------------------------------------------
/// LLFloaterScriptLimits
///----------------------------------------------------------------------------
// debug switches, won't work in release
#ifndef LL_RELEASE_FOR_DOWNLOAD
// dump responder replies to llinfos for debugging
//#define DUMP_REPLIES_TO_LLINFOS
#ifdef DUMP_REPLIES_TO_LLINFOS
#include "llsdserialize.h"
#include "llwindow.h"
#endif
// use fake LLSD responses to check the viewer side is working correctly
// I'm syncing this with the server side efforts so hopfully we can keep
// the to-ing and fro-ing between the two teams to a minimum
//#define USE_FAKE_RESPONSES
#ifdef USE_FAKE_RESPONSES
const S32 FAKE_NUMBER_OF_URLS = 329;
const S32 FAKE_AVAILABLE_URLS = 731;
const S32 FAKE_AMOUNT_OF_MEMORY = 66741;
const S32 FAKE_AVAILABLE_MEMORY = 895577;
#endif
#endif
const S32 SIZE_OF_ONE_KB = 1024;
LLFloaterScriptLimits::LLFloaterScriptLimits(const LLSD& seed)
: LLFloater(/*seed*/)
{
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_script_limits.xml");
}
BOOL LLFloaterScriptLimits::postBuild()
{
// a little cheap and cheerful - if there's an about land panel open default to showing parcel info,
// otherwise default to showing attachments (avatar appearance)
bool selectParcelPanel = false;
LLFloaterLand* instance = LLFloaterLand::getInstance();
if(instance)
{
if(instance->instanceVisible())
{
selectParcelPanel = true;
}
}
mTab = getChild<LLTabContainer>("scriptlimits_panels");
if(!mTab)
{
llwarns << "Error! couldn't get scriptlimits_panels, aborting Script Information setup" << llendl;
return FALSE;
}
// contruct the panels
std::string land_url = gAgent.getRegion()->getCapability("LandResources");
if (!land_url.empty())
{
LLPanelScriptLimitsRegionMemory* panel_memory;
panel_memory = new LLPanelScriptLimitsRegionMemory;
mInfoPanels.push_back(panel_memory);
LLUICtrlFactory::getInstance()->buildPanel(panel_memory, "panel_script_limits_region_memory.xml");
mTab->addTabPanel(panel_memory, "Region Memory");
}
std::string attachment_url = gAgent.getRegion()->getCapability("AttachmentResources");
if (!attachment_url.empty())
{
LLPanelScriptLimitsAttachment* panel_attachments = new LLPanelScriptLimitsAttachment;
mInfoPanels.push_back(panel_attachments);
LLUICtrlFactory::getInstance()->buildPanel(panel_attachments, "panel_script_limits_my_avatar.xml");
mTab->addTabPanel(panel_attachments, "My Avatar");
}
if(mInfoPanels.size() > 0)
{
mTab->selectTab(0);
}
if(!selectParcelPanel && (mInfoPanels.size() > 1))
{
mTab->selectTab(1);
}
return TRUE;
}
LLFloaterScriptLimits::~LLFloaterScriptLimits()
{
}
// public
void LLFloaterScriptLimits::refresh()
{
for(info_panels_t::iterator iter = mInfoPanels.begin();
iter != mInfoPanels.end(); ++iter)
{
(*iter)->refresh();
}
}
///----------------------------------------------------------------------------
// Base class for panels
///----------------------------------------------------------------------------
LLPanelScriptLimitsInfo::LLPanelScriptLimitsInfo()
: LLPanel()
{
}
// virtual
BOOL LLPanelScriptLimitsInfo::postBuild()
{
refresh();
return TRUE;
}
// virtual
void LLPanelScriptLimitsInfo::updateChild(LLUICtrl* child_ctr)
{
}
///----------------------------------------------------------------------------
// Responders
///----------------------------------------------------------------------------
void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content)
{
//we don't need to test with a fake response here (shouldn't anyway)
#ifdef DUMP_REPLIES_TO_LLINFOS
LLSDNotationStreamer notation_streamer(content);
std::ostringstream nice_llsd;
nice_llsd << notation_streamer;
OSMessageBox(nice_llsd.str(), "main cap response:", 0);
llinfos << "main cap response:" << content << llendl;
#endif
// at this point we have an llsd which should contain ether one or two urls to the services we want.
// first we look for the details service:
if(content.has("ScriptResourceDetails"))
{
LLHTTPClient::get(content["ScriptResourceDetails"], new fetchScriptLimitsRegionDetailsResponder(mInfo));
}
else
{
LLFloaterScriptLimits* instance = LLFloaterScriptLimits::findInstance();
if(!instance)
{
llwarns << "Failed to get llfloaterscriptlimits instance" << llendl;
}
}
// then the summary service:
if(content.has("ScriptResourceSummary"))
{
LLHTTPClient::get(content["ScriptResourceSummary"], new fetchScriptLimitsRegionSummaryResponder(mInfo));
}
}
void fetchScriptLimitsRegionInfoResponder::error(U32 status, const std::string& reason)
{
llwarns << "fetchScriptLimitsRegionInfoResponder error [status:" << status << "]: " << reason << llendl;
}
void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)
{
#ifdef USE_FAKE_RESPONSES
LLSD fake_content;
LLSD summary = LLSD::emptyMap();
LLSD available = LLSD::emptyArray();
LLSD available_urls = LLSD::emptyMap();
LLSD available_memory = LLSD::emptyMap();
LLSD used = LLSD::emptyArray();
LLSD used_urls = LLSD::emptyMap();
LLSD used_memory = LLSD::emptyMap();
used_urls["type"] = "urls";
used_urls["amount"] = FAKE_NUMBER_OF_URLS;
available_urls["type"] = "urls";
available_urls["amount"] = FAKE_AVAILABLE_URLS;
used_memory["type"] = "memory";
used_memory["amount"] = FAKE_AMOUNT_OF_MEMORY;
available_memory["type"] = "memory";
available_memory["amount"] = FAKE_AVAILABLE_MEMORY;
//summary response:{'summary':{'available':[{'amount':i731,'type':'urls'},{'amount':i895577,'type':'memory'},{'amount':i731,'type':'urls'},{'amount':i895577,'type':'memory'}],'used':[{'amount':i329,'type':'urls'},{'amount':i66741,'type':'memory'}]}}
used.append(used_urls);
used.append(used_memory);
available.append(available_urls);
available.append(available_memory);
summary["available"] = available;
summary["used"] = used;
fake_content["summary"] = summary;
const LLSD& content = fake_content;
#else
const LLSD& content = content_ref;
#endif
#ifdef DUMP_REPLIES_TO_LLINFOS
LLSDNotationStreamer notation_streamer(content);
std::ostringstream nice_llsd;
nice_llsd << notation_streamer;
OSMessageBox(nice_llsd.str(), "summary response:", 0);
llwarns << "summary response:" << *content << llendl;
#endif
LLFloaterScriptLimits* instance = LLFloaterScriptLimits::findInstance();
if(!instance)
{
llwarns << "Failed to get llfloaterscriptlimits instance" << llendl;
}
else
{
LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
if(tab)
{
LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
if(panel_memory)
{
panel_memory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
LLButton* btn = panel_memory->getChild<LLButton>("refresh_list_btn");
if(btn)
{
btn->setEnabled(true);
}
panel_memory->setRegionSummary(content);
}
}
}
}
void fetchScriptLimitsRegionSummaryResponder::error(U32 status, const std::string& reason)
{
llwarns << "fetchScriptLimitsRegionSummaryResponder error [status:" << status << "]: " << reason << llendl;
}
void fetchScriptLimitsRegionDetailsResponder::result(const LLSD& content_ref)
{
#ifdef USE_FAKE_RESPONSES
/*
Updated detail service, ** denotes field added:
result (map)
+-parcels (array of maps)
+-id (uuid)
+-local_id (S32)**
+-name (string)
+-owner_id (uuid) (in ERS as owner, but owner_id in code)
+-objects (array of maps)
+-id (uuid)
+-name (string)
+-owner_id (uuid) (in ERS as owner, in code as owner_id)
+-owner_name (sting)**
+-location (map)**
+-x (float)
+-y (float)
+-z (float)
+-resources (map) (this is wrong in the ERS but right in code)
+-type (string)
+-amount (int)
*/
LLSD fake_content;
LLSD resource = LLSD::emptyMap();
LLSD location = LLSD::emptyMap();
LLSD object = LLSD::emptyMap();
LLSD objects = LLSD::emptyArray();
LLSD parcel = LLSD::emptyMap();
LLSD parcels = LLSD::emptyArray();
resource["urls"] = FAKE_NUMBER_OF_URLS;
resource["memory"] = FAKE_AMOUNT_OF_MEMORY;
location["x"] = 128.0f;
location["y"] = 128.0f;
location["z"] = 0.0f;
object["id"] = LLUUID("d574a375-0c6c-fe3d-5733-da669465afc7");
object["name"] = "Gabs fake Object!";
object["owner_id"] = LLUUID("8dbf2d41-69a0-4e5e-9787-0c9d297bc570");
object["owner_name"] = "Gabs Linden";
object["location"] = location;
object["resources"] = resource;
objects.append(object);
parcel["id"] = LLUUID("da05fb28-0d20-e593-2728-bddb42dd0160");
parcel["local_id"] = 42;
parcel["name"] = "Gabriel Linden\'s Sub Plot";
parcel["objects"] = objects;
parcels.append(parcel);
fake_content["parcels"] = parcels;
const LLSD& content = fake_content;
#else
const LLSD& content = content_ref;
#endif
#ifdef DUMP_REPLIES_TO_LLINFOS
LLSDNotationStreamer notation_streamer(content);
std::ostringstream nice_llsd;
nice_llsd << notation_streamer;
OSMessageBox(nice_llsd.str(), "details response:", 0);
llinfos << "details response:" << content << llendl;
#endif
LLFloaterScriptLimits* instance = LLFloaterScriptLimits::findInstance();
if(!instance)
{
llwarns << "Failed to get llfloaterscriptlimits instance" << llendl;
}
else
{
LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
if(tab)
{
LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
if(panel_memory)
{
panel_memory->setRegionDetails(content);
}
else
{
llwarns << "Failed to get scriptlimits memory panel" << llendl;
}
}
else
{
llwarns << "Failed to get scriptlimits_panels" << llendl;
}
}
}
void fetchScriptLimitsRegionDetailsResponder::error(U32 status, const std::string& reason)
{
llwarns << "fetchScriptLimitsRegionDetailsResponder error [status:" << status << "]: " << reason << llendl;
}
void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref)
{
#ifdef USE_FAKE_RESPONSES
// just add the summary, as that's all I'm testing currently!
LLSD fake_content = LLSD::emptyMap();
LLSD summary = LLSD::emptyMap();
LLSD available = LLSD::emptyArray();
LLSD available_urls = LLSD::emptyMap();
LLSD available_memory = LLSD::emptyMap();
LLSD used = LLSD::emptyArray();
LLSD used_urls = LLSD::emptyMap();
LLSD used_memory = LLSD::emptyMap();
used_urls["type"] = "urls";
used_urls["amount"] = FAKE_NUMBER_OF_URLS;
available_urls["type"] = "urls";
available_urls["amount"] = FAKE_AVAILABLE_URLS;
used_memory["type"] = "memory";
used_memory["amount"] = FAKE_AMOUNT_OF_MEMORY;
available_memory["type"] = "memory";
available_memory["amount"] = FAKE_AVAILABLE_MEMORY;
used.append(used_urls);
used.append(used_memory);
available.append(available_urls);
available.append(available_memory);
summary["available"] = available;
summary["used"] = used;
fake_content["summary"] = summary;
fake_content["attachments"] = content_ref["attachments"];
const LLSD& content = fake_content;
#else
const LLSD& content = content_ref;
#endif
#ifdef DUMP_REPLIES_TO_LLINFOS
LLSDNotationStreamer notation_streamer(content);
std::ostringstream nice_llsd;
nice_llsd << notation_streamer;
OSMessageBox(nice_llsd.str(), "attachment response:", 0);
llinfos << "attachment response:" << content << llendl;
#endif
LLFloaterScriptLimits* instance = LLFloaterScriptLimits::findInstance();
if(!instance)
{
llwarns << "Failed to get llfloaterscriptlimits instance" << llendl;
}
else
{
LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
if(tab)
{
LLPanelScriptLimitsAttachment* panel = (LLPanelScriptLimitsAttachment*)tab->getChild<LLPanel>("script_limits_my_avatar_panel");
if(panel)
{
panel->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
LLButton* btn = panel->getChild<LLButton>("refresh_list_btn");
if(btn)
{
btn->setEnabled(true);
}
panel->setAttachmentDetails(content);
}
else
{
llwarns << "Failed to get script_limits_my_avatar_panel" << llendl;
}
}
else
{
llwarns << "Failed to get scriptlimits_panels" << llendl;
}
}
}
void fetchScriptLimitsAttachmentInfoResponder::error(U32 status, const std::string& reason)
{
llwarns << "fetchScriptLimitsAttachmentInfoResponder error [status:" << status << "]: " << reason << llendl;
}
///----------------------------------------------------------------------------
// Memory Panel
///----------------------------------------------------------------------------
LLPanelScriptLimitsRegionMemory::~LLPanelScriptLimitsRegionMemory()
{
if(!mParcelId.isNull())
{
LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this);
mParcelId.setNull();
}
};
BOOL LLPanelScriptLimitsRegionMemory::getLandScriptResources()
{
LLSD body;
std::string url = gAgent.getRegion()->getCapability("LandResources");
if (!url.empty())
{
body["parcel_id"] = mParcelId;
LLSD info;
info["parcel_id"] = mParcelId;
LLHTTPClient::post(url, body, new fetchScriptLimitsRegionInfoResponder(info));
return TRUE;
}
else
{
return FALSE;
}
}
void LLPanelScriptLimitsRegionMemory::processParcelInfo(const LLParcelData& parcel_data)
{
if(!getLandScriptResources())
{
std::string msg_error = LLTrans::getString("ScriptLimitsRequestError");
getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_error));
}
else
{
std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting");
getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_waiting));
}
}
void LLPanelScriptLimitsRegionMemory::setParcelID(const LLUUID& parcel_id)
{
if (!parcel_id.isNull())
{
if(!mParcelId.isNull())
{
LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this);
mParcelId.setNull();
}
mParcelId = parcel_id;
LLRemoteParcelInfoProcessor::getInstance()->addObserver(parcel_id, this);
LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id);
}
else
{
std::string msg_error = LLTrans::getString("ScriptLimitsRequestError");
getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_error));
}
}
// virtual
void LLPanelScriptLimitsRegionMemory::setErrorStatus(U32 status, const std::string& reason)
{
llwarns << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl;
}
// callback from the name cache with an owner name to add to the list
void LLPanelScriptLimitsRegionMemory::onNameCache(
const LLUUID& id,
const std::string& full_name)
{
LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list");
if(!list)
{
return;
}
std::string name;
LLAvatarNameCache::getPNSName(id, name);
std::vector<LLSD>::iterator id_itor;
for (id_itor = mObjectListItems.begin(); id_itor != mObjectListItems.end(); ++id_itor)
{
LLSD element = *id_itor;
if(element["owner_id"].asUUID() == id)
{
LLScrollListItem* item = list->getItem(element["id"].asUUID());
if(item)
{
item->getColumn(3)->setValue(LLSD(name));
element["columns"][3]["value"] = name;
}
}
}
}
void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content)
{
LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list");
if(!list)
{
llwarns << "Error getting the scripts_list control" << llendl;
return;
}
S32 number_parcels = content["parcels"].size();
LLStringUtil::format_map_t args_parcels;
args_parcels["[PARCELS]"] = llformat ("%d", number_parcels);
std::string msg_parcels = LLTrans::getString("ScriptLimitsParcelsOwned", args_parcels);
getChild<LLUICtrl>("parcels_listed")->setValue(LLSD(msg_parcels));
uuid_vec_t names_requested;
// This makes the assumption that all objects will have the same set
// of attributes, ie they will all have, or none will have locations
// This is a pretty safe assumption as it's reliant on server version.
bool has_locations = false;
bool has_local_ids = false;
for(S32 i = 0; i < number_parcels; i++)
{
std::string parcel_name = content["parcels"][i]["name"].asString();
LLUUID parcel_id = content["parcels"][i]["id"].asUUID();
S32 number_objects = content["parcels"][i]["objects"].size();
S32 local_id = 0;
if(content["parcels"][i].has("local_id"))
{
// if any locations are found flag that we can use them and turn on the highlight button
has_local_ids = true;
local_id = content["parcels"][i]["local_id"].asInteger();
}
for(S32 j = 0; j < number_objects; j++)
{
S32 size = content["parcels"][i]["objects"][j]["resources"]["memory"].asInteger() / SIZE_OF_ONE_KB;
S32 urls = content["parcels"][i]["objects"][j]["resources"]["urls"].asInteger();
std::string name_buf = content["parcels"][i]["objects"][j]["name"].asString();
LLUUID task_id = content["parcels"][i]["objects"][j]["id"].asUUID();
LLUUID owner_id = content["parcels"][i]["objects"][j]["owner_id"].asUUID();
// This field may not be sent by all server versions, but it's OK if
// it uses the LLSD default of false
bool is_group_owned = content["parcels"][i]["objects"][j]["is_group_owned"].asBoolean();
F32 location_x = 0.0f;
F32 location_y = 0.0f;
F32 location_z = 0.0f;
if(content["parcels"][i]["objects"][j].has("location"))
{
// if any locations are found flag that we can use them and turn on the highlight button
LLVector3 vec = ll_vector3_from_sd(content["parcels"][i]["objects"][j]["location"]);
has_locations = true;
location_x = vec.mV[0];
location_y = vec.mV[1];
location_z = vec.mV[2];
}
std::string owner_buf;
// in the future the server will give us owner names, so see if we're there yet:
if(content["parcels"][i]["objects"][j].has("owner_name"))
{
owner_buf = content["parcels"][i]["objects"][j]["owner_name"].asString();
}
// ...and if not use the slightly more painful method of disovery:
else
{
BOOL name_is_cached;
if (is_group_owned)
{
name_is_cached = gCacheName->getGroupName(owner_id, owner_buf);
}
else
{
name_is_cached = LLAvatarNameCache::getPNSName(owner_id, owner_buf); // username
}
if(!name_is_cached)
{
if(std::find(names_requested.begin(), names_requested.end(), owner_id) == names_requested.end())
{
names_requested.push_back(owner_id);
gCacheName->get(owner_id, is_group_owned, // username
boost::bind(&LLPanelScriptLimitsRegionMemory::onNameCache,
this, _1, _2));
}
}
}
LLSD item_params;
item_params["id"] = task_id;
item_params["columns"][0]["column"] = "size";
item_params["columns"][0]["value"] = size;
item_params["columns"][1]["column"] = "urls";
item_params["columns"][1]["value"] = urls;
item_params["columns"][2]["column"] = "name";
item_params["columns"][2]["value"] = name_buf;
item_params["columns"][3]["column"] = "owner";
item_params["columns"][3]["value"] = owner_buf;
item_params["columns"][4]["column"] = "parcel";
item_params["columns"][4]["value"] = parcel_name;
item_params["columns"][5]["column"] = "location";
item_params["columns"][5]["value"] = has_locations
? llformat("<%0.1f,%0.1f,%0.1f>", location_x, location_y, location_z)
: "";
list->addElement(item_params);
LLSD element;
element["owner_id"] = owner_id;
element["id"] = task_id;
element["local_id"] = local_id;
mObjectListItems.push_back(element);
}
}
if (has_locations)
{
LLButton* btn = getChild<LLButton>("highlight_btn");
if(btn)
{
btn->setVisible(true);
}
}
if (has_local_ids)
{
LLButton* btn = getChild<LLButton>("return_btn");
if(btn)
{
btn->setVisible(true);
}
}
// save the structure to make object return easier
mContent = content;
}
void LLPanelScriptLimitsRegionMemory::setRegionSummary(LLSD content)
{
if(content["summary"]["used"][0]["type"].asString() == std::string("memory"))
{
mParcelMemoryUsed = content["summary"]["used"][0]["amount"].asInteger() / SIZE_OF_ONE_KB;
mParcelMemoryMax = content["summary"]["available"][0]["amount"].asInteger() / SIZE_OF_ONE_KB;
mGotParcelMemoryUsed = true;
}
else if(content["summary"]["used"][1]["type"].asString() == std::string("memory"))
{
mParcelMemoryUsed = content["summary"]["used"][1]["amount"].asInteger() / SIZE_OF_ONE_KB;
mParcelMemoryMax = content["summary"]["available"][1]["amount"].asInteger() / SIZE_OF_ONE_KB;
mGotParcelMemoryUsed = true;
}
else
{
llwarns << "summary doesn't contain memory info" << llendl;
return;
}
if(content["summary"]["used"][0]["type"].asString() == std::string("urls"))
{
mParcelURLsUsed = content["summary"]["used"][0]["amount"].asInteger();
mParcelURLsMax = content["summary"]["available"][0]["amount"].asInteger();
mGotParcelURLsUsed = true;
}
else if(content["summary"]["used"][1]["type"].asString() == std::string("urls"))
{
mParcelURLsUsed = content["summary"]["used"][1]["amount"].asInteger();
mParcelURLsMax = content["summary"]["available"][1]["amount"].asInteger();
mGotParcelURLsUsed = true;
}
else
{
llwarns << "summary doesn't contain urls info" << llendl;
return;
}
if((mParcelMemoryUsed >= 0) && (mParcelMemoryMax >= 0))
{
S32 parcel_memory_available = mParcelMemoryMax - mParcelMemoryUsed;
LLStringUtil::format_map_t args_parcel_memory;
args_parcel_memory["[COUNT]"] = llformat ("%d", mParcelMemoryUsed);
args_parcel_memory["[MAX]"] = llformat ("%d", mParcelMemoryMax);
args_parcel_memory["[AVAILABLE]"] = llformat ("%d", parcel_memory_available);
std::string msg_parcel_memory = LLTrans::getString("ScriptLimitsMemoryUsed", args_parcel_memory);
getChild<LLUICtrl>("memory_used")->setValue(LLSD(msg_parcel_memory));
}
if((mParcelURLsUsed >= 0) && (mParcelURLsMax >= 0))
{
S32 parcel_urls_available = mParcelURLsMax - mParcelURLsUsed;
LLStringUtil::format_map_t args_parcel_urls;
args_parcel_urls["[COUNT]"] = llformat ("%d", mParcelURLsUsed);
args_parcel_urls["[MAX]"] = llformat ("%d", mParcelURLsMax);
args_parcel_urls["[AVAILABLE]"] = llformat ("%d", parcel_urls_available);
std::string msg_parcel_urls = LLTrans::getString("ScriptLimitsURLsUsed", args_parcel_urls);
getChild<LLUICtrl>("urls_used")->setValue(LLSD(msg_parcel_urls));
}
}
BOOL LLPanelScriptLimitsRegionMemory::postBuild()
{
childSetAction("refresh_list_btn", onClickRefresh, this);
childSetAction("highlight_btn", onClickHighlight, this);
childSetAction("return_btn", onClickReturn, this);
std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting");
getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_waiting));
LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list");
if(!list)
{
return FALSE;
}
//set all columns to resizable mode even if some columns will be empty
for(S32 column = 0; column < list->getNumColumns(); column++)
{
LLScrollListColumn* columnp = list->getColumn(column);
columnp->mHeader->setHasResizableElement(TRUE);
}
return StartRequestChain();
}
BOOL LLPanelScriptLimitsRegionMemory::StartRequestChain()
{
LLUUID region_id;
LLFloaterLand* instance = LLFloaterLand::getInstance();
if(!instance)
{
getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
//might have to do parent post build here
//if not logic below could use early outs
return FALSE;
}
LLParcel* parcel = instance->getCurrentSelectedParcel();
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
if (!parcel) //Pretend we have the parcel we're on selected.
{
parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
region = gAgent.getRegion();
}
LLUUID current_region_id = gAgent.getRegion()->getRegionID();
if ((region) && (parcel))
{
LLVector3 parcel_center = parcel->getCenterpoint();
region_id = region->getRegionID();
if(region_id != current_region_id)
{
std::string msg_wrong_region = LLTrans::getString("ScriptLimitsRequestWrongRegion");
getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_wrong_region));
return FALSE;
}
LLVector3d pos_global = region->getCenterGlobal();
LLSD body;
std::string url = region->getCapability("RemoteParcelRequest");
if (!url.empty())
{
body["location"] = ll_sd_from_vector3(parcel_center);
if (!region_id.isNull())
{
body["region_id"] = region_id;
}
if (!pos_global.isExactlyZero())
{
U64 region_handle = to_region_handle(pos_global);
body["region_handle"] = ll_sd_from_U64(region_handle);
}
LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle()));
}
else
{
llwarns << "Can't get parcel info for script information request" << region_id
<< ". Region: " << region->getName()
<< " does not support RemoteParcelRequest" << llendl;
std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestError");
getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_waiting));
}
}
else
{
std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestNoParcelSelected");
getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_waiting));
}
return LLPanelScriptLimitsInfo::postBuild();
}
void LLPanelScriptLimitsRegionMemory::clearList()
{
LLCtrlListInterface *list = childGetListInterface("scripts_list");
if (list)
{
list->operateOnAll(LLCtrlListInterface::OP_DELETE);
}
mGotParcelMemoryUsed = false;
mGotParcelMemoryMax = false;
mGotParcelURLsUsed = false;
mGotParcelURLsMax = false;
std::string msg_empty_string("");
getChild<LLUICtrl>("memory_used")->setValue(LLSD(msg_empty_string));
getChild<LLUICtrl>("urls_used")->setValue(LLSD(msg_empty_string));
getChild<LLUICtrl>("parcels_listed")->setValue(LLSD(msg_empty_string));
mObjectListItems.clear();
}
// static
void LLPanelScriptLimitsRegionMemory::onClickRefresh(void* userdata)
{
LLFloaterScriptLimits* instance = LLFloaterScriptLimits::findInstance();
if(instance)
{
LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
if(tab)
{
LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
if(panel_memory)
{
//To stop people from hammering the refesh button and accidentally dosing themselves - enough requests can crash the viewer!
//turn the button off, then turn it on when we get a response
LLButton* btn = panel_memory->getChild<LLButton>("refresh_list_btn");
if(btn)
{
btn->setEnabled(false);
}
panel_memory->clearList();
panel_memory->StartRequestChain();
}
}
return;
}
else
{
llwarns << "could not find LLPanelScriptLimitsRegionMemory instance after refresh button clicked" << llendl;
return;
}
}
void LLPanelScriptLimitsRegionMemory::showBeacon()
{
LLScrollListCtrl* list = getChild<LLScrollListCtrl>("scripts_list");
if (!list) return;
LLScrollListItem* first_selected = list->getFirstSelected();
if (!first_selected) return;
std::string name = first_selected->getColumn(2)->getValue().asString();
std::string pos_string = first_selected->getColumn(5)->getValue().asString();
F32 x, y, z;
S32 matched = sscanf(pos_string.c_str(), "<%g,%g,%g>", &x, &y, &z);
if (matched != 3) return;
LLVector3 pos_agent(x, y, z);
LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent);
std::string tooltip("");
LLTracker::trackLocation(pos_global, name, tooltip, LLTracker::LOCATION_ITEM);
}
// static
void LLPanelScriptLimitsRegionMemory::onClickHighlight(void* userdata)
{
LLFloaterScriptLimits* instance = LLFloaterScriptLimits::findInstance();
if(instance)
{
LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
if(tab)
{
LLPanelScriptLimitsRegionMemory* panel = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
if(panel)
{
panel->showBeacon();
}
}
return;
}
else
{
llwarns << "could not find LLPanelScriptLimitsRegionMemory instance after highlight button clicked" << llendl;
return;
}
}
void LLPanelScriptLimitsRegionMemory::returnObjectsFromParcel(S32 local_id)
{
LLMessageSystem *msg = gMessageSystem;
LLViewerRegion* region = gAgent.getRegion();
if (!region) return;
LLCtrlListInterface *list = childGetListInterface("scripts_list");
if (!list || list->getItemCount() == 0) return;
std::vector<LLSD>::iterator id_itor;
bool start_message = true;
for (id_itor = mObjectListItems.begin(); id_itor != mObjectListItems.end(); ++id_itor)
{
LLSD element = *id_itor;
if (!list->isSelected(element["id"].asUUID()))
{
// Selected only
continue;
}
if(element["local_id"].asInteger() != local_id)
{
// Not the parcel we are looking for
continue;
}
if (start_message)
{
msg->newMessageFast(_PREHASH_ParcelReturnObjects);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
msg->nextBlockFast(_PREHASH_ParcelData);
msg->addS32Fast(_PREHASH_LocalID, element["local_id"].asInteger());
msg->addU32Fast(_PREHASH_ReturnType, RT_LIST);
start_message = false;
}
msg->nextBlockFast(_PREHASH_TaskIDs);
msg->addUUIDFast(_PREHASH_TaskID, element["id"].asUUID());
if (msg->isSendFullFast(_PREHASH_TaskIDs))
{
msg->sendReliable(region->getHost());
start_message = true;
}
}
if (!start_message)
{
msg->sendReliable(region->getHost());
}
}
void LLPanelScriptLimitsRegionMemory::returnObjects()
{
if(!mContent.has("parcels"))
{
return;
}
S32 number_parcels = mContent["parcels"].size();
// a message per parcel containing all objects to be returned from that parcel
for(S32 i = 0; i < number_parcels; i++)
{
S32 local_id = 0;
if(mContent["parcels"][i].has("local_id"))
{
local_id = mContent["parcels"][i]["local_id"].asInteger();
returnObjectsFromParcel(local_id);
}
}
onClickRefresh(NULL);
}
// static
void LLPanelScriptLimitsRegionMemory::onClickReturn(void* userdata)
{
LLFloaterScriptLimits* instance = LLFloaterScriptLimits::findInstance();
if(instance)
{
LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
if(tab)
{
LLPanelScriptLimitsRegionMemory* panel = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
if(panel)
{
panel->returnObjects();
}
}
return;
}
else
{
llwarns << "could not find LLPanelScriptLimitsRegionMemory instance after highlight button clicked" << llendl;
return;
}
}
///----------------------------------------------------------------------------
// Attachment Panel
///----------------------------------------------------------------------------
BOOL LLPanelScriptLimitsAttachment::requestAttachmentDetails()
{
LLSD body;
std::string url = gAgent.getRegion()->getCapability("AttachmentResources");
if (!url.empty())
{
LLHTTPClient::get(url, body, new fetchScriptLimitsAttachmentInfoResponder());
return TRUE;
}
else
{
return FALSE;
}
}
void LLPanelScriptLimitsAttachment::setAttachmentDetails(LLSD content)
{
LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list");
if(!list)
{
return;
}
S32 number_attachments = content["attachments"].size();
for(int i = 0; i < number_attachments; i++)
{
std::string humanReadableLocation = "";
if(content["attachments"][i].has("location"))
{
std::string actualLocation = content["attachments"][i]["location"];
humanReadableLocation = LLTrans::getString(actualLocation.c_str());
}
S32 number_objects = content["attachments"][i]["objects"].size();
for(int j = 0; j < number_objects; j++)
{
LLUUID task_id = content["attachments"][i]["objects"][j]["id"].asUUID();
S32 size = 0;
if(content["attachments"][i]["objects"][j]["resources"].has("memory"))
{
size = content["attachments"][i]["objects"][j]["resources"]["memory"].asInteger() / SIZE_OF_ONE_KB;
}
S32 urls = 0;
if(content["attachments"][i]["objects"][j]["resources"].has("urls"))
{
urls = content["attachments"][i]["objects"][j]["resources"]["urls"].asInteger();
}
std::string name = content["attachments"][i]["objects"][j]["name"].asString();
LLSD element;
element["id"] = task_id;
element["columns"][0]["column"] = "size";
element["columns"][0]["value"] = llformat("%d", size);
element["columns"][0]["font"] = "SANSSERIF";
element["columns"][1]["column"] = "urls";
element["columns"][1]["value"] = llformat("%d", urls);
element["columns"][1]["font"] = "SANSSERIF";
element["columns"][2]["column"] = "name";
element["columns"][2]["value"] = name;
element["columns"][2]["font"] = "SANSSERIF";
element["columns"][3]["column"] = "location";
element["columns"][3]["value"] = humanReadableLocation;
element["columns"][3]["font"] = "SANSSERIF";
list->addElement(element);
}
}
setAttachmentSummary(content);
getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
LLButton* btn = getChild<LLButton>("refresh_list_btn");
if(btn)
{
btn->setEnabled(true);
}
}
BOOL LLPanelScriptLimitsAttachment::postBuild()
{
childSetAction("refresh_list_btn", onClickRefresh, this);
std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting");
getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_waiting));
return requestAttachmentDetails();
}
void LLPanelScriptLimitsAttachment::clearList()
{
LLCtrlListInterface *list = childGetListInterface("scripts_list");
if (list)
{
list->operateOnAll(LLCtrlListInterface::OP_DELETE);
}
std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting");
getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_waiting));
}
void LLPanelScriptLimitsAttachment::setAttachmentSummary(LLSD content)
{
if(content["summary"]["used"][0]["type"].asString() == std::string("memory"))
{
mAttachmentMemoryUsed = content["summary"]["used"][0]["amount"].asInteger() / SIZE_OF_ONE_KB;
mAttachmentMemoryMax = content["summary"]["available"][0]["amount"].asInteger() / SIZE_OF_ONE_KB;
mGotAttachmentMemoryUsed = true;
}
else if(content["summary"]["used"][1]["type"].asString() == std::string("memory"))
{
mAttachmentMemoryUsed = content["summary"]["used"][1]["amount"].asInteger() / SIZE_OF_ONE_KB;
mAttachmentMemoryMax = content["summary"]["available"][1]["amount"].asInteger() / SIZE_OF_ONE_KB;
mGotAttachmentMemoryUsed = true;
}
else
{
llwarns << "attachment details don't contain memory summary info" << llendl;
return;
}
if(content["summary"]["used"][0]["type"].asString() == std::string("urls"))
{
mAttachmentURLsUsed = content["summary"]["used"][0]["amount"].asInteger();
mAttachmentURLsMax = content["summary"]["available"][0]["amount"].asInteger();
mGotAttachmentURLsUsed = true;
}
else if(content["summary"]["used"][1]["type"].asString() == std::string("urls"))
{
mAttachmentURLsUsed = content["summary"]["used"][1]["amount"].asInteger();
mAttachmentURLsMax = content["summary"]["available"][1]["amount"].asInteger();
mGotAttachmentURLsUsed = true;
}
else
{
llwarns << "attachment details don't contain urls summary info" << llendl;
return;
}
if((mAttachmentMemoryUsed >= 0) && (mAttachmentMemoryMax >= 0))
{
S32 attachment_memory_available = mAttachmentMemoryMax - mAttachmentMemoryUsed;
LLStringUtil::format_map_t args_attachment_memory;
args_attachment_memory["[COUNT]"] = llformat ("%d", mAttachmentMemoryUsed);
args_attachment_memory["[MAX]"] = llformat ("%d", mAttachmentMemoryMax);
args_attachment_memory["[AVAILABLE]"] = llformat ("%d", attachment_memory_available);
std::string msg_attachment_memory = LLTrans::getString("ScriptLimitsMemoryUsed", args_attachment_memory);
getChild<LLUICtrl>("memory_used")->setValue(LLSD(msg_attachment_memory));
}
if((mAttachmentURLsUsed >= 0) && (mAttachmentURLsMax >= 0))
{
S32 attachment_urls_available = mAttachmentURLsMax - mAttachmentURLsUsed;
LLStringUtil::format_map_t args_attachment_urls;
args_attachment_urls["[COUNT]"] = llformat ("%d", mAttachmentURLsUsed);
args_attachment_urls["[MAX]"] = llformat ("%d", mAttachmentURLsMax);
args_attachment_urls["[AVAILABLE]"] = llformat ("%d", attachment_urls_available);
std::string msg_attachment_urls = LLTrans::getString("ScriptLimitsURLsUsed", args_attachment_urls);
getChild<LLUICtrl>("urls_used")->setValue(LLSD(msg_attachment_urls));
}
}
// static
void LLPanelScriptLimitsAttachment::onClickRefresh(void* userdata)
{
LLFloaterScriptLimits* instance = LLFloaterScriptLimits::findInstance();
if(instance)
{
LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
LLPanelScriptLimitsAttachment* panel_attachments = (LLPanelScriptLimitsAttachment*)tab->getChild<LLPanel>("script_limits_my_avatar_panel");
LLButton* btn = panel_attachments->getChild<LLButton>("refresh_list_btn");
//To stop people from hammering the refesh button and accidentally dosing themselves - enough requests can crash the viewer!
//turn the button off, then turn it on when we get a response
if(btn)
{
btn->setEnabled(false);
}
panel_attachments->clearList();
panel_attachments->requestAttachmentDetails();
return;
}
else
{
llwarns << "could not find LLPanelScriptLimitsRegionMemory instance after refresh button clicked" << llendl;
return;
}
}