llfloaterinspect.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. /**
  2. * @file llfloaterinspect.cpp
  3. * @brief Implementation of floaters for object and avatar inspection tool
  4. *
  5. * $LicenseInfo:firstyear=2006&license=viewergpl$
  6. *
  7. * Copyright (c) 2006-2009, Linden Research, Inc, 2009-2023 Henri Beauchamp.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llfloaterinspect.h"
  34. #include "llbutton.h"
  35. #include "llcachename.h"
  36. #include "lldate.h"
  37. #include "lliconctrl.h"
  38. #include "llscrolllistctrl.h"
  39. #include "lluictrlfactory.h"
  40. #include "llcommandhandler.h"
  41. #include "llfloateravatarinfo.h"
  42. #include "llfloaterobjectweights.h"
  43. #include "llfloatertools.h"
  44. //MK
  45. #include "mkrlinterface.h"
  46. //mk
  47. #include "llselectmgr.h"
  48. #include "lltoolcomp.h"
  49. #include "lltoolmgr.h"
  50. #include "llvoavatar.h"
  51. #include "llviewercontrol.h"
  52. #include "llviewerobjectlist.h"
  53. #define COMMENT_PREFIX "\342\200\243 "
  54. // Command handler
  55. // Handlea secondlife:///app/object/<ID>/inspect SLURLs
  56. class LLInspectObjectHandler final : public LLCommandHandler
  57. {
  58. public:
  59. LLInspectObjectHandler() : LLCommandHandler("object", UNTRUSTED_BLOCK) {}
  60. bool handle(const LLSD& params, const LLSD&, LLMediaCtrl*) override
  61. {
  62. if (params.size() < 2) return false;
  63. LLUUID object_id;
  64. if (!object_id.set(params[0], false))
  65. {
  66. return false;
  67. }
  68. const std::string verb = params[1].asString();
  69. if (verb == "inspect")
  70. {
  71. LLViewerObject* object = gObjectList.findObject(object_id);
  72. if (object)
  73. {
  74. LLFloaterInspect::show(object);
  75. return true;
  76. }
  77. }
  78. return false;
  79. }
  80. };
  81. LLInspectObjectHandler gInspectObjectHandler;
  82. // LLFloaterInspect class
  83. LLFloaterInspect::LLFloaterInspect(const LLSD&)
  84. : mDirty(false)
  85. {
  86. LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inspect.xml");
  87. }
  88. //virtual
  89. LLFloaterInspect::~LLFloaterInspect()
  90. {
  91. if (!LLFloaterTools::isVisible())
  92. {
  93. if (gToolMgr.getBaseTool() == &gToolCompInspect)
  94. {
  95. gToolMgr.clearTransientTool();
  96. }
  97. // Switch back to basic toolset
  98. gToolMgr.setCurrentToolset(gBasicToolset);
  99. }
  100. else
  101. {
  102. gFloaterToolsp->setFocus(true);
  103. }
  104. }
  105. //virtual
  106. bool LLFloaterInspect::postBuild()
  107. {
  108. mObjectList = getChild<LLScrollListCtrl>("object_list");
  109. mObjectList->setCommitCallback(onSelectObject);
  110. mObjectList->setCallbackUserData(this);
  111. mButtonOwner = getChild<LLButton>("button owner");
  112. mButtonOwner->setClickedCallback(onClickOwnerProfile, this);
  113. mButtonCreator = getChild<LLButton>("button creator");
  114. mButtonCreator->setClickedCallback(onClickCreatorProfile, this);
  115. mButtonWeights = getChild<LLButton>("button weights");
  116. mButtonWeights->setClickedCallback(onClickWeights, this);
  117. mIconNavMeshInfo = getChild<LLIconCtrl>("nav_mesh_info");
  118. mNavMeshToolTip = mIconNavMeshInfo->getToolTip();
  119. childSetAction("refresh", onClickRefresh, this);
  120. childSetAction("close", onClickClose, this);
  121. return true;
  122. }
  123. //virtual
  124. void LLFloaterInspect::draw()
  125. {
  126. if (mDirty)
  127. {
  128. mDirty = false;
  129. refresh();
  130. }
  131. LLFloater::draw();
  132. }
  133. //virtual
  134. void LLFloaterInspect::refresh()
  135. {
  136. LLUUID creator_id;
  137. std::string creator_name;
  138. S32 pos = mObjectList->getScrollPos();
  139. mButtonOwner->setEnabled(false);
  140. mButtonCreator->setEnabled(false);
  141. mButtonWeights->setEnabled(false);
  142. LLUUID selected_uuid;
  143. S32 selected_index = mObjectList->getFirstSelectedIndex();
  144. if (selected_index > -1)
  145. {
  146. LLScrollListItem* item = mObjectList->getFirstSelected();
  147. if (item)
  148. {
  149. selected_uuid = item->getUUID();
  150. }
  151. }
  152. mObjectList->deleteAllItems();
  153. const std::string& loadingstr = getString("loading");
  154. bool loading = false;
  155. S32 total_scripts = 0;
  156. const std::string format = gSavedSettings.getString("TimestampFormat");
  157. // List all transient objects, then all linked objects
  158. for (LLObjectSelection::valid_iterator
  159. iter = mObjectSelection->valid_begin(),
  160. end = mObjectSelection->valid_end();
  161. iter != end; ++iter)
  162. {
  163. LLSelectNode* obj = *iter;
  164. if (!obj || obj->mCreationDate == 0)
  165. {
  166. // Do not have valid information from the server, so skip this one
  167. continue;
  168. }
  169. LLViewerObject* vobj = obj->getObject();
  170. if (!vobj || vobj->isDead())
  171. {
  172. // Object gone or soon gone !
  173. continue;
  174. }
  175. time_t timestamp = (time_t)(obj->mCreationDate / 1000000);
  176. std::string owner_name, creator_name, last_owner_name;
  177. if (gCacheNamep)
  178. {
  179. gCacheNamep->getFullName(obj->mPermissions->getOwner(),
  180. owner_name);
  181. gCacheNamep->getFullName(obj->mPermissions->getCreator(),
  182. creator_name);
  183. gCacheNamep->getFullName(obj->mPermissions->getLastOwner(),
  184. last_owner_name);
  185. }
  186. LLUUID id = vobj->getID();
  187. S32 scripts = -1;
  188. S32 total = -1;
  189. invcounts_map_t::iterator itr = mInventoryNums.find(id);
  190. if (itr != mInventoryNums.end())
  191. {
  192. scripts = itr->second.first;
  193. total_scripts += scripts;
  194. total = itr->second.second;
  195. }
  196. else
  197. {
  198. requestInventory(vobj);
  199. loading = true;
  200. }
  201. LLSD row;
  202. row["id"] = id;
  203. row["columns"][0]["column"] = "object_name";
  204. row["columns"][0]["type"] = "text";
  205. // Make sure we are either at the top of the link chain
  206. // or top of the editable chain, for attachments
  207. if (vobj->isRoot() || vobj->isRootEdit())
  208. {
  209. row["columns"][0]["value"] = obj->mName;
  210. row["columns"][0]["font-style"] = "BOLD";
  211. }
  212. else
  213. {
  214. row["columns"][0]["value"] = std::string(" ") + obj->mName;
  215. }
  216. row["columns"][1]["column"] = "owner_name";
  217. row["columns"][1]["type"] = "text";
  218. row["columns"][1]["value"] = owner_name;
  219. row["columns"][2]["column"] = "last_owner_name";
  220. row["columns"][2]["type"] = "text";
  221. row["columns"][2]["value"] = last_owner_name;
  222. row["columns"][3]["column"] = "creator_name";
  223. row["columns"][3]["type"] = "text";
  224. row["columns"][3]["value"] = creator_name;
  225. row["columns"][4]["column"] = "creation_date";
  226. row["columns"][4]["type"] = "date";
  227. row["columns"][4]["format"] = format;
  228. row["columns"][4]["value"] = LLDate(timestamp);
  229. row["columns"][5]["column"] = "inventory";
  230. row["columns"][5]["type"] = "text";
  231. row["columns"][5]["value"] = (total < 0 ? loadingstr
  232. : llformat("%d/%d", scripts, total));
  233. mObjectList->addElement(row, ADD_TOP);
  234. }
  235. std::string comment = COMMENT_PREFIX + getString("total_scripts") +
  236. llformat(" %d", total_scripts);
  237. if (loading)
  238. {
  239. comment += " " + getString("so_far");
  240. }
  241. mObjectList->addCommentText(comment);
  242. if (selected_index > -1 &&
  243. mObjectList->getItemIndex(selected_uuid) == selected_index)
  244. {
  245. mObjectList->selectNthItem(selected_index);
  246. }
  247. else
  248. {
  249. mObjectList->selectNthItem(0);
  250. }
  251. onSelectObject(mObjectList, this);
  252. mObjectList->setScrollPos(pos);
  253. // Navmesh/pathfinding attribute(s)
  254. std::string pf_info = gSelectMgr.getPathFindingAttributeInfo(true);
  255. bool show_icon = !pf_info.empty();
  256. if (show_icon)
  257. {
  258. mIconNavMeshInfo->setToolTip(mNavMeshToolTip + " " + pf_info);
  259. }
  260. mIconNavMeshInfo->setVisible(show_icon);
  261. }
  262. void LLFloaterInspect::onFocusReceived()
  263. {
  264. gToolMgr.setTransientTool(&gToolCompInspect);
  265. LLFloater::onFocusReceived();
  266. }
  267. void LLFloaterInspect::requestInventory(LLViewerObject* vobj)
  268. {
  269. if (vobj && !hasRegisteredListener(vobj))
  270. {
  271. registerVOInventoryListener(vobj, NULL);
  272. requestVOInventory(vobj);
  273. }
  274. }
  275. void LLFloaterInspect::inventoryChanged(LLViewerObject* vobj,
  276. LLInventoryObject::object_list_t* inv,
  277. S32, void*)
  278. {
  279. if (!vobj || !inv)
  280. {
  281. return;
  282. }
  283. removeVOInventoryListener(vobj);
  284. const LLUUID id = vobj->getID();
  285. S32 scripts = 0, total = 0;
  286. for (LLInventoryObject::object_list_t::const_iterator
  287. it = inv->begin(), end = inv->end();
  288. it != end; ++it)
  289. {
  290. LLAssetType::EType type = (*it)->getType();
  291. if (type == LLAssetType::AT_LSL_TEXT ||
  292. type == LLAssetType::AT_SCRIPT) // Legacy scripts
  293. {
  294. ++scripts;
  295. }
  296. if (type != LLAssetType::AT_LSL_BYTECODE && // Do not count the bytecode associated with AT_LSL_TEXT
  297. type != LLAssetType::AT_CATEGORY && // Do not count folders
  298. type != LLAssetType::AT_NONE) // There's one such unknown item per prim...
  299. {
  300. ++total;
  301. }
  302. }
  303. mInventoryNums[id] = std::make_pair(scripts, total);
  304. mDirty = true;
  305. }
  306. //static
  307. void LLFloaterInspect::dirty()
  308. {
  309. LLFloaterInspect* self = findInstance();
  310. if (self)
  311. {
  312. self->removeVOInventoryListeners();
  313. self->mInventoryNums.clear();
  314. self->mDirty = true;
  315. }
  316. }
  317. //static
  318. LLUUID LLFloaterInspect::getSelectedUUID()
  319. {
  320. LLFloaterInspect* self = findInstance();
  321. if (self)
  322. {
  323. if (self->mObjectList->getAllSelected().size() > 0)
  324. {
  325. LLScrollListItem* item = self->mObjectList->getFirstSelected();
  326. if (item)
  327. {
  328. return item->getUUID();
  329. }
  330. }
  331. }
  332. return LLUUID::null;
  333. }
  334. //static
  335. void LLFloaterInspect::show(void* data)
  336. {
  337. if (data)
  338. {
  339. gSelectMgr.selectObjectAndFamily((LLViewerObject*)data);
  340. }
  341. // Ensure that the pie menu does not deselect things when it looses the
  342. // focus (this can happen with "select own objects only" is enabled).
  343. bool forcesel = gSelectMgr.setForceSelection(true);
  344. LLFloaterInspect* self = getInstance();
  345. self->open();
  346. gToolMgr.setTransientTool(&gToolCompInspect);
  347. gSelectMgr.setForceSelection(forcesel); // Restore previous value
  348. self->mObjectSelection = gSelectMgr.getSelection();
  349. self->refresh();
  350. }
  351. //static
  352. void LLFloaterInspect::onClickCreatorProfile(void* data)
  353. {
  354. LLFloaterInspect* self = (LLFloaterInspect*)data;
  355. if (!self || self->mObjectList->getAllSelected().size() == 0)
  356. {
  357. return;
  358. }
  359. LLScrollListItem* item = self->mObjectList->getFirstSelected();
  360. if (item)
  361. {
  362. struct f final : public LLSelectedNodeFunctor
  363. {
  364. LLUUID obj_id;
  365. f(const LLUUID& id) : obj_id(id) {}
  366. bool apply(LLSelectNode* node) override
  367. {
  368. return (obj_id == node->getObject()->getID());
  369. }
  370. } func(item->getUUID());
  371. LLSelectNode* node = self->mObjectSelection->getFirstNode(&func);
  372. if (node)
  373. {
  374. LLFloaterAvatarInfo::showFromDirectory(node->mPermissions->getCreator());
  375. }
  376. }
  377. }
  378. //static
  379. void LLFloaterInspect::onClickOwnerProfile(void* data)
  380. {
  381. LLFloaterInspect* self = (LLFloaterInspect*)data;
  382. if (!self || self->mObjectList->getAllSelected().size() == 0)
  383. {
  384. return;
  385. }
  386. LLScrollListItem* item = self->mObjectList->getFirstSelected();
  387. if (item)
  388. {
  389. LLUUID selected_id = item->getUUID();
  390. struct f final : public LLSelectedNodeFunctor
  391. {
  392. LLUUID obj_id;
  393. f(const LLUUID& id) : obj_id(id) {}
  394. bool apply(LLSelectNode* node) override
  395. {
  396. return (obj_id == node->getObject()->getID());
  397. }
  398. } func(selected_id);
  399. LLSelectNode* node = self->mObjectSelection->getFirstNode(&func);
  400. if (node)
  401. {
  402. const LLUUID& owner_id = node->mPermissions->getOwner();
  403. LLFloaterAvatarInfo::showFromDirectory(owner_id);
  404. }
  405. }
  406. }
  407. //static
  408. void LLFloaterInspect::onClickWeights(void* data)
  409. {
  410. LLFloaterInspect* self = (LLFloaterInspect*)data;
  411. if (self)
  412. {
  413. LLFloaterObjectWeights::show(self);
  414. }
  415. }
  416. //static
  417. void LLFloaterInspect::onClickRefresh(void* data)
  418. {
  419. LLFloaterInspect* self = (LLFloaterInspect*)data;
  420. if (self)
  421. {
  422. self->mInventoryNums.clear();
  423. dirty();
  424. }
  425. }
  426. //static
  427. void LLFloaterInspect::onClickClose(void* data)
  428. {
  429. LLFloaterInspect* self = (LLFloaterInspect*)data;
  430. if (self)
  431. {
  432. self->close();
  433. }
  434. }
  435. //static
  436. void LLFloaterInspect::onSelectObject(LLUICtrl*, void* data)
  437. {
  438. LLFloaterInspect* self = (LLFloaterInspect*)data;
  439. if (self && getSelectedUUID().notNull())
  440. {
  441. self->mButtonOwner->setEnabled(true);
  442. self->mButtonCreator->setEnabled(true);
  443. self->mButtonWeights->setEnabled(true);
  444. }
  445. }
  446. // HBFloaterInspectAvatar class
  447. HBFloaterInspectAvatar::HBFloaterInspectAvatar(const LLSD&)
  448. : mDirty(false)
  449. {
  450. LLUICtrlFactory::getInstance()->buildFloater(this,
  451. "floater_inspect_avatar.xml");
  452. }
  453. //virtual
  454. bool HBFloaterInspectAvatar::postBuild()
  455. {
  456. mObjectList = getChild<LLScrollListCtrl>("object_list");
  457. mObjectList->setDoubleClickCallback(onDoubleClickObject);
  458. mObjectList->setCallbackUserData(this);
  459. childSetAction("profile", onClickProfile, this);
  460. childSetAction("refresh", onClickRefresh, this);
  461. childSetAction("close", onClickClose, this);
  462. mTitle = getTitle();
  463. return true;
  464. }
  465. //virtual
  466. void HBFloaterInspectAvatar::draw()
  467. {
  468. if (mDirty)
  469. {
  470. mDirty = false;
  471. refresh();
  472. }
  473. LLFloater::draw();
  474. }
  475. //virtual
  476. void HBFloaterInspectAvatar::refresh()
  477. {
  478. S32 pos = mObjectList->getScrollPos();
  479. LLUUID selected_uuid;
  480. S32 selected_index = mObjectList->getFirstSelectedIndex();
  481. if (selected_index > -1)
  482. {
  483. LLScrollListItem* item = mObjectList->getFirstSelected();
  484. if (item)
  485. {
  486. selected_uuid = item->getUUID();
  487. }
  488. }
  489. mObjectList->deleteAllItems();
  490. LLVOAvatar* avatar = gObjectList.findAvatar(mAvatarID);
  491. if (!avatar)
  492. {
  493. setTitle(mTitle);
  494. mObjectList->addCommentText(getString("no_avatar"));
  495. removeVOInventoryListeners();
  496. mScriptCounts.clear();
  497. return;
  498. }
  499. //MK
  500. if (gRLenabled &&
  501. (gRLInterface.mContainsShownames || gRLInterface.mContainsShowNearby ||
  502. gRLInterface.mContainsShownametags))
  503. {
  504. setTitle(mTitle);
  505. }
  506. else
  507. //mk
  508. {
  509. std::string avatar_name;
  510. if (gCacheNamep && gCacheNamep->getFullName(mAvatarID, avatar_name))
  511. {
  512. setTitle(mTitle + ": " + avatar_name);
  513. }
  514. }
  515. const std::string& loadingstr = getString("loading");
  516. bool loading = false;
  517. S32 attachments = 0;
  518. S32 total_primitives = 0;
  519. S32 total_scripts = 0;
  520. // List all attachements
  521. for (S32 i = 0, count = avatar->mAttachedObjectsVector.size(); i < count;
  522. ++i)
  523. {
  524. LLViewerObject* vobj = avatar->mAttachedObjectsVector[i].first;
  525. LLViewerJointAttachment* vatt = avatar->mAttachedObjectsVector[i].second;
  526. if (!vatt || !vatt->getValid() || !vobj || vobj->isDead())
  527. {
  528. continue;
  529. }
  530. const std::string& joint_name = vatt->getName();
  531. ++attachments;
  532. const LLUUID& id = vobj->getID();
  533. S32 primitives = 1;
  534. S32 scripts = -1; // Value for "loading"
  535. scriptcounts_map_t::iterator itr = mScriptCounts.find(id);
  536. if (itr == mScriptCounts.end())
  537. {
  538. loading = true;
  539. requestInventory(vobj);
  540. }
  541. else
  542. {
  543. scripts = itr->second;
  544. total_scripts += scripts;
  545. }
  546. // We must also get the child primitives info...
  547. LLViewerObject::child_list_t child_list = vobj->getChildren();
  548. for (LLViewerObject::child_list_t::iterator
  549. child_it = child_list.begin(), end3 = child_list.end();
  550. child_it != end3; ++child_it)
  551. {
  552. LLViewerObject* child = *child_it;
  553. if (!child || child->isDead() || child->isAvatar())
  554. {
  555. continue;
  556. }
  557. ++primitives;
  558. scriptcounts_map_t::iterator itrc = mScriptCounts.find(child->getID());
  559. if (itrc != mScriptCounts.end())
  560. {
  561. if (scripts >= 0)
  562. {
  563. scripts += itrc->second;
  564. }
  565. total_scripts += itrc->second;
  566. }
  567. else
  568. {
  569. loading = true;
  570. requestInventory(child);
  571. scripts = -1; // Value for "loading"
  572. }
  573. }
  574. total_primitives += primitives;
  575. LLSD row;
  576. row["id"] = id;
  577. row["columns"][0]["column"] = "object_id";
  578. row["columns"][0]["type"] = "text";
  579. row["columns"][0]["value"] = id.asString();
  580. row["columns"][1]["column"] = "attach";
  581. row["columns"][1]["type"] = "text";
  582. row["columns"][1]["value"] = joint_name;
  583. row["columns"][2]["column"] = "primitives";
  584. row["columns"][2]["type"] = "text";
  585. row["columns"][2]["value"] = llformat("%d", primitives);
  586. row["columns"][3]["column"] = "scripts";
  587. row["columns"][3]["type"] = "text";
  588. row["columns"][3]["value"] = (scripts < 0 ? loadingstr
  589. : llformat("%d", scripts));
  590. LLScrollListItem* item = mObjectList->addElement(row);
  591. if (item)
  592. {
  593. item->setEnabled(!vobj->isHUDAttachment());
  594. }
  595. }
  596. std::string comment = COMMENT_PREFIX + getString("total_attachments") +
  597. llformat(" %d ", attachments) +
  598. getString("total_primitives") +
  599. llformat(" %d ", total_primitives) +
  600. getString("total_scripts") +
  601. llformat(" %d", total_scripts);
  602. if (loading)
  603. {
  604. comment += " " + getString("so_far");
  605. }
  606. mObjectList->addCommentText(comment);
  607. if (selected_index > -1 &&
  608. mObjectList->getItemIndex(selected_uuid) == selected_index)
  609. {
  610. mObjectList->selectNthItem(selected_index);
  611. }
  612. else
  613. {
  614. mObjectList->selectNthItem(0);
  615. }
  616. mObjectList->setScrollPos(pos);
  617. }
  618. void HBFloaterInspectAvatar::requestInventory(LLViewerObject* vobj)
  619. {
  620. if (vobj && !hasRegisteredListener(vobj))
  621. {
  622. registerVOInventoryListener(vobj, NULL);
  623. requestVOInventory(vobj);
  624. }
  625. }
  626. void HBFloaterInspectAvatar::inventoryChanged(LLViewerObject* vobj,
  627. LLInventoryObject::object_list_t* inv,
  628. S32, void*)
  629. {
  630. if (!vobj || !inv)
  631. {
  632. return;
  633. }
  634. removeVOInventoryListener(vobj);
  635. const LLUUID id = vobj->getID();
  636. S32 scripts = 0;
  637. for (LLInventoryObject::object_list_t::const_iterator
  638. it = inv->begin(), end = inv->end();
  639. it != end; ++it)
  640. {
  641. LLAssetType::EType type = (*it)->getType();
  642. if (type == LLAssetType::AT_LSL_TEXT ||
  643. // Legacy scripts
  644. type == LLAssetType::AT_SCRIPT)
  645. {
  646. ++scripts;
  647. }
  648. }
  649. mScriptCounts[id] = scripts;
  650. mDirty = true;
  651. }
  652. //static
  653. void HBFloaterInspectAvatar::show(const LLUUID& av_id)
  654. {
  655. HBFloaterInspectAvatar* self = getInstance();
  656. self->mScriptCounts.clear();
  657. self->mAvatarID = av_id;
  658. self->open();
  659. self->refresh();
  660. }
  661. //static
  662. void HBFloaterInspectAvatar::onClickProfile(void* data)
  663. {
  664. HBFloaterInspectAvatar* self = (HBFloaterInspectAvatar*)data;
  665. if (self && self->mAvatarID.notNull())
  666. {
  667. LLFloaterAvatarInfo::showFromDirectory(self->mAvatarID);
  668. }
  669. }
  670. //static
  671. void HBFloaterInspectAvatar::onClickRefresh(void* data)
  672. {
  673. HBFloaterInspectAvatar* self = (HBFloaterInspectAvatar*)data;
  674. if (self)
  675. {
  676. self->removeVOInventoryListeners();
  677. self->mScriptCounts.clear();
  678. self->mDirty = true;
  679. }
  680. }
  681. //static
  682. void HBFloaterInspectAvatar::onClickClose(void* data)
  683. {
  684. HBFloaterInspectAvatar* self = (HBFloaterInspectAvatar*)data;
  685. if (self)
  686. {
  687. self->close();
  688. }
  689. }
  690. //static
  691. void HBFloaterInspectAvatar::onDoubleClickObject(void* data)
  692. {
  693. HBFloaterInspectAvatar* self = (HBFloaterInspectAvatar*)data;
  694. if (self)
  695. {
  696. if (self->mObjectList->getAllSelected().size() > 0)
  697. {
  698. LLScrollListItem* item = self->mObjectList->getFirstSelected();
  699. if (item)
  700. {
  701. const LLUUID& id = item->getUUID();
  702. LLViewerObject* vobj = gObjectList.findObject(id);
  703. if (vobj)
  704. {
  705. LLFloaterInspect::show(vobj);
  706. }
  707. }
  708. }
  709. }
  710. }