/** * @file llfloatertopobjects.cpp * @brief Shows top colliders, top scripts, etc. * * $LicenseInfo:firstyear=2005&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 "llfloatertopobjects.h" // library includes #include "message.h" #include "llavatarnamecache.h" #include "llfontgl.h" #include "llagent.h" #include "llbutton.h" #include "llfloatergodtools.h" #include "llfloaterreg.h" #include "llnotificationsutil.h" #include "llparcel.h" #include "llscrolllistctrl.h" #include "llscrolllistitem.h" #include "llscrolllistcell.h" #include "lllineeditor.h" #include "lltextbox.h" #include "lltracker.h" #include "llviewermessage.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "lluictrlfactory.h" #include "llviewerobjectlist.h" #include "llviewerwindow.h" #include "llfloaterregioninfo.h" //LLFloaterTopObjects* LLFloaterTopObjects::sInstance = NULL; // Globals // const U32 TIME_STR_LENGTH = 30; /* // static void LLFloaterTopObjects::show() { if (sInstance) { sInstance->setVisibleAndFrontmost(); return; } sInstance = new LLFloaterTopObjects(); sInstance->center(); } */ LLFloaterTopObjects::LLFloaterTopObjects(const LLSD& key) : LLFloater(key), mInitialized(false), mtotalScore(0.f) { mCommitCallbackRegistrar.add("TopObjects.ShowBeacon", { boost::bind(&LLFloaterTopObjects::onClickShowBeacon, this) }); mCommitCallbackRegistrar.add("TopObjects.ReturnSelected", { boost::bind(&LLFloaterTopObjects::onReturnSelected, this), cb_info::UNTRUSTED_BLOCK }); mCommitCallbackRegistrar.add("TopObjects.ReturnAll", { boost::bind(&LLFloaterTopObjects::onReturnAll, this), cb_info::UNTRUSTED_BLOCK }); mCommitCallbackRegistrar.add("TopObjects.Refresh", { boost::bind(&LLFloaterTopObjects::onRefresh, this), cb_info::UNTRUSTED_THROTTLE }); mCommitCallbackRegistrar.add("TopObjects.GetByObjectName", { boost::bind(&LLFloaterTopObjects::onGetByObjectName, this), cb_info::UNTRUSTED_THROTTLE }); mCommitCallbackRegistrar.add("TopObjects.GetByOwnerName", { boost::bind(&LLFloaterTopObjects::onGetByOwnerName, this), cb_info::UNTRUSTED_THROTTLE }); mCommitCallbackRegistrar.add("TopObjects.GetByParcelName", { boost::bind(&LLFloaterTopObjects::onGetByParcelName, this), cb_info::UNTRUSTED_THROTTLE }); mCommitCallbackRegistrar.add("TopObjects.CommitObjectsList",{ boost::bind(&LLFloaterTopObjects::onCommitObjectsList, this), cb_info::UNTRUSTED_THROTTLE }); mCommitCallbackRegistrar.add("TopObjects.TeleportToSelected", { boost::bind(&LLFloaterTopObjects::teleportToSelectedObject, this), cb_info::UNTRUSTED_THROTTLE }); } LLFloaterTopObjects::~LLFloaterTopObjects() { } // virtual bool LLFloaterTopObjects::postBuild() { mObjectsScrollList = getChild("objects_list"); mObjectsScrollList->setFocus(true); mObjectsScrollList->setDoubleClickCallback(onDoubleClickObjectsList, this); mObjectsScrollList->setCommitOnSelectionChange(true); mObjectsScrollList->setCommitCallback(boost::bind(&LLFloaterTopObjects::onSelectionChanged, this)); setDefaultBtn("show_beacon_btn"); mCurrentMode = STAT_REPORT_TOP_SCRIPTS; mFlags = 0; mFilter.clear(); return true; } // static void LLFloaterTopObjects::setMode(U32 mode) { LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance("top_objects"); if(!instance) return; instance->mCurrentMode = mode; } // static void LLFloaterTopObjects::handle_land_reply(LLMessageSystem* msg, void** data) { LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance("top_objects"); if(instance && instance->isInVisibleChain()) { instance->handleReply(msg, data); //HACK: for some reason sometimes top scripts originally comes back //with no results even though they're there if (!instance->mObjectListIDs.size() && !instance->mInitialized) { instance->onRefresh(); instance->mInitialized = true; } } else { LLFloaterRegionInfo* region_info_floater = LLFloaterReg::getTypedInstance("region_info"); if(region_info_floater) { region_info_floater->enableTopButtons(); } } } void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) { U32 request_flags; U32 total_count; U64 total_memory = 0; msg->getU32Fast(_PREHASH_RequestData, _PREHASH_RequestFlags, request_flags); msg->getU32Fast(_PREHASH_RequestData, _PREHASH_TotalObjectCount, total_count); msg->getU32Fast(_PREHASH_RequestData, _PREHASH_ReportType, mCurrentMode); LLScrollListCtrl *list = getChild("objects_list"); S32 block_count = msg->getNumberOfBlocks("ReportData"); for (S32 block = 0; block < block_count; ++block) { U32 task_local_id; U32 time_stamp = 0; LLUUID task_id; F32 location_x, location_y, location_z; F32 score; std::string name_buf; std::string owner_buf; std::string parcel_buf("unknown"); F32 mono_score = 0.f; bool have_extended_data = false; S32 public_urls = 0; F32 script_memory = 0.f; msg->getU32Fast(_PREHASH_ReportData, _PREHASH_TaskLocalID, task_local_id, block); msg->getUUIDFast(_PREHASH_ReportData, _PREHASH_TaskID, task_id, block); msg->getF32Fast(_PREHASH_ReportData, _PREHASH_LocationX, location_x, block); msg->getF32Fast(_PREHASH_ReportData, _PREHASH_LocationY, location_y, block); msg->getF32Fast(_PREHASH_ReportData, _PREHASH_LocationZ, location_z, block); msg->getF32Fast(_PREHASH_ReportData, _PREHASH_Score, score, block); msg->getStringFast(_PREHASH_ReportData, _PREHASH_TaskName, name_buf, block); msg->getStringFast(_PREHASH_ReportData, _PREHASH_OwnerName, owner_buf, block); if(msg->has("DataExtended")) { have_extended_data = true; msg->getU32("DataExtended", "TimeStamp", time_stamp, block); msg->getF32("DataExtended", "MonoScore", mono_score, block); msg->getS32("DataExtended", "PublicURLs", public_urls, block); std::string parcel_name; F32 script_size = 0.f; msg->getString("DataExtended", "ParcelName", parcel_name, block); msg->getF32("DataExtended", "Size", script_size, block); if (parcel_name.size() > 0 || script_size > 0) { parcel_buf = parcel_name; script_memory = script_size; total_memory += script_size; } } LLSD element; element["id"] = task_id; LLSD columns; S32 column_num = 0; columns[column_num]["column"] = "score"; columns[column_num]["value"] = llformat("%0.3f", score); columns[column_num++]["font"] = "SANSSERIF"; columns[column_num]["column"] = "name"; columns[column_num]["value"] = name_buf; columns[column_num++]["font"] = "SANSSERIF"; // Owner names can have trailing spaces sent from server LLStringUtil::trim(owner_buf); // *TODO: Send owner_id from server and look up display name owner_buf = LLCacheName::buildUsername(owner_buf); columns[column_num]["column"] = "owner"; columns[column_num]["value"] = owner_buf; columns[column_num++]["font"] = "SANSSERIF"; columns[column_num]["column"] = "location"; columns[column_num]["value"] = llformat("<%0.f, %0.f, %0.f>", location_x, location_y, location_z); columns[column_num++]["font"] = "SANSSERIF"; columns[column_num]["column"] = "parcel"; columns[column_num]["value"] = parcel_buf; columns[column_num++]["font"] = "SANSSERIF"; columns[column_num]["column"] = "time"; columns[column_num]["type"] = "date"; columns[column_num]["value"] = LLDate((time_t)time_stamp); columns[column_num++]["font"] = "SANSSERIF"; if (mCurrentMode == STAT_REPORT_TOP_SCRIPTS && have_extended_data) { columns[column_num]["column"] = "memory"; columns[column_num]["value"] = llformat("%0.0f", (script_memory / 1024.f)); columns[column_num++]["font"] = "SANSSERIF"; columns[column_num]["column"] = "URLs"; columns[column_num]["value"] = llformat("%d", public_urls); columns[column_num++]["font"] = "SANSSERIF"; } element["columns"] = columns; list->addElement(element); mObjectListData.append(element); mObjectListIDs.push_back(task_id); mtotalScore += score; } if (total_count == 0 && list->getItemCount() == 0) { list->setCommentText(getString("none_descriptor")); } else { list->selectFirstItem(); } if (mCurrentMode == STAT_REPORT_TOP_SCRIPTS) { setTitle(getString("top_scripts_title")); list->setColumnLabel("score", getString("scripts_score_label")); LLUIString format = getString("top_scripts_text"); total_memory /= 1024; format.setArg("[MEMORY]", llformat("%ld", total_memory)); format.setArg("[COUNT]", llformat("%d", total_count)); format.setArg("[TIME]", llformat("%0.3f", mtotalScore)); getChild("title_text")->setValue(LLSD(format)); list->setColumnLabel("URLs", getString("URLs")); list->setColumnLabel("memory", getString("memory")); } else { setTitle(getString("top_colliders_title")); list->setColumnLabel("score", getString("colliders_score_label")); list->setColumnLabel("URLs", ""); list->setColumnLabel("memory", ""); LLUIString format = getString("top_colliders_text"); format.setArg("[COUNT]", llformat("%d", total_count)); getChild("title_text")->setValue(LLSD(format)); } LLFloaterRegionInfo* region_info_floater = LLFloaterReg::getTypedInstance("region_info"); if(region_info_floater) { region_info_floater->enableTopButtons(); } getChildView("refresh_btn")->setEnabled(true); } void LLFloaterTopObjects::onCommitObjectsList() { updateSelectionInfo(); } void LLFloaterTopObjects::updateSelectionInfo() { LLScrollListCtrl* list = getChild("objects_list"); if (!list) return; LLUUID object_id = list->getCurrentID(); if (object_id.isNull()) return; std::string object_id_string = object_id.asString(); getChild("id_editor")->setValue(LLSD(object_id_string)); LLScrollListItem* sli = list->getFirstSelected(); llassert(sli); if (sli) { getChild("object_name_editor")->setValue(sli->getColumn(1)->getValue().asString()); getChild("owner_name_editor")->setValue(sli->getColumn(2)->getValue().asString()); getChild("parcel_name_editor")->setValue(sli->getColumn(4)->getValue().asString()); } } // static void LLFloaterTopObjects::onDoubleClickObjectsList(void* data) { LLFloaterTopObjects* self = (LLFloaterTopObjects*)data; self->showBeacon(); } // static void LLFloaterTopObjects::onClickShowBeacon() { showBeacon(); } void LLFloaterTopObjects::returnObjects(bool all) { LLMessageSystem *msg = gMessageSystem; LLViewerRegion* region = gAgent.getRegion(); if (!region) return; LLCtrlListInterface *list = getChild("objects_list")->getListInterface(); if (!list || list->getItemCount() == 0) return; uuid_vec_t::iterator id_itor; bool start_message = true; for (id_itor = mObjectListIDs.begin(); id_itor != mObjectListIDs.end(); ++id_itor) { LLUUID task_id = *id_itor; if (!all && !list->isSelected(task_id)) { // Selected only 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, -1); // Whole region msg->addS32Fast(_PREHASH_ReturnType, RT_NONE); start_message = false; } msg->nextBlockFast(_PREHASH_TaskIDs); msg->addUUIDFast(_PREHASH_TaskID, task_id); if (msg->isSendFullFast(_PREHASH_TaskIDs)) { msg->sendReliable(region->getHost()); start_message = true; } } if (!start_message) { msg->sendReliable(region->getHost()); } } //static bool LLFloaterTopObjects::callbackReturnAll(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance("top_objects"); if(!instance) return false; if (option == 0) { instance->returnObjects(true); } return false; } void LLFloaterTopObjects::onReturnAll() { LLNotificationsUtil::add("ReturnAllTopObjects", LLSD(), LLSD(), &callbackReturnAll); } void LLFloaterTopObjects::onReturnSelected() { returnObjects(false); } void LLFloaterTopObjects::clearList() { LLCtrlListInterface *list = childGetListInterface("objects_list"); if (list) { list->operateOnAll(LLCtrlListInterface::OP_DELETE); } mObjectListData.clear(); mObjectListIDs.clear(); mtotalScore = 0.f; onSelectionChanged(); } void LLFloaterTopObjects::onRefresh() { U32 mode = STAT_REPORT_TOP_SCRIPTS; U32 flags = 0; std::string filter = ""; mode = mCurrentMode; flags = mFlags; filter = mFilter; clearList(); LLMessageSystem *msg = gMessageSystem; msg->newMessageFast(_PREHASH_LandStatRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); msg->nextBlockFast(_PREHASH_RequestData); msg->addU32Fast(_PREHASH_ReportType, mode); msg->addU32Fast(_PREHASH_RequestFlags, flags); msg->addStringFast(_PREHASH_Filter, filter); msg->addS32Fast(_PREHASH_ParcelLocalID, 0); LLFloaterRegionInfo* region_info_floater = LLFloaterReg::getTypedInstance("region_info"); if(region_info_floater) { region_info_floater->disableTopButtons(); } disableRefreshBtn(); msg->sendReliable(gAgent.getRegionHost()); mFilter.clear(); mFlags = 0; } void LLFloaterTopObjects::disableRefreshBtn() { getChildView("refresh_btn")->setEnabled(false); } void LLFloaterTopObjects::onGetByObjectName() { mFlags = STAT_FILTER_BY_OBJECT; mFilter = getChild("object_name_editor")->getValue().asString(); onRefresh(); } void LLFloaterTopObjects::onGetByOwnerName() { mFlags = STAT_FILTER_BY_OWNER; mFilter = getChild("owner_name_editor")->getValue().asString(); onRefresh(); } void LLFloaterTopObjects::onGetByParcelName() { mFlags = STAT_FILTER_BY_PARCEL_NAME; mFilter = getChild("parcel_name_editor")->getValue().asString(); onRefresh(); } void LLFloaterTopObjects::showBeacon() { LLScrollListCtrl* list = getChild("objects_list"); if (!list) return; LLScrollListItem* first_selected = list->getFirstSelected(); if (!first_selected) return; std::string name = first_selected->getColumn(1)->getValue().asString(); std::string pos_string = first_selected->getColumn(3)->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); } void LLFloaterTopObjects::teleportToSelectedObject() { std::vector selected_items = mObjectsScrollList->getAllSelected(); if (selected_items.size() == 1) { LLScrollListItem* first_selected = selected_items.front(); LLVector3d teleport_location; LLViewerObject *viewer_object = gObjectList.findObject(first_selected->getUUID()); if (viewer_object == NULL) { // If we cannot find the object in the viewer list, teleport to the last reported position std::string pos_string = first_selected->getColumn(3)->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); teleport_location = gAgent.getPosGlobalFromAgent(pos_agent); } else { // If we can find the object in the viewer list, teleport to the known current position teleport_location = viewer_object->getPositionGlobal(); } gAgent.teleportViaLocationLookAt(teleport_location); } } void LLFloaterTopObjects::onSelectionChanged() { getChildView("teleport_btn")->setEnabled(mObjectsScrollList->getNumSelected() == 1); }