diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llinspectobject.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/newview/llinspectobject.cpp')
-rw-r--r-- | indra/newview/llinspectobject.cpp | 1382 |
1 files changed, 691 insertions, 691 deletions
diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp index 1f77068694..b6709a1e78 100644 --- a/indra/newview/llinspectobject.cpp +++ b/indra/newview/llinspectobject.cpp @@ -1,691 +1,691 @@ -/** - * @file llinspectobject.cpp - * - * $LicenseInfo:firstyear=2009&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 "llinspectobject.h" - -// Viewer -#include "llagent.h" // To standup -#include "llfloatersidepanelcontainer.h" -#include "llinspect.h" -#include "llmediaentry.h" -#include "llselectmgr.h" -#include "llslurl.h" -#include "llviewermenu.h" // handle_object_touch(), handle_buy() -#include "llviewermedia.h" -#include "llviewermediafocus.h" -#include "llviewerobjectlist.h" // to select the requested object -#include "llvoavatarself.h" - -// Linden libraries -#include "llbutton.h" // setLabel(), not virtual! -#include "llclickaction.h" -#include "llfloaterreg.h" -#include "llmenubutton.h" -#include "llresmgr.h" // getMonetaryString -#include "llsafehandle.h" -#include "lltextbox.h" // for description truncation -#include "lltoggleablemenu.h" -#include "lltrans.h" -#include "lluictrl.h" - -class LLViewerObject; - -////////////////////////////////////////////////////////////////////////////// -// LLInspectObject -////////////////////////////////////////////////////////////////////////////// - -// Object Inspector, a small information window used when clicking -// in the ambient inspector widget for objects in the 3D world. -class LLInspectObject : public LLInspect -{ - friend class LLFloaterReg; - -public: - // object_id - Root object ID for which to show information - // Inspector will be positioned relative to current mouse position - LLInspectObject(const LLSD& object_id); - virtual ~LLInspectObject(); - - /*virtual*/ bool postBuild(void); - - // Because floater is single instance, need to re-parse data on each spawn - // (for example, inspector about same avatar but in different position) - /*virtual*/ void onOpen(const LLSD& avatar_id); - - // Release the selection and do other cleanup - /*virtual*/ void onClose(bool app_quitting); - - // override the inspector mouse leave so timer is only paused if - // gear menu is not open - /* virtual */ void onMouseLeave(S32 x, S32 y, MASK mask); - -private: - // Refresh displayed data with information from selection manager - void update(); - - void hideButtons(); - void updateButtons(LLSelectNode* nodep); - void updateSitLabel(LLSelectNode* nodep); - void updateTouchLabel(LLSelectNode* nodep); - - void updateName(LLSelectNode* nodep); - void updateDescription(LLSelectNode* nodep); - void updatePrice(LLSelectNode* nodep); - void updateCreator(LLSelectNode* nodep); - - void updateMediaCurrentURL(); - void updateSecureBrowsing(); - - void onClickBuy(); - void onClickPay(); - void onClickTakeFreeCopy(); - void onClickTouch(); - void onClickSit(); - void onClickOpen(); - void onClickMoreInfo(); - void onClickZoomIn(); - -private: - LLUUID mObjectID; - LLUUID mPreviousObjectID; - S32 mObjectFace; - viewer_media_t mMediaImpl; - LLMediaEntry* mMediaEntry; - LLSafeHandle<LLObjectSelection> mObjectSelection; - boost::signals2::connection mSelectionUpdateSlot; -}; - -LLInspectObject::LLInspectObject(const LLSD& sd) -: LLInspect( LLSD() ), // single_instance, doesn't really need key - mObjectID(NULL), // set in onOpen() - mObjectFace(0), - mObjectSelection(NULL), - mMediaImpl(NULL), - mMediaEntry(NULL) -{ - // can't make the properties request until the widgets are constructed - // as it might return immediately, so do it in postBuild. - mCommitCallbackRegistrar.add("InspectObject.Buy", boost::bind(&LLInspectObject::onClickBuy, this)); - mCommitCallbackRegistrar.add("InspectObject.Pay", boost::bind(&LLInspectObject::onClickPay, this)); - mCommitCallbackRegistrar.add("InspectObject.TakeFreeCopy", boost::bind(&LLInspectObject::onClickTakeFreeCopy, this)); - mCommitCallbackRegistrar.add("InspectObject.Touch", boost::bind(&LLInspectObject::onClickTouch, this)); - mCommitCallbackRegistrar.add("InspectObject.Sit", boost::bind(&LLInspectObject::onClickSit, this)); - mCommitCallbackRegistrar.add("InspectObject.Open", boost::bind(&LLInspectObject::onClickOpen, this)); - mCommitCallbackRegistrar.add("InspectObject.MoreInfo", boost::bind(&LLInspectObject::onClickMoreInfo, this)); - mCommitCallbackRegistrar.add("InspectObject.ZoomIn", boost::bind(&LLInspectObject::onClickZoomIn, this)); -} - - -LLInspectObject::~LLInspectObject() -{ - if (mSelectionUpdateSlot.connected()) - { - mSelectionUpdateSlot.disconnect(); - } -} - -/*virtual*/ -bool LLInspectObject::postBuild(void) -{ - // The XML file has sample data in it. Clear that out so we don't - // flicker when data arrives off network. - getChild<LLUICtrl>("object_name")->setValue(""); - getChild<LLUICtrl>("object_creator")->setValue(""); - getChild<LLUICtrl>("object_description")->setValue(""); - getChild<LLUICtrl>("object_media_url")->setValue(""); - // Set buttons invisible until we know what this object can do - hideButtons(); - - // Hide floater when name links clicked - LLTextBox* textbox = getChild<LLTextBox>("object_creator"); - textbox->setURLClickedCallback(boost::bind(&LLInspectObject::closeFloater, this, false) ); - - // Hook up functionality - getChild<LLUICtrl>("buy_btn")->setCommitCallback( - boost::bind(&LLInspectObject::onClickBuy, this)); - getChild<LLUICtrl>("pay_btn")->setCommitCallback( - boost::bind(&LLInspectObject::onClickPay, this)); - getChild<LLUICtrl>("take_free_copy_btn")->setCommitCallback( - boost::bind(&LLInspectObject::onClickTakeFreeCopy, this)); - getChild<LLUICtrl>("touch_btn")->setCommitCallback( - boost::bind(&LLInspectObject::onClickTouch, this)); - getChild<LLUICtrl>("sit_btn")->setCommitCallback( - boost::bind(&LLInspectObject::onClickSit, this)); - getChild<LLUICtrl>("open_btn")->setCommitCallback( - boost::bind(&LLInspectObject::onClickOpen, this)); - getChild<LLUICtrl>("more_info_btn")->setCommitCallback( - boost::bind(&LLInspectObject::onClickMoreInfo, this)); - - if (!mSelectionUpdateSlot.connected()) - { - // Watch for updates to selection properties off the network - mSelectionUpdateSlot = LLSelectMgr::getInstance()->mUpdateSignal.connect( - boost::bind(&LLInspectObject::update, this)); - } - - return true; -} - -// Multiple calls to showInstance("inspect_avatar", foo) will provide different -// LLSD for foo, which we will catch here. -//virtual -void LLInspectObject::onOpen(const LLSD& data) -{ - // Start animation - LLInspect::onOpen(data); - - // Extract appropriate avatar id - mObjectID = data["object_id"]; - - if(data.has("object_face")) - { - mObjectFace = data["object_face"]; - } - - LLInspect::repositionInspector(data); - - // Promote hovered object to a complete selection, which will also force - // a request for selected object data off the network - LLViewerObject* obj = gObjectList.findObject( mObjectID ); - if (obj) - { - // Media focus and this code fight over the select manager. - // Make sure any media is unfocused before changing the selection here. - LLViewerMediaFocus::getInstance()->clearFocus(); - - LLSelectMgr::instance().deselectAll(); - mObjectSelection = LLSelectMgr::instance().selectObjectAndFamily(obj,false,true); - - // Mark this as a transient selection - struct SetTransient : public LLSelectedNodeFunctor - { - bool apply(LLSelectNode* node) - { - node->setTransient(true); - return true; - } - } functor; - mObjectSelection->applyToNodes(&functor); - - // Does this face have media? - const LLTextureEntry* tep = obj->getTE(mObjectFace); - if (!tep) - return; - - mMediaEntry = tep->hasMedia() ? tep->getMediaData() : NULL; - if(!mMediaEntry) - return; - - mMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mMediaEntry->getMediaID()); - } -} - -// virtual -void LLInspectObject::onClose(bool app_quitting) -{ - // Release selection to deselect - mObjectSelection = NULL; - mPreviousObjectID = mObjectID; - - getChild<LLMenuButton>("gear_btn")->hideMenu(); -} - - -void LLInspectObject::update() -{ - // Performance optimization, because we listen to updates from select mgr - // but we're never destroyed. - if (!getVisible()) return; - - LLObjectSelection* selection = LLSelectMgr::getInstance()->getSelection(); - if (!selection) return; - - LLSelectNode* nodep = selection->getFirstRootNode(); - if (!nodep) return; - - // If we don't have fresh object info yet and it's the object we inspected last time, - // keep showing the previously retrieved data until we get the update. - if (!nodep->mValid && nodep->getObject()->getID() == mPreviousObjectID) - { - return; - } - - updateButtons(nodep); - updateName(nodep); - updateDescription(nodep); - updateCreator(nodep); - updatePrice(nodep); - - LLViewerObject* obj = nodep->getObject(); - if(!obj) - return; - - if ( mObjectFace < 0 - || mObjectFace >= obj->getNumTEs() ) - { - return; - } - - // Does this face have media? - const LLTextureEntry* tep = obj->getTE(mObjectFace); - if (!tep) - return; - - mMediaEntry = tep->hasMedia() ? tep->getMediaData() : NULL; - if(!mMediaEntry) - return; - - mMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mMediaEntry->getMediaID()); - - updateMediaCurrentURL(); - updateSecureBrowsing(); -} - -void LLInspectObject::hideButtons() -{ - getChild<LLUICtrl>("buy_btn")->setVisible(false); - getChild<LLUICtrl>("pay_btn")->setVisible(false); - getChild<LLUICtrl>("take_free_copy_btn")->setVisible(false); - getChild<LLUICtrl>("touch_btn")->setVisible(false); - getChild<LLUICtrl>("sit_btn")->setVisible(false); - getChild<LLUICtrl>("open_btn")->setVisible(false); -} - -// *TODO: Extract this method from lltoolpie.cpp and put somewhere shared -extern U8 final_click_action(LLViewerObject*); - -// Choose the "most relevant" operation for this object, and show a button for -// that operation as the left-most button in the inspector. -void LLInspectObject::updateButtons(LLSelectNode* nodep) -{ - // We'll start with everyone hidden and show the ones we need - hideButtons(); - - LLViewerObject* object = nodep->getObject(); - LLViewerObject *parent = (LLViewerObject*)object->getParent(); - bool for_copy = anyone_copy_selection(nodep); - bool for_sale = enable_buy_object(); - S32 price = nodep->mSaleInfo.getSalePrice(); - U8 click_action = final_click_action(object); - - if (for_copy - || (for_sale && price == 0)) - { - // Free copies have priority over other operations - getChild<LLUICtrl>("take_free_copy_btn")->setVisible(true); - } - else if (for_sale) - { - getChild<LLUICtrl>("buy_btn")->setVisible(true); - } - else if ( enable_pay_object() ) - { - getChild<LLUICtrl>("pay_btn")->setVisible(true); - } - else if (click_action == CLICK_ACTION_SIT) - { - // Click-action sit must come before "open" because many objects on - // which you can sit have scripts, and hence can be opened - getChild<LLUICtrl>("sit_btn")->setVisible(true); - updateSitLabel(nodep); - } - else if (object->flagHandleTouch() - || (parent && parent->flagHandleTouch())) - { - getChild<LLUICtrl>("touch_btn")->setVisible(true); - updateTouchLabel(nodep); - } - else if ( enable_object_open() ) - { - // Open is last because anything with a script in it can be opened - getChild<LLUICtrl>("open_btn")->setVisible(true); - } - else - { - // By default, we can sit on anything - getChild<LLUICtrl>("sit_btn")->setVisible(true); - updateSitLabel(nodep); - } - - // No flash - focusFirstItem(false, false); -} - -void LLInspectObject::updateSitLabel(LLSelectNode* nodep) -{ - LLButton* sit_btn = getChild<LLButton>("sit_btn"); - if (!nodep->mSitName.empty()) - { - sit_btn->setLabel( nodep->mSitName ); - } - else - { - sit_btn->setLabel( getString("Sit") ); - } -} - -void LLInspectObject::updateTouchLabel(LLSelectNode* nodep) -{ - LLButton* sit_btn = getChild<LLButton>("touch_btn"); - if (!nodep->mTouchName.empty()) - { - sit_btn->setLabel( nodep->mTouchName ); - } - else - { - sit_btn->setLabel( getString("Touch") ); - } -} - -void LLInspectObject::updateName(LLSelectNode* nodep) -{ - std::string name; - if (!nodep->mName.empty()) - { - name = nodep->mName; - } - else - { - name = LLTrans::getString("TooltipNoName"); - } - getChild<LLUICtrl>("object_name")->setValue(name); -} - -void LLInspectObject::updateDescription(LLSelectNode* nodep) -{ - const char* const DEFAULT_DESC = "(No Description)"; - std::string desc; - if (!nodep->mDescription.empty() - && nodep->mDescription != DEFAULT_DESC) - { - desc = nodep->mDescription; - } - - LLTextBox* textbox = getChild<LLTextBox>("object_description"); - textbox->setValue(desc); -} - -void LLInspectObject::updateMediaCurrentURL() -{ - if(!mMediaEntry) - return; - LLTextBox* textbox = getChild<LLTextBox>("object_media_url"); - std::string media_url = ""; - textbox->setValue(media_url); - textbox->setToolTip(media_url); - LLStringUtil::format_map_t args; - - if(mMediaImpl.notNull() && mMediaImpl->hasMedia()) - { - - LLPluginClassMedia* media_plugin = NULL; - media_plugin = mMediaImpl->getMediaPlugin(); - if(media_plugin) - { - if(media_plugin->pluginSupportsMediaTime()) - { - args["[CurrentURL]"] = mMediaImpl->getMediaURL(); - } - else - { - args["[CurrentURL]"] = media_plugin->getLocation(); - } - media_url = LLTrans::getString("CurrentURL", args); - - } - } - else if(mMediaEntry->getCurrentURL() != "") - { - args["[CurrentURL]"] = mMediaEntry->getCurrentURL(); - media_url = LLTrans::getString("CurrentURL", args); - } - - textbox->setText(media_url); - textbox->setToolTip(media_url); -} - -void LLInspectObject::updateCreator(LLSelectNode* nodep) -{ - // final information for display - LLStringUtil::format_map_t args; - std::string text; - - // Leave text blank until data loaded - if (nodep->mValid) - { - // Utilize automatic translation of SLURL into name to display - // a clickable link - // Objects cannot be created by a group, so use agent URL format - LLUUID creator_id = nodep->mPermissions->getCreator(); - std::string creator_url = - LLSLURL("agent", creator_id, "about").getSLURLString(); - args["[CREATOR]"] = creator_url; - - // created by one user but owned by another - std::string owner_url; - LLUUID owner_id; - bool group_owned = nodep->mPermissions->isGroupOwned(); - if (group_owned) - { - owner_id = nodep->mPermissions->getGroup(); - owner_url = LLSLURL("group", owner_id, "about").getSLURLString(); - } - else - { - owner_id = nodep->mPermissions->getOwner(); - owner_url = LLSLURL("agent", owner_id, "about").getSLURLString(); - } - args["[OWNER]"] = owner_url; - - if (creator_id == owner_id) - { - // common case, created and owned by one user - text = getString("Creator", args); - } - else - { - text = getString("CreatorAndOwner", args); - } - } - getChild<LLUICtrl>("object_creator")->setValue(text); -} - -void LLInspectObject::updatePrice(LLSelectNode* nodep) -{ - // *TODO: Only look these up once and use for both updateButtons and here - bool for_copy = anyone_copy_selection(nodep); - bool for_sale = enable_buy_object(); - S32 price = nodep->mSaleInfo.getSalePrice(); - - bool show_price_icon = false; - std::string line; - if (for_copy - || (for_sale && price == 0)) - { - line = getString("PriceFree"); - show_price_icon = true; - } - else if (for_sale) - { - LLStringUtil::format_map_t args; - args["[AMOUNT]"] = LLResMgr::getInstance()->getMonetaryString(price); - line = getString("Price", args); - show_price_icon = true; - } - getChild<LLUICtrl>("price_text")->setValue(line); - getChild<LLUICtrl>("price_icon")->setVisible(show_price_icon); -} - -void LLInspectObject::updateSecureBrowsing() -{ - bool is_secure_browsing = false; - - if(mMediaImpl.notNull() - && mMediaImpl->hasMedia()) - { - LLPluginClassMedia* media_plugin = NULL; - std::string current_url = ""; - media_plugin = mMediaImpl->getMediaPlugin(); - if(media_plugin) - { - if(media_plugin->pluginSupportsMediaTime()) - { - current_url = mMediaImpl->getMediaURL(); - } - else - { - current_url = media_plugin->getLocation(); - } - } - - std::string prefix = std::string("https://"); - std::string test_prefix = current_url.substr(0, prefix.length()); - LLStringUtil::toLower(test_prefix); - if(test_prefix == prefix) - { - is_secure_browsing = true; - } - } - getChild<LLUICtrl>("secure_browsing")->setVisible(is_secure_browsing); -} - -// For the object inspector, only unpause the fade timer -// if the gear menu is not open -void LLInspectObject::onMouseLeave(S32 x, S32 y, MASK mask) -{ - LLToggleableMenu* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu(); - if ( gear_menu && gear_menu->getVisible() ) - { - return; - } - - if(childHasVisiblePopupMenu()) - { - return; - } - - mOpenTimer.unpause(); -} - -void LLInspectObject::onClickBuy() -{ - handle_buy(); - closeFloater(); -} - -void LLInspectObject::onClickPay() -{ - handle_give_money_dialog(); - closeFloater(); -} - -void LLInspectObject::onClickTakeFreeCopy() -{ - LLObjectSelection* selection = LLSelectMgr::getInstance()->getSelection(); - if (!selection) return; - - LLSelectNode* nodep = selection->getFirstRootNode(); - if (!nodep) return; - - // Figure out if this is a "free buy" or a "take copy" - bool for_copy = anyone_copy_selection(nodep); - // Prefer to just take a free copy - if (for_copy) - { - handle_take_copy(); - } - else - { - // Buy for free (confusing, but that's how it is) - handle_buy(); - } - closeFloater(); -} - -void LLInspectObject::onClickTouch() -{ - handle_object_touch(); - closeFloater(); -} - -void LLInspectObject::onClickSit() -{ - bool is_sitting = false; - if (mObjectSelection) - { - LLSelectNode* node = mObjectSelection->getFirstRootNode(); - if (node && node->mValid) - { - LLViewerObject* root_object = node->getObject(); - if (root_object - && isAgentAvatarValid() - && gAgentAvatarp->isSitting() - && gAgentAvatarp->getRoot() == root_object) - { - is_sitting = true; - } - } - } - - if (is_sitting) - { - gAgent.standUp(); - } - else - { - handle_object_sit(mObjectID); - } - closeFloater(); -} - -void LLInspectObject::onClickOpen() -{ - LLFloaterReg::showInstance("openobject"); - closeFloater(); -} - -void LLInspectObject::onClickMoreInfo() -{ - LLFloaterReg::showInstance("task_properties"); - closeFloater(); -} - -void LLInspectObject::onClickZoomIn() -{ - handle_look_at_selection("zoom"); - closeFloater(); -} - -////////////////////////////////////////////////////////////////////////////// -// LLInspectObjectUtil -////////////////////////////////////////////////////////////////////////////// -void LLInspectObjectUtil::registerFloater() -{ - LLFloaterReg::add("inspect_object", "inspect_object.xml", - &LLFloaterReg::build<LLInspectObject>); -} - +/**
+ * @file llinspectobject.cpp
+ *
+ * $LicenseInfo:firstyear=2009&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 "llinspectobject.h"
+
+// Viewer
+#include "llagent.h" // To standup
+#include "llfloatersidepanelcontainer.h"
+#include "llinspect.h"
+#include "llmediaentry.h"
+#include "llselectmgr.h"
+#include "llslurl.h"
+#include "llviewermenu.h" // handle_object_touch(), handle_buy()
+#include "llviewermedia.h"
+#include "llviewermediafocus.h"
+#include "llviewerobjectlist.h" // to select the requested object
+#include "llvoavatarself.h"
+
+// Linden libraries
+#include "llbutton.h" // setLabel(), not virtual!
+#include "llclickaction.h"
+#include "llfloaterreg.h"
+#include "llmenubutton.h"
+#include "llresmgr.h" // getMonetaryString
+#include "llsafehandle.h"
+#include "lltextbox.h" // for description truncation
+#include "lltoggleablemenu.h"
+#include "lltrans.h"
+#include "lluictrl.h"
+
+class LLViewerObject;
+
+//////////////////////////////////////////////////////////////////////////////
+// LLInspectObject
+//////////////////////////////////////////////////////////////////////////////
+
+// Object Inspector, a small information window used when clicking
+// in the ambient inspector widget for objects in the 3D world.
+class LLInspectObject : public LLInspect
+{
+ friend class LLFloaterReg;
+
+public:
+ // object_id - Root object ID for which to show information
+ // Inspector will be positioned relative to current mouse position
+ LLInspectObject(const LLSD& object_id);
+ virtual ~LLInspectObject();
+
+ /*virtual*/ bool postBuild(void);
+
+ // Because floater is single instance, need to re-parse data on each spawn
+ // (for example, inspector about same avatar but in different position)
+ /*virtual*/ void onOpen(const LLSD& avatar_id);
+
+ // Release the selection and do other cleanup
+ /*virtual*/ void onClose(bool app_quitting);
+
+ // override the inspector mouse leave so timer is only paused if
+ // gear menu is not open
+ /* virtual */ void onMouseLeave(S32 x, S32 y, MASK mask);
+
+private:
+ // Refresh displayed data with information from selection manager
+ void update();
+
+ void hideButtons();
+ void updateButtons(LLSelectNode* nodep);
+ void updateSitLabel(LLSelectNode* nodep);
+ void updateTouchLabel(LLSelectNode* nodep);
+
+ void updateName(LLSelectNode* nodep);
+ void updateDescription(LLSelectNode* nodep);
+ void updatePrice(LLSelectNode* nodep);
+ void updateCreator(LLSelectNode* nodep);
+
+ void updateMediaCurrentURL();
+ void updateSecureBrowsing();
+
+ void onClickBuy();
+ void onClickPay();
+ void onClickTakeFreeCopy();
+ void onClickTouch();
+ void onClickSit();
+ void onClickOpen();
+ void onClickMoreInfo();
+ void onClickZoomIn();
+
+private:
+ LLUUID mObjectID;
+ LLUUID mPreviousObjectID;
+ S32 mObjectFace;
+ viewer_media_t mMediaImpl;
+ LLMediaEntry* mMediaEntry;
+ LLSafeHandle<LLObjectSelection> mObjectSelection;
+ boost::signals2::connection mSelectionUpdateSlot;
+};
+
+LLInspectObject::LLInspectObject(const LLSD& sd)
+: LLInspect( LLSD() ), // single_instance, doesn't really need key
+ mObjectID(NULL), // set in onOpen()
+ mObjectFace(0),
+ mObjectSelection(NULL),
+ mMediaImpl(NULL),
+ mMediaEntry(NULL)
+{
+ // can't make the properties request until the widgets are constructed
+ // as it might return immediately, so do it in postBuild.
+ mCommitCallbackRegistrar.add("InspectObject.Buy", boost::bind(&LLInspectObject::onClickBuy, this));
+ mCommitCallbackRegistrar.add("InspectObject.Pay", boost::bind(&LLInspectObject::onClickPay, this));
+ mCommitCallbackRegistrar.add("InspectObject.TakeFreeCopy", boost::bind(&LLInspectObject::onClickTakeFreeCopy, this));
+ mCommitCallbackRegistrar.add("InspectObject.Touch", boost::bind(&LLInspectObject::onClickTouch, this));
+ mCommitCallbackRegistrar.add("InspectObject.Sit", boost::bind(&LLInspectObject::onClickSit, this));
+ mCommitCallbackRegistrar.add("InspectObject.Open", boost::bind(&LLInspectObject::onClickOpen, this));
+ mCommitCallbackRegistrar.add("InspectObject.MoreInfo", boost::bind(&LLInspectObject::onClickMoreInfo, this));
+ mCommitCallbackRegistrar.add("InspectObject.ZoomIn", boost::bind(&LLInspectObject::onClickZoomIn, this));
+}
+
+
+LLInspectObject::~LLInspectObject()
+{
+ if (mSelectionUpdateSlot.connected())
+ {
+ mSelectionUpdateSlot.disconnect();
+ }
+}
+
+/*virtual*/
+bool LLInspectObject::postBuild(void)
+{
+ // The XML file has sample data in it. Clear that out so we don't
+ // flicker when data arrives off network.
+ getChild<LLUICtrl>("object_name")->setValue("");
+ getChild<LLUICtrl>("object_creator")->setValue("");
+ getChild<LLUICtrl>("object_description")->setValue("");
+ getChild<LLUICtrl>("object_media_url")->setValue("");
+ // Set buttons invisible until we know what this object can do
+ hideButtons();
+
+ // Hide floater when name links clicked
+ LLTextBox* textbox = getChild<LLTextBox>("object_creator");
+ textbox->setURLClickedCallback(boost::bind(&LLInspectObject::closeFloater, this, false) );
+
+ // Hook up functionality
+ getChild<LLUICtrl>("buy_btn")->setCommitCallback(
+ boost::bind(&LLInspectObject::onClickBuy, this));
+ getChild<LLUICtrl>("pay_btn")->setCommitCallback(
+ boost::bind(&LLInspectObject::onClickPay, this));
+ getChild<LLUICtrl>("take_free_copy_btn")->setCommitCallback(
+ boost::bind(&LLInspectObject::onClickTakeFreeCopy, this));
+ getChild<LLUICtrl>("touch_btn")->setCommitCallback(
+ boost::bind(&LLInspectObject::onClickTouch, this));
+ getChild<LLUICtrl>("sit_btn")->setCommitCallback(
+ boost::bind(&LLInspectObject::onClickSit, this));
+ getChild<LLUICtrl>("open_btn")->setCommitCallback(
+ boost::bind(&LLInspectObject::onClickOpen, this));
+ getChild<LLUICtrl>("more_info_btn")->setCommitCallback(
+ boost::bind(&LLInspectObject::onClickMoreInfo, this));
+
+ if (!mSelectionUpdateSlot.connected())
+ {
+ // Watch for updates to selection properties off the network
+ mSelectionUpdateSlot = LLSelectMgr::getInstance()->mUpdateSignal.connect(
+ boost::bind(&LLInspectObject::update, this));
+ }
+
+ return true;
+}
+
+// Multiple calls to showInstance("inspect_avatar", foo) will provide different
+// LLSD for foo, which we will catch here.
+//virtual
+void LLInspectObject::onOpen(const LLSD& data)
+{
+ // Start animation
+ LLInspect::onOpen(data);
+
+ // Extract appropriate avatar id
+ mObjectID = data["object_id"];
+
+ if(data.has("object_face"))
+ {
+ mObjectFace = data["object_face"];
+ }
+
+ LLInspect::repositionInspector(data);
+
+ // Promote hovered object to a complete selection, which will also force
+ // a request for selected object data off the network
+ LLViewerObject* obj = gObjectList.findObject( mObjectID );
+ if (obj)
+ {
+ // Media focus and this code fight over the select manager.
+ // Make sure any media is unfocused before changing the selection here.
+ LLViewerMediaFocus::getInstance()->clearFocus();
+
+ LLSelectMgr::instance().deselectAll();
+ mObjectSelection = LLSelectMgr::instance().selectObjectAndFamily(obj,false,true);
+
+ // Mark this as a transient selection
+ struct SetTransient : public LLSelectedNodeFunctor
+ {
+ bool apply(LLSelectNode* node)
+ {
+ node->setTransient(true);
+ return true;
+ }
+ } functor;
+ mObjectSelection->applyToNodes(&functor);
+
+ // Does this face have media?
+ const LLTextureEntry* tep = obj->getTE(mObjectFace);
+ if (!tep)
+ return;
+
+ mMediaEntry = tep->hasMedia() ? tep->getMediaData() : NULL;
+ if(!mMediaEntry)
+ return;
+
+ mMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mMediaEntry->getMediaID());
+ }
+}
+
+// virtual
+void LLInspectObject::onClose(bool app_quitting)
+{
+ // Release selection to deselect
+ mObjectSelection = NULL;
+ mPreviousObjectID = mObjectID;
+
+ getChild<LLMenuButton>("gear_btn")->hideMenu();
+}
+
+
+void LLInspectObject::update()
+{
+ // Performance optimization, because we listen to updates from select mgr
+ // but we're never destroyed.
+ if (!getVisible()) return;
+
+ LLObjectSelection* selection = LLSelectMgr::getInstance()->getSelection();
+ if (!selection) return;
+
+ LLSelectNode* nodep = selection->getFirstRootNode();
+ if (!nodep) return;
+
+ // If we don't have fresh object info yet and it's the object we inspected last time,
+ // keep showing the previously retrieved data until we get the update.
+ if (!nodep->mValid && nodep->getObject()->getID() == mPreviousObjectID)
+ {
+ return;
+ }
+
+ updateButtons(nodep);
+ updateName(nodep);
+ updateDescription(nodep);
+ updateCreator(nodep);
+ updatePrice(nodep);
+
+ LLViewerObject* obj = nodep->getObject();
+ if(!obj)
+ return;
+
+ if ( mObjectFace < 0
+ || mObjectFace >= obj->getNumTEs() )
+ {
+ return;
+ }
+
+ // Does this face have media?
+ const LLTextureEntry* tep = obj->getTE(mObjectFace);
+ if (!tep)
+ return;
+
+ mMediaEntry = tep->hasMedia() ? tep->getMediaData() : NULL;
+ if(!mMediaEntry)
+ return;
+
+ mMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mMediaEntry->getMediaID());
+
+ updateMediaCurrentURL();
+ updateSecureBrowsing();
+}
+
+void LLInspectObject::hideButtons()
+{
+ getChild<LLUICtrl>("buy_btn")->setVisible(false);
+ getChild<LLUICtrl>("pay_btn")->setVisible(false);
+ getChild<LLUICtrl>("take_free_copy_btn")->setVisible(false);
+ getChild<LLUICtrl>("touch_btn")->setVisible(false);
+ getChild<LLUICtrl>("sit_btn")->setVisible(false);
+ getChild<LLUICtrl>("open_btn")->setVisible(false);
+}
+
+// *TODO: Extract this method from lltoolpie.cpp and put somewhere shared
+extern U8 final_click_action(LLViewerObject*);
+
+// Choose the "most relevant" operation for this object, and show a button for
+// that operation as the left-most button in the inspector.
+void LLInspectObject::updateButtons(LLSelectNode* nodep)
+{
+ // We'll start with everyone hidden and show the ones we need
+ hideButtons();
+
+ LLViewerObject* object = nodep->getObject();
+ LLViewerObject *parent = (LLViewerObject*)object->getParent();
+ bool for_copy = anyone_copy_selection(nodep);
+ bool for_sale = enable_buy_object();
+ S32 price = nodep->mSaleInfo.getSalePrice();
+ U8 click_action = final_click_action(object);
+
+ if (for_copy
+ || (for_sale && price == 0))
+ {
+ // Free copies have priority over other operations
+ getChild<LLUICtrl>("take_free_copy_btn")->setVisible(true);
+ }
+ else if (for_sale)
+ {
+ getChild<LLUICtrl>("buy_btn")->setVisible(true);
+ }
+ else if ( enable_pay_object() )
+ {
+ getChild<LLUICtrl>("pay_btn")->setVisible(true);
+ }
+ else if (click_action == CLICK_ACTION_SIT)
+ {
+ // Click-action sit must come before "open" because many objects on
+ // which you can sit have scripts, and hence can be opened
+ getChild<LLUICtrl>("sit_btn")->setVisible(true);
+ updateSitLabel(nodep);
+ }
+ else if (object->flagHandleTouch()
+ || (parent && parent->flagHandleTouch()))
+ {
+ getChild<LLUICtrl>("touch_btn")->setVisible(true);
+ updateTouchLabel(nodep);
+ }
+ else if ( enable_object_open() )
+ {
+ // Open is last because anything with a script in it can be opened
+ getChild<LLUICtrl>("open_btn")->setVisible(true);
+ }
+ else
+ {
+ // By default, we can sit on anything
+ getChild<LLUICtrl>("sit_btn")->setVisible(true);
+ updateSitLabel(nodep);
+ }
+
+ // No flash
+ focusFirstItem(false, false);
+}
+
+void LLInspectObject::updateSitLabel(LLSelectNode* nodep)
+{
+ LLButton* sit_btn = getChild<LLButton>("sit_btn");
+ if (!nodep->mSitName.empty())
+ {
+ sit_btn->setLabel( nodep->mSitName );
+ }
+ else
+ {
+ sit_btn->setLabel( getString("Sit") );
+ }
+}
+
+void LLInspectObject::updateTouchLabel(LLSelectNode* nodep)
+{
+ LLButton* sit_btn = getChild<LLButton>("touch_btn");
+ if (!nodep->mTouchName.empty())
+ {
+ sit_btn->setLabel( nodep->mTouchName );
+ }
+ else
+ {
+ sit_btn->setLabel( getString("Touch") );
+ }
+}
+
+void LLInspectObject::updateName(LLSelectNode* nodep)
+{
+ std::string name;
+ if (!nodep->mName.empty())
+ {
+ name = nodep->mName;
+ }
+ else
+ {
+ name = LLTrans::getString("TooltipNoName");
+ }
+ getChild<LLUICtrl>("object_name")->setValue(name);
+}
+
+void LLInspectObject::updateDescription(LLSelectNode* nodep)
+{
+ const char* const DEFAULT_DESC = "(No Description)";
+ std::string desc;
+ if (!nodep->mDescription.empty()
+ && nodep->mDescription != DEFAULT_DESC)
+ {
+ desc = nodep->mDescription;
+ }
+
+ LLTextBox* textbox = getChild<LLTextBox>("object_description");
+ textbox->setValue(desc);
+}
+
+void LLInspectObject::updateMediaCurrentURL()
+{
+ if(!mMediaEntry)
+ return;
+ LLTextBox* textbox = getChild<LLTextBox>("object_media_url");
+ std::string media_url = "";
+ textbox->setValue(media_url);
+ textbox->setToolTip(media_url);
+ LLStringUtil::format_map_t args;
+
+ if(mMediaImpl.notNull() && mMediaImpl->hasMedia())
+ {
+
+ LLPluginClassMedia* media_plugin = NULL;
+ media_plugin = mMediaImpl->getMediaPlugin();
+ if(media_plugin)
+ {
+ if(media_plugin->pluginSupportsMediaTime())
+ {
+ args["[CurrentURL]"] = mMediaImpl->getMediaURL();
+ }
+ else
+ {
+ args["[CurrentURL]"] = media_plugin->getLocation();
+ }
+ media_url = LLTrans::getString("CurrentURL", args);
+
+ }
+ }
+ else if(mMediaEntry->getCurrentURL() != "")
+ {
+ args["[CurrentURL]"] = mMediaEntry->getCurrentURL();
+ media_url = LLTrans::getString("CurrentURL", args);
+ }
+
+ textbox->setText(media_url);
+ textbox->setToolTip(media_url);
+}
+
+void LLInspectObject::updateCreator(LLSelectNode* nodep)
+{
+ // final information for display
+ LLStringUtil::format_map_t args;
+ std::string text;
+
+ // Leave text blank until data loaded
+ if (nodep->mValid)
+ {
+ // Utilize automatic translation of SLURL into name to display
+ // a clickable link
+ // Objects cannot be created by a group, so use agent URL format
+ LLUUID creator_id = nodep->mPermissions->getCreator();
+ std::string creator_url =
+ LLSLURL("agent", creator_id, "about").getSLURLString();
+ args["[CREATOR]"] = creator_url;
+
+ // created by one user but owned by another
+ std::string owner_url;
+ LLUUID owner_id;
+ bool group_owned = nodep->mPermissions->isGroupOwned();
+ if (group_owned)
+ {
+ owner_id = nodep->mPermissions->getGroup();
+ owner_url = LLSLURL("group", owner_id, "about").getSLURLString();
+ }
+ else
+ {
+ owner_id = nodep->mPermissions->getOwner();
+ owner_url = LLSLURL("agent", owner_id, "about").getSLURLString();
+ }
+ args["[OWNER]"] = owner_url;
+
+ if (creator_id == owner_id)
+ {
+ // common case, created and owned by one user
+ text = getString("Creator", args);
+ }
+ else
+ {
+ text = getString("CreatorAndOwner", args);
+ }
+ }
+ getChild<LLUICtrl>("object_creator")->setValue(text);
+}
+
+void LLInspectObject::updatePrice(LLSelectNode* nodep)
+{
+ // *TODO: Only look these up once and use for both updateButtons and here
+ bool for_copy = anyone_copy_selection(nodep);
+ bool for_sale = enable_buy_object();
+ S32 price = nodep->mSaleInfo.getSalePrice();
+
+ bool show_price_icon = false;
+ std::string line;
+ if (for_copy
+ || (for_sale && price == 0))
+ {
+ line = getString("PriceFree");
+ show_price_icon = true;
+ }
+ else if (for_sale)
+ {
+ LLStringUtil::format_map_t args;
+ args["[AMOUNT]"] = LLResMgr::getInstance()->getMonetaryString(price);
+ line = getString("Price", args);
+ show_price_icon = true;
+ }
+ getChild<LLUICtrl>("price_text")->setValue(line);
+ getChild<LLUICtrl>("price_icon")->setVisible(show_price_icon);
+}
+
+void LLInspectObject::updateSecureBrowsing()
+{
+ bool is_secure_browsing = false;
+
+ if(mMediaImpl.notNull()
+ && mMediaImpl->hasMedia())
+ {
+ LLPluginClassMedia* media_plugin = NULL;
+ std::string current_url = "";
+ media_plugin = mMediaImpl->getMediaPlugin();
+ if(media_plugin)
+ {
+ if(media_plugin->pluginSupportsMediaTime())
+ {
+ current_url = mMediaImpl->getMediaURL();
+ }
+ else
+ {
+ current_url = media_plugin->getLocation();
+ }
+ }
+
+ std::string prefix = std::string("https://");
+ std::string test_prefix = current_url.substr(0, prefix.length());
+ LLStringUtil::toLower(test_prefix);
+ if(test_prefix == prefix)
+ {
+ is_secure_browsing = true;
+ }
+ }
+ getChild<LLUICtrl>("secure_browsing")->setVisible(is_secure_browsing);
+}
+
+// For the object inspector, only unpause the fade timer
+// if the gear menu is not open
+void LLInspectObject::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ LLToggleableMenu* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu();
+ if ( gear_menu && gear_menu->getVisible() )
+ {
+ return;
+ }
+
+ if(childHasVisiblePopupMenu())
+ {
+ return;
+ }
+
+ mOpenTimer.unpause();
+}
+
+void LLInspectObject::onClickBuy()
+{
+ handle_buy();
+ closeFloater();
+}
+
+void LLInspectObject::onClickPay()
+{
+ handle_give_money_dialog();
+ closeFloater();
+}
+
+void LLInspectObject::onClickTakeFreeCopy()
+{
+ LLObjectSelection* selection = LLSelectMgr::getInstance()->getSelection();
+ if (!selection) return;
+
+ LLSelectNode* nodep = selection->getFirstRootNode();
+ if (!nodep) return;
+
+ // Figure out if this is a "free buy" or a "take copy"
+ bool for_copy = anyone_copy_selection(nodep);
+ // Prefer to just take a free copy
+ if (for_copy)
+ {
+ handle_take_copy();
+ }
+ else
+ {
+ // Buy for free (confusing, but that's how it is)
+ handle_buy();
+ }
+ closeFloater();
+}
+
+void LLInspectObject::onClickTouch()
+{
+ handle_object_touch();
+ closeFloater();
+}
+
+void LLInspectObject::onClickSit()
+{
+ bool is_sitting = false;
+ if (mObjectSelection)
+ {
+ LLSelectNode* node = mObjectSelection->getFirstRootNode();
+ if (node && node->mValid)
+ {
+ LLViewerObject* root_object = node->getObject();
+ if (root_object
+ && isAgentAvatarValid()
+ && gAgentAvatarp->isSitting()
+ && gAgentAvatarp->getRoot() == root_object)
+ {
+ is_sitting = true;
+ }
+ }
+ }
+
+ if (is_sitting)
+ {
+ gAgent.standUp();
+ }
+ else
+ {
+ handle_object_sit(mObjectID);
+ }
+ closeFloater();
+}
+
+void LLInspectObject::onClickOpen()
+{
+ LLFloaterReg::showInstance("openobject");
+ closeFloater();
+}
+
+void LLInspectObject::onClickMoreInfo()
+{
+ LLFloaterReg::showInstance("task_properties");
+ closeFloater();
+}
+
+void LLInspectObject::onClickZoomIn()
+{
+ handle_look_at_selection("zoom");
+ closeFloater();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// LLInspectObjectUtil
+//////////////////////////////////////////////////////////////////////////////
+void LLInspectObjectUtil::registerFloater()
+{
+ LLFloaterReg::add("inspect_object", "inspect_object.xml",
+ &LLFloaterReg::build<LLInspectObject>);
+}
+
|