llinspectobject.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:18k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llinspectobject.cpp
  3.  *
  4.  * $LicenseInfo:firstyear=2009&license=viewergpl$
  5.  * 
  6.  * Copyright (c) 2009-2010, Linden Research, Inc.
  7.  * 
  8.  * Second Life Viewer Source Code
  9.  * The source code in this file ("Source Code") is provided by Linden Lab
  10.  * to you under the terms of the GNU General Public License, version 2.0
  11.  * ("GPL"), unless you have obtained a separate licensing agreement
  12.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  13.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  14.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  15.  * 
  16.  * There are special exceptions to the terms and conditions of the GPL as
  17.  * it is applied to this Source Code. View the full text of the exception
  18.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  19.  * online at
  20.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  21.  * 
  22.  * By copying, modifying or distributing this software, you acknowledge
  23.  * that you have read and understood your obligations described above,
  24.  * and agree to abide by those obligations.
  25.  * 
  26.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  27.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  28.  * COMPLETENESS OR PERFORMANCE.
  29.  * $/LicenseInfo$
  30.  */
  31. #include "llviewerprecompiledheaders.h"
  32. #include "llinspectobject.h"
  33. // Viewer
  34. #include "llinspect.h"
  35. #include "llmediaentry.h"
  36. #include "llnotificationsutil.h" // *TODO: Eliminate, add LLNotificationsUtil wrapper
  37. #include "llselectmgr.h"
  38. #include "llslurl.h"
  39. #include "llviewermenu.h" // handle_object_touch(), handle_buy()
  40. #include "llviewermedia.h"
  41. #include "llviewermediafocus.h"
  42. #include "llviewerobjectlist.h" // to select the requested object
  43. // Linden libraries
  44. #include "llbutton.h" // setLabel(), not virtual!
  45. #include "llclickaction.h"
  46. #include "llfloaterreg.h"
  47. #include "llmenubutton.h"
  48. #include "llresmgr.h" // getMonetaryString
  49. #include "llsafehandle.h"
  50. #include "llsidetray.h"
  51. #include "lltextbox.h" // for description truncation
  52. #include "lltrans.h"
  53. #include "llui.h" // positionViewNearMouse()
  54. #include "lluictrl.h"
  55. class LLViewerObject;
  56. //////////////////////////////////////////////////////////////////////////////
  57. // LLInspectObject
  58. //////////////////////////////////////////////////////////////////////////////
  59. // Object Inspector, a small information window used when clicking
  60. // in the ambient inspector widget for objects in the 3D world.
  61. class LLInspectObject : public LLInspect
  62. {
  63. friend class LLFloaterReg;
  64. public:
  65. // object_id - Root object ID for which to show information
  66. // Inspector will be positioned relative to current mouse position
  67. LLInspectObject(const LLSD& object_id);
  68. virtual ~LLInspectObject();
  69. /*virtual*/ BOOL postBuild(void);
  70. // Because floater is single instance, need to re-parse data on each spawn
  71. // (for example, inspector about same avatar but in different position)
  72. /*virtual*/ void onOpen(const LLSD& avatar_id);
  73. // Release the selection and do other cleanup
  74. /*virtual*/ void onClose(bool app_quitting);
  75. // override the inspector mouse leave so timer is only paused if 
  76. // gear menu is not open
  77. /* virtual */ void onMouseLeave(S32 x, S32 y, MASK mask);
  78. private:
  79. // Refresh displayed data with information from selection manager
  80. void update();
  81. void hideButtons();
  82. void updateButtons(LLSelectNode* nodep);
  83. void updateSitLabel(LLSelectNode* nodep);
  84. void updateTouchLabel(LLSelectNode* nodep);
  85. void updateName(LLSelectNode* nodep);
  86. void updateDescription(LLSelectNode* nodep);
  87. void updatePrice(LLSelectNode* nodep);
  88. void updateCreator(LLSelectNode* nodep);
  89. void updateMediaCurrentURL();
  90. void updateSecureBrowsing();
  91. void onClickBuy();
  92. void onClickPay();
  93. void onClickTakeFreeCopy();
  94. void onClickTouch();
  95. void onClickSit();
  96. void onClickOpen();
  97. void onClickMoreInfo();
  98. void onClickZoomIn();  
  99. private:
  100. LLUUID mObjectID;
  101. S32 mObjectFace;
  102. viewer_media_t mMediaImpl;
  103. LLMediaEntry*       mMediaEntry;
  104. LLSafeHandle<LLObjectSelection> mObjectSelection;
  105. };
  106. LLInspectObject::LLInspectObject(const LLSD& sd)
  107. : LLInspect( LLSD() ), // single_instance, doesn't really need key
  108. mObjectID(NULL), // set in onOpen()
  109. mObjectFace(0),
  110. mObjectSelection(NULL),
  111. mMediaImpl(NULL),
  112. mMediaEntry(NULL)
  113. {
  114. // can't make the properties request until the widgets are constructed
  115. // as it might return immediately, so do it in postBuild.
  116. mCommitCallbackRegistrar.add("InspectObject.Buy", boost::bind(&LLInspectObject::onClickBuy, this));
  117. mCommitCallbackRegistrar.add("InspectObject.Pay", boost::bind(&LLInspectObject::onClickPay, this));
  118. mCommitCallbackRegistrar.add("InspectObject.TakeFreeCopy", boost::bind(&LLInspectObject::onClickTakeFreeCopy, this));
  119. mCommitCallbackRegistrar.add("InspectObject.Touch", boost::bind(&LLInspectObject::onClickTouch, this));
  120. mCommitCallbackRegistrar.add("InspectObject.Sit", boost::bind(&LLInspectObject::onClickSit, this));
  121. mCommitCallbackRegistrar.add("InspectObject.Open", boost::bind(&LLInspectObject::onClickOpen, this));
  122. mCommitCallbackRegistrar.add("InspectObject.MoreInfo", boost::bind(&LLInspectObject::onClickMoreInfo, this));
  123. mCommitCallbackRegistrar.add("InspectObject.ZoomIn", boost::bind(&LLInspectObject::onClickZoomIn, this));
  124. }
  125. LLInspectObject::~LLInspectObject()
  126. {
  127. }
  128. /*virtual*/
  129. BOOL LLInspectObject::postBuild(void)
  130. {
  131. // The XML file has sample data in it.  Clear that out so we don't
  132. // flicker when data arrives off network.
  133. getChild<LLUICtrl>("object_name")->setValue("");
  134. getChild<LLUICtrl>("object_creator")->setValue("");
  135. getChild<LLUICtrl>("object_description")->setValue("");
  136. getChild<LLUICtrl>("object_media_url")->setValue("");
  137. // Set buttons invisible until we know what this object can do
  138. hideButtons();
  139. // Hide floater when name links clicked
  140. LLTextBox* textbox = getChild<LLTextBox>("object_creator");
  141. textbox->mURLClickSignal.connect(
  142. boost::bind(&LLInspectObject::closeFloater, this, false) );
  143. // Hook up functionality
  144. getChild<LLUICtrl>("buy_btn")->setCommitCallback(
  145. boost::bind(&LLInspectObject::onClickBuy, this));
  146. getChild<LLUICtrl>("pay_btn")->setCommitCallback(
  147. boost::bind(&LLInspectObject::onClickPay, this));
  148. getChild<LLUICtrl>("take_free_copy_btn")->setCommitCallback(
  149. boost::bind(&LLInspectObject::onClickTakeFreeCopy, this));
  150. getChild<LLUICtrl>("touch_btn")->setCommitCallback(
  151. boost::bind(&LLInspectObject::onClickTouch, this));
  152. getChild<LLUICtrl>("sit_btn")->setCommitCallback(
  153. boost::bind(&LLInspectObject::onClickSit, this));
  154. getChild<LLUICtrl>("open_btn")->setCommitCallback(
  155. boost::bind(&LLInspectObject::onClickOpen, this));
  156. getChild<LLUICtrl>("more_info_btn")->setCommitCallback(
  157. boost::bind(&LLInspectObject::onClickMoreInfo, this));
  158. // Watch for updates to selection properties off the network
  159. LLSelectMgr::getInstance()->mUpdateSignal.connect(
  160. boost::bind(&LLInspectObject::update, this) );
  161. return TRUE;
  162. }
  163. // Multiple calls to showInstance("inspect_avatar", foo) will provide different
  164. // LLSD for foo, which we will catch here.
  165. //virtual
  166. void LLInspectObject::onOpen(const LLSD& data)
  167. {
  168. // Start animation
  169. LLInspect::onOpen(data);
  170. // Extract appropriate avatar id
  171. mObjectID = data["object_id"];
  172. if(data.has("object_face"))
  173. {
  174. mObjectFace = data["object_face"];
  175. }
  176. // Position the inspector relative to the mouse cursor
  177. // Similar to how tooltips are positioned
  178. // See LLToolTipMgr::createToolTip
  179. if (data.has("pos"))
  180. {
  181. LLUI::positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger());
  182. }
  183. else
  184. {
  185. LLUI::positionViewNearMouse(this);
  186. }
  187. // Promote hovered object to a complete selection, which will also force
  188. // a request for selected object data off the network
  189. LLViewerObject* obj = gObjectList.findObject( mObjectID );
  190. if (obj)
  191. {
  192. // Media focus and this code fight over the select manager.  
  193. // Make sure any media is unfocused before changing the selection here.
  194. LLViewerMediaFocus::getInstance()->clearFocus();
  195. LLSelectMgr::instance().deselectAll();
  196. mObjectSelection = LLSelectMgr::instance().selectObjectAndFamily(obj);
  197. // Mark this as a transient selection
  198. struct SetTransient : public LLSelectedNodeFunctor
  199. {
  200. bool apply(LLSelectNode* node)
  201. {
  202. node->setTransient(TRUE);
  203. return true;
  204. }
  205. } functor;
  206. mObjectSelection->applyToNodes(&functor);
  207. // Does this face have media?
  208. const LLTextureEntry* tep = obj->getTE(mObjectFace);
  209. if (!tep)
  210. return;
  211. mMediaEntry = tep->hasMedia() ? tep->getMediaData() : NULL;
  212. if(!mMediaEntry)
  213. return;
  214. mMediaImpl = LLViewerMedia::getMediaImplFromTextureID(mMediaEntry->getMediaID());
  215. }
  216. }
  217. // virtual
  218. void LLInspectObject::onClose(bool app_quitting)
  219. {
  220. // Release selection to deselect
  221. mObjectSelection = NULL;
  222. getChild<LLMenuButton>("gear_btn")->hideMenu();
  223. }
  224. void LLInspectObject::update()
  225. {
  226. // Performance optimization, because we listen to updates from select mgr
  227. // but we're never destroyed.
  228. if (!getVisible()) return;
  229. LLObjectSelection* selection = LLSelectMgr::getInstance()->getSelection();
  230. if (!selection) return;
  231. LLSelectNode* nodep = selection->getFirstRootNode();
  232. if (!nodep) return;
  233. updateButtons(nodep);
  234. updateName(nodep);
  235. updateDescription(nodep);
  236. updateCreator(nodep);
  237. updatePrice(nodep);
  238. LLViewerObject* obj = nodep->getObject();
  239. if(!obj)
  240. return;
  241. if ( mObjectFace < 0 
  242. ||  mObjectFace >= obj->getNumTEs() )
  243. {
  244. return;
  245. }
  246. // Does this face have media?
  247. const LLTextureEntry* tep = obj->getTE(mObjectFace);
  248. if (!tep)
  249. return;
  250. mMediaEntry = tep->hasMedia() ? tep->getMediaData() : NULL;
  251. if(!mMediaEntry)
  252. return;
  253. mMediaImpl = LLViewerMedia::getMediaImplFromTextureID(mMediaEntry->getMediaID());
  254. updateMediaCurrentURL();
  255. updateSecureBrowsing();
  256. }
  257. void LLInspectObject::hideButtons()
  258. {
  259. getChild<LLUICtrl>("buy_btn")->setVisible(false);
  260. getChild<LLUICtrl>("pay_btn")->setVisible(false);
  261. getChild<LLUICtrl>("take_free_copy_btn")->setVisible(false);
  262. getChild<LLUICtrl>("touch_btn")->setVisible(false);
  263. getChild<LLUICtrl>("sit_btn")->setVisible(false);
  264. getChild<LLUICtrl>("open_btn")->setVisible(false);
  265. }
  266. // *TODO: Extract this method from lltoolpie.cpp and put somewhere shared
  267. extern U8 final_click_action(LLViewerObject*);
  268. // Choose the "most relevant" operation for this object, and show a button for
  269. // that operation as the left-most button in the inspector.
  270. void LLInspectObject::updateButtons(LLSelectNode* nodep)
  271. {
  272. // We'll start with everyone hidden and show the ones we need
  273. hideButtons();
  274. LLViewerObject* object = nodep->getObject();
  275. LLViewerObject *parent = (LLViewerObject*)object->getParent();
  276. bool for_copy = anyone_copy_selection(nodep);
  277. bool for_sale = enable_buy_object();
  278. S32 price = nodep->mSaleInfo.getSalePrice();
  279. U8 click_action = final_click_action(object);
  280. if (for_copy
  281. || (for_sale && price == 0))
  282. {
  283. // Free copies have priority over other operations
  284. getChild<LLUICtrl>("take_free_copy_btn")->setVisible(true);
  285. }
  286. else if (for_sale)
  287. {
  288. getChild<LLUICtrl>("buy_btn")->setVisible(true);
  289. }
  290. else if ( enable_pay_object() )
  291. {
  292. getChild<LLUICtrl>("pay_btn")->setVisible(true);
  293. }
  294. else if (click_action == CLICK_ACTION_SIT)
  295. {
  296. // Click-action sit must come before "open" because many objects on
  297. // which you can sit have scripts, and hence can be opened
  298. getChild<LLUICtrl>("sit_btn")->setVisible(true);
  299. updateSitLabel(nodep);
  300. }
  301. else if (object->flagHandleTouch()
  302. || (parent && parent->flagHandleTouch()))
  303. {
  304. getChild<LLUICtrl>("touch_btn")->setVisible(true);
  305. updateTouchLabel(nodep);
  306. }
  307. else if ( enable_object_open() )
  308. {
  309. // Open is last because anything with a script in it can be opened
  310. getChild<LLUICtrl>("open_btn")->setVisible(true);
  311. }
  312. else
  313. {
  314. // By default, we can sit on anything
  315. getChild<LLUICtrl>("sit_btn")->setVisible(true);
  316. updateSitLabel(nodep);
  317. }
  318. // No flash
  319. focusFirstItem(FALSE, FALSE);
  320. }
  321. void LLInspectObject::updateSitLabel(LLSelectNode* nodep)
  322. {
  323. LLButton* sit_btn = getChild<LLButton>("sit_btn");
  324. if (!nodep->mSitName.empty())
  325. {
  326. sit_btn->setLabel( nodep->mSitName );
  327. }
  328. else
  329. {
  330. sit_btn->setLabel( getString("Sit") );
  331. }
  332. }
  333. void LLInspectObject::updateTouchLabel(LLSelectNode* nodep)
  334. {
  335. LLButton* sit_btn = getChild<LLButton>("touch_btn");
  336. if (!nodep->mTouchName.empty())
  337. {
  338. sit_btn->setLabel( nodep->mTouchName );
  339. }
  340. else
  341. {
  342. sit_btn->setLabel( getString("Touch") );
  343. }
  344. }
  345. void LLInspectObject::updateName(LLSelectNode* nodep)
  346. {
  347. std::string name;
  348. if (!nodep->mName.empty())
  349. {
  350. name = nodep->mName;
  351. }
  352. else
  353. {
  354. name = LLTrans::getString("TooltipNoName");
  355. }
  356. getChild<LLUICtrl>("object_name")->setValue(name);
  357. }
  358. void LLInspectObject::updateDescription(LLSelectNode* nodep)
  359. {
  360. const char* const DEFAULT_DESC = "(No Description)";
  361. std::string desc;
  362. if (!nodep->mDescription.empty()
  363. && nodep->mDescription != DEFAULT_DESC)
  364. {
  365. desc = nodep->mDescription;
  366. }
  367. LLTextBox* textbox = getChild<LLTextBox>("object_description");
  368. textbox->setValue(desc);
  369. }
  370. void LLInspectObject::updateMediaCurrentURL()
  371. {
  372. if(!mMediaEntry)
  373. return;
  374. LLTextBox* textbox = getChild<LLTextBox>("object_media_url");
  375. std::string media_url = "";
  376. textbox->setValue(media_url);
  377. textbox->setToolTip(media_url);
  378. LLStringUtil::format_map_t args;
  379. if(mMediaImpl.notNull() && mMediaImpl->hasMedia())
  380. {
  381. LLPluginClassMedia* media_plugin = NULL;
  382. media_plugin = mMediaImpl->getMediaPlugin();
  383. if(media_plugin)
  384. {
  385. if(media_plugin->pluginSupportsMediaTime())
  386. {
  387. args["[CurrentURL]"] =  mMediaImpl->getMediaURL();
  388. }
  389. else
  390. {
  391. args["[CurrentURL]"] =  media_plugin->getLocation();
  392. }
  393. media_url = LLTrans::getString("CurrentURL", args);
  394. }
  395. }
  396. else if(mMediaEntry->getCurrentURL() != "")
  397. {
  398. args["[CurrentURL]"] = mMediaEntry->getCurrentURL();
  399. media_url = LLTrans::getString("CurrentURL", args);
  400. }
  401. textbox->setText(media_url);
  402. textbox->setToolTip(media_url);
  403. }
  404. void LLInspectObject::updateCreator(LLSelectNode* nodep)
  405. {
  406. // final information for display
  407. LLStringUtil::format_map_t args;
  408. std::string text;
  409. // Leave text blank until data loaded
  410. if (nodep->mValid)
  411. {
  412. // Utilize automatic translation of SLURL into name to display 
  413. // a clickable link
  414. // Objects cannot be created by a group, so use agent URL format
  415. LLUUID creator_id = nodep->mPermissions->getCreator();
  416. std::string creator_url =
  417. LLSLURL::buildCommand("agent", creator_id, "about");
  418. args["[CREATOR]"] = creator_url;
  419. // created by one user but owned by another
  420. std::string owner_url;
  421. LLUUID owner_id;
  422. bool group_owned = nodep->mPermissions->isGroupOwned();
  423. if (group_owned)
  424. {
  425. owner_id = nodep->mPermissions->getGroup();
  426. owner_url = LLSLURL::buildCommand("group", owner_id, "about");
  427. }
  428. else
  429. {
  430. owner_id = nodep->mPermissions->getOwner();
  431. owner_url = LLSLURL::buildCommand("agent", owner_id, "about");
  432. }
  433. args["[OWNER]"] = owner_url;
  434. if (creator_id == owner_id)
  435. {
  436. // common case, created and owned by one user
  437. text = getString("Creator", args);
  438. }
  439. else
  440. {
  441. text = getString("CreatorAndOwner", args);
  442. }
  443. }
  444. getChild<LLUICtrl>("object_creator")->setValue(text);
  445. }
  446. void LLInspectObject::updatePrice(LLSelectNode* nodep)
  447. {
  448. // *TODO: Only look these up once and use for both updateButtons and here
  449. bool for_copy = anyone_copy_selection(nodep);
  450. bool for_sale = enable_buy_object();
  451. S32 price = nodep->mSaleInfo.getSalePrice();
  452. bool show_price_icon = false;
  453. std::string line;
  454. if (for_copy
  455. || (for_sale && price == 0))
  456. {
  457. line = getString("PriceFree");
  458. show_price_icon = true;
  459. }
  460. else if (for_sale)
  461. {
  462. LLStringUtil::format_map_t args;
  463. args["[AMOUNT]"] = LLResMgr::getInstance()->getMonetaryString(price);
  464. line = getString("Price", args);
  465. show_price_icon = true;
  466. }
  467. getChild<LLUICtrl>("price_text")->setValue(line);
  468. getChild<LLUICtrl>("price_icon")->setVisible(show_price_icon);
  469. }
  470. void LLInspectObject::updateSecureBrowsing()
  471. {
  472. bool is_secure_browsing = false;
  473. if(mMediaImpl.notNull() 
  474.    && mMediaImpl->hasMedia())
  475. {
  476. LLPluginClassMedia* media_plugin = NULL;
  477. std::string current_url = "";
  478. media_plugin = mMediaImpl->getMediaPlugin();
  479. if(media_plugin)
  480. {
  481. if(media_plugin->pluginSupportsMediaTime())
  482. {
  483. current_url = mMediaImpl->getMediaURL();
  484. }
  485. else
  486. {
  487. current_url =  media_plugin->getLocation();
  488. }
  489. }
  490. std::string prefix =  std::string("https://");
  491. std::string test_prefix = current_url.substr(0, prefix.length());
  492. LLStringUtil::toLower(test_prefix);
  493. if(test_prefix == prefix)
  494. {
  495. is_secure_browsing = true;
  496. }
  497. }
  498. getChild<LLUICtrl>("secure_browsing")->setVisible(is_secure_browsing);
  499. }
  500. // For the object inspector, only unpause the fade timer 
  501. // if the gear menu is not open
  502. void LLInspectObject::onMouseLeave(S32 x, S32 y, MASK mask)
  503. {
  504. LLMenuGL* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu();
  505. if ( gear_menu && gear_menu->getVisible() )
  506. {
  507. return;
  508. }
  509. if(childHasVisiblePopupMenu())
  510. {
  511. return;
  512. }
  513. mOpenTimer.unpause();
  514. }
  515. void LLInspectObject::onClickBuy()
  516. {
  517. handle_buy();
  518. closeFloater();
  519. }
  520. void LLInspectObject::onClickPay()
  521. {
  522. handle_give_money_dialog();
  523. closeFloater();
  524. }
  525. void LLInspectObject::onClickTakeFreeCopy()
  526. {
  527. LLObjectSelection* selection = LLSelectMgr::getInstance()->getSelection();
  528. if (!selection) return;
  529. LLSelectNode* nodep = selection->getFirstRootNode();
  530. if (!nodep) return;
  531. // Figure out if this is a "free buy" or a "take copy"
  532. bool for_copy = anyone_copy_selection(nodep);
  533. // Prefer to just take a free copy
  534. if (for_copy)
  535. {
  536. handle_take_copy();
  537. }
  538. else
  539. {
  540. // Buy for free (confusing, but that's how it is)
  541. handle_buy();
  542. }
  543. closeFloater();
  544. }
  545. void LLInspectObject::onClickTouch()
  546. {
  547. handle_object_touch();
  548. closeFloater();
  549. }
  550. void LLInspectObject::onClickSit()
  551. {
  552. handle_object_sit_or_stand();
  553. closeFloater();
  554. }
  555. void LLInspectObject::onClickOpen()
  556. {
  557. LLFloaterReg::showInstance("openobject");
  558. closeFloater();
  559. }
  560. void LLInspectObject::onClickMoreInfo()
  561. {
  562. LLSD key;
  563. key["task"] = "task";
  564. LLSideTray::getInstance()->showPanel("sidepanel_inventory", key);
  565. closeFloater();
  566. }
  567. void LLInspectObject::onClickZoomIn() 
  568. {
  569. handle_look_at_selection("zoom");
  570. closeFloater();
  571. }
  572. //////////////////////////////////////////////////////////////////////////////
  573. // LLInspectObjectUtil
  574. //////////////////////////////////////////////////////////////////////////////
  575. void LLInspectObjectUtil::registerFloater()
  576. {
  577. LLFloaterReg::add("inspect_object", "inspect_object.xml",
  578.   &LLFloaterReg::build<LLInspectObject>);
  579. }