1359 lines
43 KiB
C++
1359 lines
43 KiB
C++
/**
|
|
* @file llpanelplaces.cpp
|
|
* @brief Side Bar "Places" panel
|
|
*
|
|
* $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 "llpanelplaces.h"
|
|
|
|
#include "llassettype.h"
|
|
#include "lltimer.h"
|
|
|
|
#include "llinventory.h"
|
|
#include "lllandmark.h"
|
|
#include "llparcel.h"
|
|
|
|
#include "llcombobox.h"
|
|
#include "llfiltereditor.h"
|
|
#include "llfirstuse.h"
|
|
#include "llfloaterreg.h"
|
|
#include "llfloatersidepanelcontainer.h"
|
|
#include "llmenubutton.h"
|
|
#include "llnotificationsutil.h"
|
|
#include "lltabcontainer.h"
|
|
#include "lltexteditor.h"
|
|
#include "lltrans.h"
|
|
#include "lluictrlfactory.h"
|
|
|
|
#include "llwindow.h"
|
|
|
|
#include "llagent.h"
|
|
#include "llagentpicksinfo.h"
|
|
#include "llavatarpropertiesprocessor.h"
|
|
#include "llcommandhandler.h"
|
|
#include "lldndbutton.h"
|
|
#include "llfloaterworldmap.h"
|
|
#include "llinventorybridge.h"
|
|
#include "llinventoryobserver.h"
|
|
#include "llinventorymodel.h"
|
|
#include "lllandmarkactions.h"
|
|
#include "lllandmarklist.h"
|
|
#include "lllayoutstack.h"
|
|
#include "llpanellandmarkinfo.h"
|
|
#include "llpanellandmarks.h"
|
|
#include "llpanelplaceprofile.h"
|
|
#include "llpanelteleporthistory.h"
|
|
#include "llremoteparcelrequest.h"
|
|
#include "llteleporthistorystorage.h"
|
|
#include "lltoggleablemenu.h"
|
|
#include "llviewerinventory.h"
|
|
#include "llviewermenu.h"
|
|
#include "llviewermessage.h"
|
|
#include "llviewerparcelmgr.h"
|
|
#include "llviewerregion.h"
|
|
#include "llviewerwindow.h"
|
|
|
|
// Constants
|
|
static const F32 PLACE_INFO_UPDATE_INTERVAL = 3.0;
|
|
static const std::string AGENT_INFO_TYPE = "agent";
|
|
static const std::string CREATE_LANDMARK_INFO_TYPE = "create_landmark";
|
|
static const std::string CREATE_PICK_TYPE = "create_pick";
|
|
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";
|
|
static const std::string LANDMARK_TAB_INFO_TYPE = "open_landmark_tab";
|
|
|
|
// Support for secondlife:///app/parcel/{UUID}/about SLapps
|
|
class LLParcelHandler : public LLCommandHandler
|
|
{
|
|
public:
|
|
// requires trusted browser to trigger
|
|
LLParcelHandler() : LLCommandHandler("parcel", UNTRUSTED_THROTTLE) { }
|
|
bool handle(const LLSD& params,
|
|
const LLSD& query_map,
|
|
const std::string& grid,
|
|
LLMediaCtrl* web)
|
|
{
|
|
if (params.size() < 2)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnablePlaceProfile"))
|
|
{
|
|
LLNotificationsUtil::add("NoPlaceInfo", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
|
|
return true;
|
|
}
|
|
|
|
LLUUID parcel_id;
|
|
if (!parcel_id.set(params[0], false))
|
|
{
|
|
return false;
|
|
}
|
|
if (params[1].asString() == "about")
|
|
{
|
|
if (parcel_id.notNull())
|
|
{
|
|
LLSD key;
|
|
key["type"] = "remote_place";
|
|
key["id"] = parcel_id;
|
|
LLFloaterSidePanelContainer::showPanel("places", key);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
LLParcelHandler gParcelHandler;
|
|
|
|
// 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 LLInventoryAddedObserver
|
|
{
|
|
public:
|
|
LLPlacesInventoryObserver(LLPanelPlaces* places_panel) :
|
|
mPlaces(places_panel)
|
|
{}
|
|
|
|
/*virtual*/ void changed(U32 mask)
|
|
{
|
|
LLInventoryAddedObserver::changed(mask);
|
|
|
|
if (mPlaces && !mPlaces->tabsCreated())
|
|
{
|
|
mPlaces->createTabs();
|
|
}
|
|
}
|
|
|
|
protected:
|
|
/*virtual*/ void done()
|
|
{
|
|
mPlaces->showAddedLandmarkInfo(gInventory.getAddedIDs());
|
|
}
|
|
|
|
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(S32 status, const std::string& reason)
|
|
{
|
|
LL_ERRS() << "Can't complete remote parcel request. Http Status: "
|
|
<< status << ". Reason : " << reason << LL_ENDL;
|
|
}
|
|
|
|
private:
|
|
std::set<LLUUID> mParcelIDs;
|
|
LLPanelPlaces* mPlaces;
|
|
};
|
|
|
|
|
|
static LLPanelInjector<LLPanelPlaces> t_places("panel_places");
|
|
|
|
LLPanelPlaces::LLPanelPlaces()
|
|
: LLPanel(),
|
|
mActivePanel(NULL),
|
|
mFilterEditor(NULL),
|
|
mPlaceProfile(NULL),
|
|
mLandmarkInfo(NULL),
|
|
mItem(NULL),
|
|
mPlaceMenu(NULL),
|
|
mLandmarkMenu(NULL),
|
|
mPosGlobal(),
|
|
isLandmarkEditModeOn(false),
|
|
mTabsCreated(false)
|
|
{
|
|
mParcelObserver = new LLPlacesParcelObserver(this);
|
|
mInventoryObserver = new LLPlacesInventoryObserver(this);
|
|
mRemoteParcelObserver = new LLPlacesRemoteParcelInfoObserver(this);
|
|
|
|
gInventory.addObserver(mInventoryObserver);
|
|
|
|
mAgentParcelChangedConnection = gAgent.addParcelChangedCallback(
|
|
boost::bind(&LLPanelPlaces::updateVerbs, this));
|
|
|
|
//buildFromFile( "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;
|
|
|
|
if (mAgentParcelChangedConnection.connected())
|
|
{
|
|
mAgentParcelChangedConnection.disconnect();
|
|
}
|
|
}
|
|
|
|
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));
|
|
|
|
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<LLMenuButton>("overflow_btn");
|
|
mOverflowBtn->setMouseDownCallback(boost::bind(&LLPanelPlaces::onOverflowButtonClicked, this));
|
|
|
|
mGearMenuButton = getChild<LLMenuButton>("options_gear_btn");
|
|
mGearMenuButton->setMouseDownCallback(boost::bind(&LLPanelPlaces::onGearMenuClick, this));
|
|
|
|
mSortingMenuButton = getChild<LLMenuButton>("sorting_menu_btn");
|
|
mSortingMenuButton->setMouseDownCallback(boost::bind(&LLPanelPlaces::onSortingMenuClick, this));
|
|
|
|
mAddMenuButton = getChild<LLMenuButton>("add_menu_btn");
|
|
mAddMenuButton->setMouseDownCallback(boost::bind(&LLPanelPlaces::onAddMenuClick, this));
|
|
|
|
mRemoveSelectedBtn = getChild<LLButton>("trash_btn");
|
|
mRemoveSelectedBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onRemoveButtonClicked, this));
|
|
|
|
LLDragAndDropButton* trash_btn = (LLDragAndDropButton*)mRemoveSelectedBtn;
|
|
trash_btn->setDragAndDropHandler(boost::bind(&LLPanelPlaces::handleDragAndDropToTrash, this
|
|
, _4 // bool drop
|
|
, _5 // EDragAndDropType cargo_type
|
|
, _6 // void* cargo_data
|
|
, _7 // EAcceptance* accept
|
|
));
|
|
|
|
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)
|
|
{
|
|
mPlaceMenu->setAlwaysShowMenu(true);
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS() << "Error loading Place menu" << LL_ENDL;
|
|
}
|
|
|
|
mLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
|
|
if (!mLandmarkMenu)
|
|
{
|
|
LL_WARNS() << "Error loading Landmark menu" << LL_ENDL;
|
|
}
|
|
|
|
mTabContainer = getChild<LLTabContainer>("Places Tabs");
|
|
if (mTabContainer)
|
|
{
|
|
mTabContainer->setCommitCallback(boost::bind(&LLPanelPlaces::onTabSelected, this));
|
|
}
|
|
|
|
mButtonsContainer = getChild<LLPanel>("button_layout_panel");
|
|
mButtonsContainer->setVisible(false);
|
|
mFilterContainer = getChild<LLLayoutStack>("top_menu_panel");
|
|
|
|
mFilterEditor = getChild<LLFilterEditor>("Filter");
|
|
if (mFilterEditor)
|
|
{
|
|
//when list item is being clicked the filter editor looses focus
|
|
//committing on focus lost leads to detaching list items
|
|
//BUT a detached list item cannot be made selected and must not be clicked onto
|
|
mFilterEditor->setCommitOnFocusLost(false);
|
|
|
|
mFilterEditor->setCommitCallback(boost::bind(&LLPanelPlaces::onFilterEdit, this, _2, false));
|
|
}
|
|
|
|
mPlaceProfile = findChild<LLPanelPlaceProfile>("panel_place_profile");
|
|
mLandmarkInfo = findChild<LLPanelLandmarkInfo>("panel_landmark_info");
|
|
if (!mPlaceProfile || !mLandmarkInfo)
|
|
return false;
|
|
|
|
mPlaceProfileBackBtn = mPlaceProfile->getChild<LLButton>("back_btn");
|
|
mPlaceProfileBackBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this));
|
|
|
|
mLandmarkInfo->getChild<LLButton>("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));
|
|
|
|
LLButton* edit_btn = mLandmarkInfo->getChild<LLButton>("edit_btn");
|
|
edit_btn->setCommitCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this));
|
|
|
|
createTabs();
|
|
updateVerbs();
|
|
|
|
return true;
|
|
}
|
|
|
|
void LLPanelPlaces::onOpen(const LLSD& key)
|
|
{
|
|
if (!mPlaceProfile || !mLandmarkInfo)
|
|
return;
|
|
|
|
if (key.size() != 0)
|
|
{
|
|
isLandmarkEditModeOn = false;
|
|
std::string key_type = key["type"].asString();
|
|
if (key_type == LANDMARK_TAB_INFO_TYPE)
|
|
{
|
|
// Small hack: We need to toggle twice. The first toggle moves from the Landmark
|
|
// or Teleport History info panel to the Landmark or Teleport History list panel.
|
|
// For this first toggle, the mPlaceInfoType should be the one previously used so
|
|
// that the state can be corretly set.
|
|
// The second toggle forces the list to be set to Landmark.
|
|
// This avoids extracting and duplicating all the state logic from togglePlaceInfoPanel()
|
|
// here or some specific private method
|
|
togglePlaceInfoPanel(false);
|
|
mPlaceInfoType = key_type;
|
|
togglePlaceInfoPanel(false);
|
|
// Update the active tab
|
|
onTabSelected();
|
|
// Update the buttons at the bottom of the panel
|
|
updateVerbs();
|
|
}
|
|
else if (key_type == CREATE_PICK_TYPE)
|
|
{
|
|
LLUUID item_id = key["item_id"];
|
|
|
|
LLLandmarksPanel* landmarks_panel =
|
|
dynamic_cast<LLLandmarksPanel*>(mTabContainer->getPanelByName("Landmarks"));
|
|
if (landmarks_panel && item_id.notNull())
|
|
{
|
|
LLLandmark* landmark = LLLandmarkActions::getLandmark(item_id, boost::bind(&LLLandmarksPanel::doCreatePick, landmarks_panel, _1, item_id));
|
|
if (landmark)
|
|
{
|
|
landmarks_panel->doCreatePick(landmark, item_id);
|
|
}
|
|
}
|
|
}
|
|
else // "create_landmark"
|
|
{
|
|
mFilterEditor->clear();
|
|
onFilterEdit("", false);
|
|
|
|
mPlaceInfoType = key_type;
|
|
mPosGlobal.setZero();
|
|
mItem = NULL;
|
|
mRegionId.setNull();
|
|
togglePlaceInfoPanel(true);
|
|
|
|
if (mPlaceInfoType == AGENT_INFO_TYPE)
|
|
{
|
|
mPlaceProfile->setInfoType(LLPanelPlaceInfo::AGENT);
|
|
if (gAgent.getRegion())
|
|
{
|
|
mRegionId = gAgent.getRegion()->getRegionID();
|
|
}
|
|
}
|
|
else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE)
|
|
{
|
|
LLUUID dest_folder = key["dest_folder"];
|
|
mLandmarkInfo->setInfoAndCreateLandmark(dest_folder);
|
|
|
|
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);
|
|
|
|
mSaveBtn->setEnabled(false);
|
|
}
|
|
else if (mPlaceInfoType == LANDMARK_INFO_TYPE)
|
|
{
|
|
mLandmarkInfo->setInfoType(LLPanelPlaceInfo::LANDMARK);
|
|
|
|
LLUUID id = key["id"].asUUID();
|
|
LLInventoryItem* item = gInventory.getItem(id);
|
|
if (!item)
|
|
return;
|
|
|
|
bool is_editable = gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID())
|
|
&& item->getPermissions().allowModifyBy(gAgent.getID());
|
|
mLandmarkInfo->setCanEdit(is_editable);
|
|
|
|
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;
|
|
|
|
mParcelLocalId = parcel_mgr->getAgentParcel()->getLocalID();
|
|
|
|
// 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)
|
|
{
|
|
// We don't know if we are already added to LLViewerParcelMgr observers list
|
|
// so try to remove observer not to add an extra one.
|
|
parcel_mgr->removeObserver(mParcelObserver);
|
|
|
|
parcel_mgr->addObserver(mParcelObserver);
|
|
parcel_mgr->selectParcelAt(gAgent.getPositionGlobal());
|
|
}
|
|
else
|
|
{
|
|
parcel_mgr->removeObserver(mParcelObserver);
|
|
|
|
// Clear the reference to selection to allow its removal in deselectUnused().
|
|
mParcel.clear();
|
|
|
|
if (!parcel_mgr->selectionEmpty())
|
|
{
|
|
parcel_mgr->deselectUnused();
|
|
}
|
|
}
|
|
}
|
|
|
|
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());
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
S32 LLPanelPlaces::notifyParent(const LLSD& info)
|
|
{
|
|
if(info.has("update_verbs"))
|
|
{
|
|
if(mPosGlobal.isExactlyZero())
|
|
{
|
|
mPosGlobal.setVec(info["global_x"], info["global_y"], info["global_z"]);
|
|
}
|
|
|
|
updateVerbs();
|
|
|
|
return 1;
|
|
}
|
|
return LLPanel::notifyParent(info);
|
|
}
|
|
|
|
void LLPanelPlaces::onLandmarkLoaded(LLLandmark* landmark)
|
|
{
|
|
if (!mLandmarkInfo)
|
|
return;
|
|
|
|
LLUUID region_id;
|
|
landmark->getRegionID(region_id);
|
|
landmark->getGlobalPos(mPosGlobal);
|
|
mLandmarkInfo->displayParcelInfo(region_id, mPosGlobal);
|
|
|
|
updateVerbs();
|
|
}
|
|
|
|
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
|
|
// but we don't convert the typed string to upper-case so that it can be fed to the web search as-is.
|
|
|
|
mActivePanel->onSearchEdit(string);
|
|
}
|
|
}
|
|
|
|
void LLPanelPlaces::onTabSelected()
|
|
{
|
|
mActivePanel = dynamic_cast<LLPanelPlacesTab*>(mTabContainer->getCurrentPanel());
|
|
if (!mActivePanel)
|
|
return;
|
|
|
|
onFilterEdit(mActivePanel->getFilterSubString(), true);
|
|
mActivePanel->updateVerbs();
|
|
|
|
// History panel does not support deletion nor creation
|
|
// Hide menus
|
|
bool supports_create = mActivePanel->getCreateMenu() != NULL;
|
|
childSetVisible("add_btn_panel", supports_create);
|
|
|
|
// favorites and inventory can remove items, history can clear history
|
|
childSetVisible("trash_btn_panel", true);
|
|
|
|
if (supports_create)
|
|
{
|
|
mRemoveSelectedBtn->setToolTip(getString("tooltip_trash_items"));
|
|
}
|
|
else
|
|
{
|
|
mRemoveSelectedBtn->setToolTip(getString("tooltip_trash_history"));
|
|
}
|
|
}
|
|
|
|
void LLPanelPlaces::onTeleportButtonClicked()
|
|
{
|
|
LLPanelPlaceInfo* panel = getCurrentInfoPanel();
|
|
if (panel && panel->getVisible())
|
|
{
|
|
if (mPlaceInfoType == LANDMARK_INFO_TYPE)
|
|
{
|
|
if (mItem.isNull())
|
|
{
|
|
LL_WARNS() << "NULL landmark item" << LL_ENDL;
|
|
llassert(mItem.notNull());
|
|
return;
|
|
}
|
|
|
|
LLSD payload;
|
|
payload["asset_id"] = mItem->getAssetUUID();
|
|
LLSD args;
|
|
args["LOCATION"] = mItem->getName();
|
|
LLNotificationsUtil::add("TeleportFromLandmark", args, 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)
|
|
{
|
|
if (mItem.isNull())
|
|
{
|
|
LL_WARNS() << "NULL landmark item" << LL_ENDL;
|
|
llassert(mItem.notNull());
|
|
return;
|
|
}
|
|
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->isSingleItemSelected())
|
|
{
|
|
mActivePanel->onShowOnMap();
|
|
}
|
|
else
|
|
{
|
|
LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance();
|
|
LLVector3d global_pos = gAgent.getPositionGlobal();
|
|
|
|
if (!global_pos.isExactlyZero() && worldmap_instance)
|
|
{
|
|
worldmap_instance->trackLocation(global_pos);
|
|
LLFloaterReg::showInstance("world_map", "center");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 folder_id = mLandmarkInfo->getLandmarkFolder();
|
|
bool change_parent = folder_id != mItem->getParentUUID();
|
|
|
|
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);
|
|
LLPointer<LLInventoryCallback> cb;
|
|
if (change_parent)
|
|
{
|
|
cb = new LLUpdateLandmarkParent(new_item, folder_id);
|
|
}
|
|
LLInventoryModel::LLCategoryUpdate up(mItem->getParentUUID(), 0);
|
|
gInventory.accountForUpdate(up);
|
|
update_inventory_item(new_item, cb);
|
|
}
|
|
else if (change_parent)
|
|
{
|
|
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_INFO_TYPE ||
|
|
mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) && mPlaceMenu != NULL)
|
|
{
|
|
menu = mPlaceMenu;
|
|
|
|
bool landmark_item_enabled = false;
|
|
LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance();
|
|
if (is_agent_place_info_visible
|
|
&& gAgent.getRegion()
|
|
&& mRegionId == gAgent.getRegion()->getRegionID()
|
|
&& parcel_mgr
|
|
&& parcel_mgr->getAgentParcel()->getLocalID() == mParcelLocalId)
|
|
{
|
|
// Floater still shows location identical to agent's position
|
|
landmark_item_enabled = !LLLandmarkActions::landmarkAlreadyExists();
|
|
}
|
|
|
|
// 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(landmark_item_enabled);
|
|
// STORM-411
|
|
// Creating landmarks for remote locations is impossible.
|
|
// So hide menu item "Make a Landmark" in "Teleport History Profile" panel.
|
|
menu->setItemVisible("landmark", mPlaceInfoType != TELEPORT_HISTORY_INFO_TYPE);
|
|
menu->arrangeAndClear();
|
|
}
|
|
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;
|
|
}
|
|
|
|
mOverflowBtn->setMenu(menu, LLMenuButton::MP_TOP_RIGHT);
|
|
}
|
|
|
|
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")
|
|
{
|
|
LLPanelPlaceInfo* panel = getCurrentInfoPanel();
|
|
if (panel)
|
|
{
|
|
panel->createPick(mPosGlobal);
|
|
}
|
|
}
|
|
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));
|
|
LL_INFOS() << "Copied inventory item #" << mItem->getUUID() << " to favorites." << LL_ENDL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void LLPanelPlaces::onBackButtonClicked()
|
|
{
|
|
togglePlaceInfoPanel(false);
|
|
|
|
// Resetting mPlaceInfoType when Place Info panel is closed.
|
|
mPlaceInfoType = LLStringUtil::null;
|
|
|
|
isLandmarkEditModeOn = false;
|
|
|
|
updateVerbs();
|
|
}
|
|
|
|
void LLPanelPlaces::onGearMenuClick()
|
|
{
|
|
if (mActivePanel)
|
|
{
|
|
LLToggleableMenu* menu = mActivePanel->getSelectionMenu();
|
|
mGearMenuButton->setMenu(menu, LLMenuButton::MP_BOTTOM_LEFT);
|
|
}
|
|
}
|
|
|
|
void LLPanelPlaces::onSortingMenuClick()
|
|
{
|
|
if (mActivePanel)
|
|
{
|
|
LLToggleableMenu* menu = mActivePanel->getSortingMenu();
|
|
mSortingMenuButton->setMenu(menu, LLMenuButton::MP_BOTTOM_LEFT);
|
|
}
|
|
}
|
|
|
|
void LLPanelPlaces::onAddMenuClick()
|
|
{
|
|
if (mActivePanel)
|
|
{
|
|
LLToggleableMenu* menu = mActivePanel->getCreateMenu();
|
|
mAddMenuButton->setMenu(menu, LLMenuButton::MP_BOTTOM_LEFT);
|
|
}
|
|
}
|
|
|
|
void LLPanelPlaces::onRemoveButtonClicked()
|
|
{
|
|
if (mActivePanel)
|
|
{
|
|
mActivePanel->onRemoveSelected();
|
|
}
|
|
}
|
|
|
|
bool LLPanelPlaces::handleDragAndDropToTrash(bool drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept)
|
|
{
|
|
if (mActivePanel)
|
|
{
|
|
return mActivePanel->handleDragAndDropToTrash(drop, cargo_type, cargo_data, accept);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void LLPanelPlaces::togglePlaceInfoPanel(bool visible)
|
|
{
|
|
if (!mPlaceProfile || !mLandmarkInfo)
|
|
return;
|
|
|
|
mTabContainer->setVisible(!visible);
|
|
mButtonsContainer->setVisible(visible);
|
|
mFilterContainer->setVisible(!visible);
|
|
|
|
if (mPlaceInfoType == AGENT_INFO_TYPE ||
|
|
mPlaceInfoType == REMOTE_PLACE_INFO_TYPE ||
|
|
mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE)
|
|
{
|
|
mPlaceProfile->setVisible(visible);
|
|
|
|
if (visible)
|
|
{
|
|
mPlaceProfile->resetLocation();
|
|
|
|
// Do not reset location info until mResetInfoTimer has expired
|
|
// to avoid text blinking.
|
|
mResetInfoTimer.setTimerExpirySec(PLACE_INFO_UPDATE_INTERVAL);
|
|
|
|
mLandmarkInfo->setVisible(false);
|
|
}
|
|
else if (mPlaceInfoType == AGENT_INFO_TYPE)
|
|
{
|
|
LLViewerParcelMgr::getInstance()->removeObserver(mParcelObserver);
|
|
|
|
// Clear reference to parcel selection when closing place profile panel.
|
|
// LLViewerParcelMgr removes the selection if it has 1 reference to it.
|
|
mParcel.clear();
|
|
}
|
|
}
|
|
else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE ||
|
|
mPlaceInfoType == LANDMARK_INFO_TYPE ||
|
|
mPlaceInfoType == LANDMARK_TAB_INFO_TYPE)
|
|
{
|
|
mLandmarkInfo->setVisible(visible);
|
|
mPlaceProfile->setVisible(false);
|
|
if (visible)
|
|
{
|
|
mLandmarkInfo->resetLocation();
|
|
}
|
|
else
|
|
{
|
|
std::string tab_panel_name("Landmarks");
|
|
if (mItem.notNull())
|
|
{
|
|
if (gInventory.isObjectDescendentOf(mItem->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE)))
|
|
{
|
|
tab_panel_name = "Favorites";
|
|
}
|
|
}
|
|
|
|
LLLandmarksPanel* landmarks_panel = dynamic_cast<LLLandmarksPanel*>(mTabContainer->getPanelByName(tab_panel_name));
|
|
if (landmarks_panel)
|
|
{
|
|
// If a landmark info is being closed we open the landmarks tab
|
|
// and set this landmark selected.
|
|
mTabContainer->selectTabPanel(landmarks_panel);
|
|
if (mItem.notNull())
|
|
{
|
|
landmarks_panel->setItemSelected(mItem->getUUID(), true);
|
|
}
|
|
else
|
|
{
|
|
landmarks_panel->resetSelection();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// virtual
|
|
void LLPanelPlaces::onVisibilityChange(bool new_visibility)
|
|
{
|
|
LLPanel::onVisibilityChange(new_visibility);
|
|
|
|
if (!new_visibility && mPlaceInfoType == AGENT_INFO_TYPE)
|
|
{
|
|
LLViewerParcelMgr::getInstance()->removeObserver(mParcelObserver);
|
|
|
|
// Clear reference to parcel selection when closing places panel.
|
|
mParcel.clear();
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
LLVector3d prev_pos_global = mPosGlobal;
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
// Reset location info only if global position has changed
|
|
// and update timer has expired to reduce unnecessary text and icons updates.
|
|
if (prev_pos_global != mPosGlobal && mResetInfoTimer.hasExpired())
|
|
{
|
|
mPlaceProfile->resetLocation();
|
|
mResetInfoTimer.setTimerExpirySec(PLACE_INFO_UPDATE_INTERVAL);
|
|
}
|
|
|
|
mPlaceProfile->displaySelectedParcelInfo(parcel, region, mPosGlobal, is_current_parcel);
|
|
|
|
updateVerbs();
|
|
}
|
|
|
|
void LLPanelPlaces::createTabs()
|
|
{
|
|
if (!(gInventory.isInventoryUsable() && LLTeleportHistory::getInstance() && !mTabsCreated))
|
|
return;
|
|
|
|
LLFavoritesPanel* favorites_panel = new LLFavoritesPanel();
|
|
if (favorites_panel)
|
|
{
|
|
mTabContainer->addTabPanel(
|
|
LLTabContainer::TabPanelParams().
|
|
panel(favorites_panel).
|
|
label(getString("favorites_tab_title")).
|
|
insert_at(LLTabContainer::END));
|
|
}
|
|
|
|
LLLandmarksPanel* landmarks_panel = new LLLandmarksPanel();
|
|
if (landmarks_panel)
|
|
{
|
|
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)
|
|
{
|
|
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());
|
|
|
|
if (mActivePanel)
|
|
{
|
|
// Filter applied to show all items.
|
|
mActivePanel->onSearchEdit(mActivePanel->getFilterSubString());
|
|
|
|
// History panel does not support deletion nor creation
|
|
// Hide menus
|
|
bool supports_create = mActivePanel->getCreateMenu() != NULL;
|
|
childSetVisible("add_btn_panel", supports_create);
|
|
|
|
// favorites and inventory can remove items, history can clear history
|
|
childSetVisible("trash_btn_panel", true);
|
|
|
|
if (supports_create)
|
|
{
|
|
mRemoveSelectedBtn->setToolTip(getString("tooltip_trash_items"));
|
|
}
|
|
else
|
|
{
|
|
mRemoveSelectedBtn->setToolTip(getString("tooltip_trash_history"));
|
|
}
|
|
|
|
mActivePanel->setRemoveBtn(mRemoveSelectedBtn);
|
|
mActivePanel->updateVerbs();
|
|
}
|
|
|
|
mTabsCreated = true;
|
|
}
|
|
|
|
void LLPanelPlaces::changedGlobalPos(const LLVector3d &global_pos)
|
|
{
|
|
mPosGlobal = global_pos;
|
|
updateVerbs();
|
|
}
|
|
|
|
void LLPanelPlaces::showAddedLandmarkInfo(const uuid_set_t& items)
|
|
{
|
|
for (uuid_set_t::const_iterator item_iter = items.begin();
|
|
item_iter != items.end();
|
|
++item_iter)
|
|
{
|
|
const LLUUID& item_id = (*item_iter);
|
|
if(!highlight_offered_object(item_id))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
LLInventoryItem* item = gInventory.getItem(item_id);
|
|
|
|
llassert(item);
|
|
if (item && (LLAssetType::AT_LANDMARK == item->getType()) )
|
|
{
|
|
// Created landmark is passed to Places panel to allow its editing.
|
|
// If the panel is closed we don't reopen it until created landmark is loaded.
|
|
if("create_landmark" == getPlaceInfoType() && !getItem())
|
|
{
|
|
setItem(item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
mSaveBtn->setVisible(isLandmarkEditModeOn);
|
|
mCancelBtn->setVisible(isLandmarkEditModeOn);
|
|
mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn);
|
|
|
|
bool show_options_btn = is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn;
|
|
mOverflowBtn->setVisible(show_options_btn);
|
|
getChild<LLLayoutPanel>("lp_options")->setVisible(show_options_btn);
|
|
getChild<LLLayoutPanel>("lp2")->setVisible(!show_options_btn);
|
|
|
|
if (is_place_info_visible)
|
|
{
|
|
mShowOnMapBtn->setEnabled(have_3d_pos);
|
|
|
|
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 ||
|
|
mPlaceInfoType == LANDMARK_TAB_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);
|
|
}
|