/** * @file llpanelplaces.cpp * @brief Side Bar "Places" panel * * $LicenseInfo:firstyear=2009&license=viewergpl$ * * Copyright (c) 2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llpanelplaces.h" #include "llassettype.h" #include "llwindow.h" #include "llinventory.h" #include "lllandmark.h" #include "llparcel.h" #include "llcombobox.h" #include "llfiltereditor.h" #include "llfloaterreg.h" #include "llnotificationsutil.h" #include "lltabcontainer.h" #include "lltexteditor.h" #include "lltrans.h" #include "lluictrlfactory.h" #include "llagent.h" #include "llagentpicksinfo.h" #include "llavatarpropertiesprocessor.h" #include "llfloaterworldmap.h" #include "llinventorybridge.h" #include "llinventoryobserver.h" #include "llinventorymodel.h" #include "lllandmarkactions.h" #include "lllandmarklist.h" #include "llpanellandmarkinfo.h" #include "llpanellandmarks.h" #include "llpanelpick.h" #include "llpanelplaceprofile.h" #include "llpanelteleporthistory.h" #include "llremoteparcelrequest.h" #include "llteleporthistorystorage.h" #include "lltoggleablemenu.h" #include "llviewerinventory.h" #include "llviewermenu.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerwindow.h" static const S32 LANDMARK_FOLDERS_MENU_WIDTH = 250; static const std::string AGENT_INFO_TYPE = "agent"; static const std::string CREATE_LANDMARK_INFO_TYPE = "create_landmark"; static const std::string LANDMARK_INFO_TYPE = "landmark"; static const std::string REMOTE_PLACE_INFO_TYPE = "remote_place"; static const std::string TELEPORT_HISTORY_INFO_TYPE = "teleport_history"; // Helper functions static bool is_agent_in_selected_parcel(LLParcel* parcel); static void onSLURLBuilt(std::string& slurl); //Observer classes class LLPlacesParcelObserver : public LLParcelObserver { public: LLPlacesParcelObserver(LLPanelPlaces* places_panel) : LLParcelObserver(), mPlaces(places_panel) {} /*virtual*/ void changed() { if (mPlaces) mPlaces->changedParcelSelection(); } private: LLPanelPlaces* mPlaces; }; class LLPlacesInventoryObserver : public LLInventoryObserver { public: LLPlacesInventoryObserver(LLPanelPlaces* places_panel) : LLInventoryObserver(), mPlaces(places_panel) {} /*virtual*/ void changed(U32 mask) { if (mPlaces) mPlaces->changedInventory(mask); } private: LLPanelPlaces* mPlaces; }; class LLPlacesRemoteParcelInfoObserver : public LLRemoteParcelInfoObserver { public: LLPlacesRemoteParcelInfoObserver(LLPanelPlaces* places_panel) : LLRemoteParcelInfoObserver(), mPlaces(places_panel) {} ~LLPlacesRemoteParcelInfoObserver() { // remove any in-flight observers std::set<LLUUID>::iterator it; for (it = mParcelIDs.begin(); it != mParcelIDs.end(); ++it) { const LLUUID &id = *it; LLRemoteParcelInfoProcessor::getInstance()->removeObserver(id, this); } mParcelIDs.clear(); } /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data) { if (mPlaces) { mPlaces->changedGlobalPos(LLVector3d(parcel_data.global_x, parcel_data.global_y, parcel_data.global_z)); } mParcelIDs.erase(parcel_data.parcel_id); LLRemoteParcelInfoProcessor::getInstance()->removeObserver(parcel_data.parcel_id, this); } /*virtual*/ void setParcelID(const LLUUID& parcel_id) { if (!parcel_id.isNull()) { mParcelIDs.insert(parcel_id); LLRemoteParcelInfoProcessor::getInstance()->addObserver(parcel_id, this); LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id); } } /*virtual*/ void setErrorStatus(U32 status, const std::string& reason) { llerrs << "Can't complete remote parcel request. Http Status: " << status << ". Reason : " << reason << llendl; } private: std::set<LLUUID> mParcelIDs; LLPanelPlaces* mPlaces; }; static LLRegisterPanelClassWrapper<LLPanelPlaces> t_places("panel_places"); LLPanelPlaces::LLPanelPlaces() : LLPanel(), mActivePanel(NULL), mFilterEditor(NULL), mPlaceProfile(NULL), mLandmarkInfo(NULL), mPickPanel(NULL), mItem(NULL), mPlaceMenu(NULL), mLandmarkMenu(NULL), mPosGlobal(), isLandmarkEditModeOn(false) { mParcelObserver = new LLPlacesParcelObserver(this); mInventoryObserver = new LLPlacesInventoryObserver(this); mRemoteParcelObserver = new LLPlacesRemoteParcelInfoObserver(this); gInventory.addObserver(mInventoryObserver); LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback( boost::bind(&LLPanelPlaces::updateVerbs, this)); //LLUICtrlFactory::getInstance()->buildPanel(this, "panel_places.xml"); // Called from LLRegisterPanelClass::defaultPanelClassBuilder() } LLPanelPlaces::~LLPanelPlaces() { if (gInventory.containsObserver(mInventoryObserver)) gInventory.removeObserver(mInventoryObserver); LLViewerParcelMgr::getInstance()->removeObserver(mParcelObserver); delete mInventoryObserver; delete mParcelObserver; delete mRemoteParcelObserver; } BOOL LLPanelPlaces::postBuild() { mTeleportBtn = getChild<LLButton>("teleport_btn"); mTeleportBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onTeleportButtonClicked, this)); mShowOnMapBtn = getChild<LLButton>("map_btn"); mShowOnMapBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onShowOnMapButtonClicked, this)); mEditBtn = getChild<LLButton>("edit_btn"); mEditBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this)); mSaveBtn = getChild<LLButton>("save_btn"); mSaveBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onSaveButtonClicked, this)); mCancelBtn = getChild<LLButton>("cancel_btn"); mCancelBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onCancelButtonClicked, this)); mCloseBtn = getChild<LLButton>("close_btn"); mCloseBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this)); mOverflowBtn = getChild<LLButton>("overflow_btn"); mOverflowBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onOverflowButtonClicked, this)); LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; registrar.add("Places.OverflowMenu.Action", boost::bind(&LLPanelPlaces::onOverflowMenuItemClicked, this, _2)); LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; enable_registrar.add("Places.OverflowMenu.Enable", boost::bind(&LLPanelPlaces::onOverflowMenuItemEnable, this, _2)); mPlaceMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_place.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); if (!mPlaceMenu) { llwarns << "Error loading Place menu" << llendl; } mLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); if (!mLandmarkMenu) { llwarns << "Error loading Landmark menu" << llendl; } mTabContainer = getChild<LLTabContainer>("Places Tabs"); if (mTabContainer) { mTabContainer->setCommitCallback(boost::bind(&LLPanelPlaces::onTabSelected, this)); } mFilterEditor = getChild<LLFilterEditor>("Filter"); if (mFilterEditor) { mFilterEditor->setCommitCallback(boost::bind(&LLPanelPlaces::onFilterEdit, this, _2, false)); } mPlaceProfile = getChild<LLPanelPlaceProfile>("panel_place_profile"); mLandmarkInfo = getChild<LLPanelLandmarkInfo>("panel_landmark_info"); if (!mPlaceProfile || !mLandmarkInfo) return FALSE; LLButton* back_btn = mPlaceProfile->getChild<LLButton>("back_btn"); back_btn->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this)); back_btn = mLandmarkInfo->getChild<LLButton>("back_btn"); back_btn->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this)); LLLineEditor* title_editor = mLandmarkInfo->getChild<LLLineEditor>("title_editor"); title_editor->setKeystrokeCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this), NULL); LLTextEditor* notes_editor = mLandmarkInfo->getChild<LLTextEditor>("notes_editor"); notes_editor->setKeystrokeCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this)); LLComboBox* folder_combo = mLandmarkInfo->getChild<LLComboBox>("folder_combo"); folder_combo->setCommitCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this)); return TRUE; } void LLPanelPlaces::onOpen(const LLSD& key) { if(!mPlaceProfile || !mLandmarkInfo || key.size() == 0) return; mFilterEditor->clear(); onFilterEdit("", false); mPlaceInfoType = key["type"].asString(); mPosGlobal.setZero(); mItem = NULL; isLandmarkEditModeOn = false; togglePlaceInfoPanel(TRUE); if (mPlaceInfoType == AGENT_INFO_TYPE) { mPlaceProfile->setInfoType(LLPanelPlaceInfo::AGENT); } else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) { mLandmarkInfo->setInfoType(LLPanelPlaceInfo::CREATE_LANDMARK); if (key.has("x") && key.has("y") && key.has("z")) { mPosGlobal = LLVector3d(key["x"].asReal(), key["y"].asReal(), key["z"].asReal()); } else { mPosGlobal = gAgent.getPositionGlobal(); } mLandmarkInfo->displayParcelInfo(LLUUID(), mPosGlobal); // Disable Save button because there is no item to save yet. // The button will be enabled in onLandmarkLoaded callback. mSaveBtn->setEnabled(FALSE); } else if (mPlaceInfoType == LANDMARK_INFO_TYPE) { mLandmarkInfo->setInfoType(LLPanelPlaceInfo::LANDMARK); LLInventoryItem* item = gInventory.getItem(key["id"].asUUID()); if (!item) return; setItem(item); } else if (mPlaceInfoType == REMOTE_PLACE_INFO_TYPE) { if (key.has("id")) { LLUUID parcel_id = key["id"].asUUID(); mPlaceProfile->setParcelID(parcel_id); // query the server to get the global 3D position of this // parcel - we need this for teleport/mapping functions. mRemoteParcelObserver->setParcelID(parcel_id); } else { mPosGlobal = LLVector3d(key["x"].asReal(), key["y"].asReal(), key["z"].asReal()); mPlaceProfile->displayParcelInfo(LLUUID(), mPosGlobal); } mPlaceProfile->setInfoType(LLPanelPlaceInfo::PLACE); } else if (mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) { S32 index = key["id"].asInteger(); const LLTeleportHistoryStorage::slurl_list_t& hist_items = LLTeleportHistoryStorage::getInstance()->getItems(); mPosGlobal = hist_items[index].mGlobalPos; mPlaceProfile->setInfoType(LLPanelPlaceInfo::TELEPORT_HISTORY); mPlaceProfile->displayParcelInfo(LLUUID(), mPosGlobal); } updateVerbs(); LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); if (!parcel_mgr) return; // Start using LLViewerParcelMgr for land selection if // information about nearby land is requested. // Otherwise stop using land selection and deselect land. if (mPlaceInfoType == AGENT_INFO_TYPE) { parcel_mgr->addObserver(mParcelObserver); parcel_mgr->selectParcelAt(gAgent.getPositionGlobal()); } else { parcel_mgr->removeObserver(mParcelObserver); if (!parcel_mgr->selectionEmpty()) { parcel_mgr->deselectLand(); } } } void LLPanelPlaces::setItem(LLInventoryItem* item) { if (!mLandmarkInfo || !item) return; mItem = item; LLAssetType::EType item_type = mItem->getActualType(); if (item_type == LLAssetType::AT_LANDMARK || item_type == LLAssetType::AT_LINK) { // If the item is a link get a linked item if (item_type == LLAssetType::AT_LINK) { mItem = gInventory.getItem(mItem->getLinkedUUID()); if (mItem.isNull()) return; } } else { return; } // Check if item is in agent's inventory and he has the permission to modify it. BOOL is_landmark_editable = gInventory.isObjectDescendentOf(mItem->getUUID(), gInventory.getRootFolderID()) && mItem->getPermissions().allowModifyBy(gAgent.getID()); mEditBtn->setEnabled(is_landmark_editable); mSaveBtn->setEnabled(is_landmark_editable); if (is_landmark_editable) { if(!mLandmarkInfo->setLandmarkFolder(mItem->getParentUUID()) && !mItem->getParentUUID().isNull()) { const LLViewerInventoryCategory* cat = gInventory.getCategory(mItem->getParentUUID()); if (cat) { std::string cat_fullname = LLPanelLandmarkInfo::getFullFolderName(cat); LLComboBox* folderList = mLandmarkInfo->getChild<LLComboBox>("folder_combo"); folderList->add(cat_fullname, cat->getUUID(), ADD_TOP); } } } mLandmarkInfo->displayItemInfo(mItem); LLLandmark* lm = gLandmarkList.getAsset(mItem->getAssetUUID(), boost::bind(&LLPanelPlaces::onLandmarkLoaded, this, _1)); if (lm) { onLandmarkLoaded(lm); } } void LLPanelPlaces::onLandmarkLoaded(LLLandmark* landmark) { if (!mLandmarkInfo) return; LLUUID region_id; landmark->getRegionID(region_id); landmark->getGlobalPos(mPosGlobal); mLandmarkInfo->displayParcelInfo(region_id, mPosGlobal); mSaveBtn->setEnabled(TRUE); } void LLPanelPlaces::onFilterEdit(const std::string& search_string, bool force_filter) { if (!mActivePanel) return; if (force_filter || mActivePanel->getFilterSubString() != search_string) { std::string string = search_string; // Searches are case-insensitive LLStringUtil::toUpper(string); LLStringUtil::trimHead(string); mActivePanel->onSearchEdit(string); } } void LLPanelPlaces::onTabSelected() { mActivePanel = dynamic_cast<LLPanelPlacesTab*>(mTabContainer->getCurrentPanel()); if (!mActivePanel) return; onFilterEdit(mActivePanel->getFilterSubString(), true); mActivePanel->updateVerbs(); } void LLPanelPlaces::onTeleportButtonClicked() { LLPanelPlaceInfo* panel = getCurrentInfoPanel(); if (panel && panel->getVisible()) { if (mPlaceInfoType == LANDMARK_INFO_TYPE) { LLSD payload; payload["asset_id"] = mItem->getAssetUUID(); LLNotificationsUtil::add("TeleportFromLandmark", LLSD(), payload); } else if (mPlaceInfoType == AGENT_INFO_TYPE || mPlaceInfoType == REMOTE_PLACE_INFO_TYPE || mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) { LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); if (!mPosGlobal.isExactlyZero() && worldmap_instance) { gAgent.teleportViaLocation(mPosGlobal); worldmap_instance->trackLocation(mPosGlobal); } } } else { if (mActivePanel) mActivePanel->onTeleport(); } } void LLPanelPlaces::onShowOnMapButtonClicked() { LLPanelPlaceInfo* panel = getCurrentInfoPanel(); if (panel && panel->getVisible()) { LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); if(!worldmap_instance) return; if (mPlaceInfoType == AGENT_INFO_TYPE || mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE || mPlaceInfoType == REMOTE_PLACE_INFO_TYPE || mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) { if (!mPosGlobal.isExactlyZero()) { worldmap_instance->trackLocation(mPosGlobal); LLFloaterReg::showInstance("world_map", "center"); } } else if (mPlaceInfoType == LANDMARK_INFO_TYPE) { LLLandmark* landmark = gLandmarkList.getAsset(mItem->getAssetUUID()); if (!landmark) return; LLVector3d landmark_global_pos; if (!landmark->getGlobalPos(landmark_global_pos)) return; if (!landmark_global_pos.isExactlyZero()) { worldmap_instance->trackLocation(landmark_global_pos); LLFloaterReg::showInstance("world_map", "center"); } } } else { if (mActivePanel) mActivePanel->onShowOnMap(); } } void LLPanelPlaces::onEditButtonClicked() { if (!mLandmarkInfo || isLandmarkEditModeOn) return; isLandmarkEditModeOn = true; mLandmarkInfo->toggleLandmarkEditMode(TRUE); updateVerbs(); } void LLPanelPlaces::onSaveButtonClicked() { if (!mLandmarkInfo || mItem.isNull()) return; std::string current_title_value = mLandmarkInfo->getLandmarkTitle(); std::string item_title_value = mItem->getName(); std::string current_notes_value = mLandmarkInfo->getLandmarkNotes(); std::string item_notes_value = mItem->getDescription(); LLStringUtil::trim(current_title_value); LLStringUtil::trim(current_notes_value); LLUUID item_id = mItem->getUUID(); LLUUID folder_id = mLandmarkInfo->getLandmarkFolder(); LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(mItem); if (!current_title_value.empty() && (item_title_value != current_title_value || item_notes_value != current_notes_value)) { new_item->rename(current_title_value); new_item->setDescription(current_notes_value); new_item->updateServer(FALSE); } if(folder_id != mItem->getParentUUID()) { LLInventoryModel::update_list_t update; LLInventoryModel::LLCategoryUpdate old_folder(mItem->getParentUUID(),-1); update.push_back(old_folder); LLInventoryModel::LLCategoryUpdate new_folder(folder_id, 1); update.push_back(new_folder); gInventory.accountForUpdate(update); new_item->setParent(folder_id); new_item->updateParentOnServer(FALSE); } gInventory.updateItem(new_item); gInventory.notifyObservers(); onCancelButtonClicked(); } void LLPanelPlaces::onCancelButtonClicked() { if (!mLandmarkInfo) return; if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) { onBackButtonClicked(); } else { mLandmarkInfo->toggleLandmarkEditMode(FALSE); isLandmarkEditModeOn = false; updateVerbs(); // Reload the landmark properties. mLandmarkInfo->displayItemInfo(mItem); } } void LLPanelPlaces::onOverflowButtonClicked() { LLToggleableMenu* menu; bool is_agent_place_info_visible = mPlaceInfoType == AGENT_INFO_TYPE; if ((is_agent_place_info_visible || mPlaceInfoType == "remote_place" || mPlaceInfoType == "teleport_history") && mPlaceMenu != NULL) { menu = mPlaceMenu; // Enable adding a landmark only for agent current parcel and if // there is no landmark already pointing to that parcel in agent's inventory. menu->getChild<LLMenuItemCallGL>("landmark")->setEnabled(is_agent_place_info_visible && !LLLandmarkActions::landmarkAlreadyExists()); } else if (mPlaceInfoType == LANDMARK_INFO_TYPE && mLandmarkMenu != NULL) { menu = mLandmarkMenu; BOOL is_landmark_removable = FALSE; if (mItem.notNull()) { const LLUUID& item_id = mItem->getUUID(); const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); is_landmark_removable = gInventory.isObjectDescendentOf(item_id, gInventory.getRootFolderID()) && !gInventory.isObjectDescendentOf(item_id, trash_id); } menu->getChild<LLMenuItemCallGL>("delete")->setEnabled(is_landmark_removable); } else { return; } if (!menu->toggleVisibility()) return; if (menu->getButtonRect().isEmpty()) { menu->setButtonRect(mOverflowBtn); } menu->updateParent(LLMenuGL::sMenuContainer); LLRect rect = mOverflowBtn->getRect(); LLMenuGL::showPopup(this, menu, rect.mRight, rect.mTop); } bool LLPanelPlaces::onOverflowMenuItemEnable(const LLSD& param) { std::string value = param.asString(); if("can_create_pick" == value) { return !LLAgentPicksInfo::getInstance()->isPickLimitReached(); } return true; } void LLPanelPlaces::onOverflowMenuItemClicked(const LLSD& param) { std::string item = param.asString(); if (item == "landmark") { LLSD key; key["type"] = CREATE_LANDMARK_INFO_TYPE; key["x"] = mPosGlobal.mdV[VX]; key["y"] = mPosGlobal.mdV[VY]; key["z"] = mPosGlobal.mdV[VZ]; onOpen(key); } else if (item == "copy") { LLLandmarkActions::getSLURLfromPosGlobal(mPosGlobal, boost::bind(&onSLURLBuilt, _1)); } else if (item == "delete") { gInventory.removeItem(mItem->getUUID()); onBackButtonClicked(); } else if (item == "pick") { if (mPickPanel == NULL) { mPickPanel = LLPanelPickEdit::create(); addChild(mPickPanel); mPickPanel->setExitCallback(boost::bind(&LLPanelPlaces::togglePickPanel, this, FALSE)); mPickPanel->setCancelCallback(boost::bind(&LLPanelPlaces::togglePickPanel, this, FALSE)); mPickPanel->setSaveCallback(boost::bind(&LLPanelPlaces::togglePickPanel, this, FALSE)); } togglePickPanel(TRUE); mPickPanel->onOpen(LLSD()); LLPanelPlaceInfo* panel = getCurrentInfoPanel(); if (panel) { panel->createPick(mPosGlobal, mPickPanel); } LLRect rect = getRect(); mPickPanel->reshape(rect.getWidth(), rect.getHeight()); mPickPanel->setRect(rect); } else if (item == "add_to_favbar") { if ( mItem.notNull() ) { const LLUUID& favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); if ( favorites_id.notNull() ) { copy_inventory_item(gAgent.getID(), mItem->getPermissions().getOwner(), mItem->getUUID(), favorites_id, std::string(), LLPointer<LLInventoryCallback>(NULL)); llinfos << "Copied inventory item #" << mItem->getUUID() << " to favorites." << llendl; } } } } void LLPanelPlaces::onBackButtonClicked() { togglePlaceInfoPanel(FALSE); // Resetting mPlaceInfoType when Place Info panel is closed. mPlaceInfoType = LLStringUtil::null; isLandmarkEditModeOn = false; updateVerbs(); } void LLPanelPlaces::togglePickPanel(BOOL visible) { if (mPickPanel) mPickPanel->setVisible(visible); } void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) { if (!mPlaceProfile || !mLandmarkInfo) return; mFilterEditor->setVisible(!visible); mTabContainer->setVisible(!visible); if (mPlaceInfoType == AGENT_INFO_TYPE || mPlaceInfoType == REMOTE_PLACE_INFO_TYPE || mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) { mPlaceProfile->setVisible(visible); if (visible) { mPlaceProfile->resetLocation(); LLRect rect = getRect(); LLRect new_rect = LLRect(rect.mLeft, rect.mTop, rect.mRight, mTabContainer->getRect().mBottom); mPlaceProfile->reshape(new_rect.getWidth(), new_rect.getHeight()); mLandmarkInfo->setVisible(FALSE); } } else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE || mPlaceInfoType == LANDMARK_INFO_TYPE) { mLandmarkInfo->setVisible(visible); if (visible) { mLandmarkInfo->resetLocation(); LLRect rect = getRect(); LLRect new_rect = LLRect(rect.mLeft, rect.mTop, rect.mRight, mTabContainer->getRect().mBottom); mLandmarkInfo->reshape(new_rect.getWidth(), new_rect.getHeight()); mPlaceProfile->setVisible(FALSE); } } } void LLPanelPlaces::changedParcelSelection() { if (!mPlaceProfile) return; LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); mParcel = parcel_mgr->getFloatingParcelSelection(); LLParcel* parcel = mParcel->getParcel(); LLViewerRegion* region = parcel_mgr->getSelectionRegion(); if (!region || !parcel) return; // If agent is inside the selected parcel show agent's region<X, Y, Z>, // otherwise show region<X, Y, Z> of agent's selection point. bool is_current_parcel = is_agent_in_selected_parcel(parcel); if (is_current_parcel) { mPosGlobal = gAgent.getPositionGlobal(); } else { LLVector3d pos_global = gViewerWindow->getLastPick().mPosGlobal; if (!pos_global.isExactlyZero()) { mPosGlobal = pos_global; } } mPlaceProfile->resetLocation(); mPlaceProfile->displaySelectedParcelInfo(parcel, region, mPosGlobal, is_current_parcel); updateVerbs(); } void LLPanelPlaces::changedInventory(U32 mask) { if (!(gInventory.isInventoryUsable() && LLTeleportHistory::getInstance())) return; LLLandmarksPanel* landmarks_panel = new LLLandmarksPanel(); if (landmarks_panel) { landmarks_panel->setPanelPlacesButtons(this); mTabContainer->addTabPanel( LLTabContainer::TabPanelParams(). panel(landmarks_panel). label(getString("landmarks_tab_title")). insert_at(LLTabContainer::END)); } LLTeleportHistoryPanel* teleport_history_panel = new LLTeleportHistoryPanel(); if (teleport_history_panel) { teleport_history_panel->setPanelPlacesButtons(this); mTabContainer->addTabPanel( LLTabContainer::TabPanelParams(). panel(teleport_history_panel). label(getString("teleport_history_tab_title")). insert_at(LLTabContainer::END)); } mTabContainer->selectFirstTab(); mActivePanel = dynamic_cast<LLPanelPlacesTab*>(mTabContainer->getCurrentPanel()); // Filter applied to show all items. if (mActivePanel) mActivePanel->onSearchEdit(mActivePanel->getFilterSubString()); // we don't need to monitor inventory changes anymore, // so remove the observer gInventory.removeObserver(mInventoryObserver); } void LLPanelPlaces::changedGlobalPos(const LLVector3d &global_pos) { mPosGlobal = global_pos; updateVerbs(); } void LLPanelPlaces::updateVerbs() { bool is_place_info_visible; LLPanelPlaceInfo* panel = getCurrentInfoPanel(); if (panel) { is_place_info_visible = panel->getVisible(); } else { is_place_info_visible = false; } bool is_agent_place_info_visible = mPlaceInfoType == AGENT_INFO_TYPE; bool is_create_landmark_visible = mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE; bool have_3d_pos = ! mPosGlobal.isExactlyZero(); mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); mOverflowBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); mEditBtn->setVisible(mPlaceInfoType == LANDMARK_INFO_TYPE && !isLandmarkEditModeOn); mSaveBtn->setVisible(isLandmarkEditModeOn); mCancelBtn->setVisible(isLandmarkEditModeOn); mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn); mShowOnMapBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos); mOverflowBtn->setEnabled(is_place_info_visible && !is_create_landmark_visible); if (is_place_info_visible) { if (is_agent_place_info_visible) { // We don't need to teleport to the current location // so check if the location is not within the current parcel. mTeleportBtn->setEnabled(have_3d_pos && !LLViewerParcelMgr::getInstance()->inAgentParcel(mPosGlobal)); } else if (mPlaceInfoType == LANDMARK_INFO_TYPE || mPlaceInfoType == REMOTE_PLACE_INFO_TYPE) { mTeleportBtn->setEnabled(have_3d_pos); } } else { if (mActivePanel) mActivePanel->updateVerbs(); } } LLPanelPlaceInfo* LLPanelPlaces::getCurrentInfoPanel() { if (mPlaceInfoType == AGENT_INFO_TYPE || mPlaceInfoType == REMOTE_PLACE_INFO_TYPE || mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) { return mPlaceProfile; } else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE || mPlaceInfoType == LANDMARK_INFO_TYPE) { return mLandmarkInfo; } return NULL; } static bool is_agent_in_selected_parcel(LLParcel* parcel) { LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); LLViewerRegion* region = parcel_mgr->getSelectionRegion(); if (!region || !parcel) return false; return region == gAgent.getRegion() && parcel->getLocalID() == parcel_mgr->getAgentParcel()->getLocalID(); } static void onSLURLBuilt(std::string& slurl) { LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(slurl)); LLSD args; args["SLURL"] = slurl; LLNotificationsUtil::add("CopySLURL", args); }