PageRenderTime 203ms CodeModel.GetById 24ms app.highlight 161ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/llfloaterworldmap.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1633 lines | 1198 code | 256 blank | 179 comment | 178 complexity | e8e1b56ac84f22ef749ebb130834c462 MD5 | raw file
   1/** 
   2 * @file llfloaterworldmap.cpp
   3 * @author James Cook, Tom Yedwab
   4 * @brief LLFloaterWorldMap class implementation
   5 *
   6 * $LicenseInfo:firstyear=2003&license=viewerlgpl$
   7 * Second Life Viewer Source Code
   8 * Copyright (C) 2010, Linden Research, Inc.
   9 * 
  10 * This library is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU Lesser General Public
  12 * License as published by the Free Software Foundation;
  13 * version 2.1 of the License only.
  14 * 
  15 * This library is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 * Lesser General Public License for more details.
  19 * 
  20 * You should have received a copy of the GNU Lesser General Public
  21 * License along with this library; if not, write to the Free Software
  22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  23 * 
  24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  25 * $/LicenseInfo$
  26 */
  27
  28/*
  29 * Map of the entire world, with multiple background images,
  30 * avatar tracking, teleportation by double-click, etc.
  31 */
  32
  33#include "llviewerprecompiledheaders.h"
  34
  35#include "llfloaterworldmap.h"
  36
  37#include "llagent.h"
  38#include "llagentcamera.h"
  39#include "llbutton.h"
  40#include "llcallingcard.h"
  41#include "llcombobox.h"
  42#include "llviewercontrol.h"
  43#include "llcommandhandler.h"
  44#include "lldraghandle.h"
  45//#include "llfirstuse.h"
  46#include "llfloaterreg.h"		// getTypedInstance()
  47#include "llfocusmgr.h"
  48#include "llinventoryfunctions.h"
  49#include "llinventorymodel.h"
  50#include "llinventorymodelbackgroundfetch.h"
  51#include "llinventoryobserver.h"
  52#include "lllandmarklist.h"
  53#include "llsearcheditor.h"
  54#include "llnotificationsutil.h"
  55#include "llregionhandle.h"
  56#include "llscrolllistctrl.h"
  57#include "llslurl.h"
  58#include "lltextbox.h"
  59#include "lltracker.h"
  60#include "lltrans.h"
  61#include "llviewerinventory.h"	// LLViewerInventoryItem
  62#include "llviewermenu.h"
  63#include "llviewerregion.h"
  64#include "llviewerstats.h"
  65#include "llviewertexture.h"
  66#include "llworldmap.h"
  67#include "llworldmapmessage.h"
  68#include "llworldmapview.h"
  69#include "lluictrlfactory.h"
  70#include "llappviewer.h"
  71#include "llmapimagetype.h"
  72#include "llweb.h"
  73#include "llsliderctrl.h"
  74#include "message.h"
  75#include "llwindow.h"			// copyTextToClipboard()
  76#include <algorithm>
  77
  78//---------------------------------------------------------------------------
  79// Constants
  80//---------------------------------------------------------------------------
  81static const F32 MAP_ZOOM_TIME = 0.2f;
  82
  83// Merov: we switched from using the "world size" (which varies depending where the user went) to a fixed
  84// width of 512 regions max visible at a time. This makes the zoom slider works in a consistent way across
  85// sessions and doesn't prevent the user to pan the world if it was to grow a lot beyond that limit.
  86// Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window.
  87static const S32 MAX_VISIBLE_REGIONS = 512;
  88
  89// It would be more logical to have this inside the method where it is used but to compile under gcc this
  90// struct has to be here.
  91struct SortRegionNames
  92{
  93	inline bool operator ()(std::pair <U64, LLSimInfo*> const& _left, std::pair <U64, LLSimInfo*> const& _right)
  94	{
  95		return(LLStringUtil::compareInsensitive(_left.second->getName(), _right.second->getName()) < 0);
  96	}
  97};
  98
  99enum EPanDirection
 100{
 101	PAN_UP,
 102	PAN_DOWN,
 103	PAN_LEFT,
 104	PAN_RIGHT
 105};
 106
 107// Values in pixels per region
 108static const F32 ZOOM_MAX = 128.f;
 109
 110//---------------------------------------------------------------------------
 111// Globals
 112//---------------------------------------------------------------------------
 113
 114// handle secondlife:///app/worldmap/{NAME}/{COORDS} URLs
 115class LLWorldMapHandler : public LLCommandHandler
 116{
 117public:
 118	// requires trusted browser to trigger
 119	LLWorldMapHandler() : LLCommandHandler("worldmap", UNTRUSTED_THROTTLE ) { }
 120	
 121	bool handle(const LLSD& params, const LLSD& query_map,
 122				LLMediaCtrl* web)
 123	{
 124		if (!LLUI::sSettingGroups["config"]->getBOOL("EnableWorldMap"))
 125		{
 126			LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
 127			return true;
 128		}
 129
 130		if (params.size() == 0)
 131		{
 132			// support the secondlife:///app/worldmap SLapp
 133			LLFloaterReg::showInstance("world_map", "center");
 134			return true;
 135		}
 136		
 137		// support the secondlife:///app/worldmap/{LOCATION}/{COORDS} SLapp
 138		const std::string region_name = LLURI::unescape(params[0].asString());
 139		S32 x = (params.size() > 1) ? params[1].asInteger() : 128;
 140		S32 y = (params.size() > 2) ? params[2].asInteger() : 128;
 141		S32 z = (params.size() > 3) ? params[3].asInteger() : 0;
 142		
 143		LLFloaterWorldMap::getInstance()->trackURL(region_name, x, y, z);
 144		LLFloaterReg::showInstance("world_map", "center");
 145		
 146		return true;
 147	}
 148};
 149LLWorldMapHandler gWorldMapHandler;
 150
 151// SocialMap handler secondlife:///app/maptrackavatar/id
 152class LLMapTrackAvatarHandler : public LLCommandHandler
 153{
 154public:
 155	// requires trusted browser to trigger
 156	LLMapTrackAvatarHandler() : LLCommandHandler("maptrackavatar", UNTRUSTED_THROTTLE) 
 157	{ 
 158	}
 159	
 160	bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
 161	{
 162		if (!LLUI::sSettingGroups["config"]->getBOOL("EnableWorldMap"))
 163		{
 164			LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
 165			return true;
 166		}
 167		
 168		//Make sure we have some parameters
 169		if (params.size() == 0)
 170		{
 171			return false;
 172		}
 173		
 174		//Get the ID
 175		LLUUID id;
 176		if (!id.set( params[0], FALSE ))
 177		{
 178			return false;
 179		}
 180		
 181		LLFloaterWorldMap::getInstance()->avatarTrackFromSlapp( id  ); 
 182		LLFloaterReg::showInstance( "world_map", "center" );
 183		
 184		return true;
 185	}
 186};	
 187LLMapTrackAvatarHandler gMapTrackAvatar;
 188
 189LLFloaterWorldMap* gFloaterWorldMap = NULL;
 190
 191class LLMapInventoryObserver : public LLInventoryObserver
 192{
 193public:
 194	LLMapInventoryObserver() {}
 195	virtual ~LLMapInventoryObserver() {}
 196	virtual void changed(U32 mask);
 197};
 198
 199void LLMapInventoryObserver::changed(U32 mask)
 200{
 201	// if there's a change we're interested in.
 202	if((mask & (LLInventoryObserver::CALLING_CARD | LLInventoryObserver::ADD |
 203				LLInventoryObserver::REMOVE)) != 0)
 204	{
 205		gFloaterWorldMap->inventoryChanged();
 206	}
 207}
 208
 209class LLMapFriendObserver : public LLFriendObserver
 210{
 211public:
 212	LLMapFriendObserver() {}
 213	virtual ~LLMapFriendObserver() {}
 214	virtual void changed(U32 mask);
 215};
 216
 217void LLMapFriendObserver::changed(U32 mask)
 218{
 219	// if there's a change we're interested in.
 220	if((mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE | LLFriendObserver::POWERS)) != 0)
 221	{
 222		gFloaterWorldMap->friendsChanged();
 223	}
 224}
 225
 226//---------------------------------------------------------------------------
 227// Statics
 228//---------------------------------------------------------------------------
 229
 230// Used as a pretend asset and inventory id to mean "landmark at my home location."
 231const LLUUID LLFloaterWorldMap::sHomeID( "10000000-0000-0000-0000-000000000001" );
 232
 233//---------------------------------------------------------------------------
 234// Construction and destruction
 235//---------------------------------------------------------------------------
 236
 237
 238LLFloaterWorldMap::LLFloaterWorldMap(const LLSD& key)
 239:	LLFloater(key),
 240	mInventory(NULL),
 241	mInventoryObserver(NULL),
 242	mFriendObserver(NULL),
 243	mCompletingRegionName(),
 244	mCompletingRegionPos(),
 245	mWaitingForTracker(FALSE),
 246	mIsClosing(FALSE),
 247	mSetToUserPosition(TRUE),
 248	mTrackedLocation(0,0,0),
 249	mTrackedStatus(LLTracker::TRACKING_NOTHING),
 250	mListFriendCombo(NULL),
 251	mListLandmarkCombo(NULL),
 252	mListSearchResults(NULL)
 253{
 254	gFloaterWorldMap = this;
 255	
 256	mFactoryMap["objects_mapview"] = LLCallbackMap(createWorldMapView, NULL);
 257	
 258	mCommitCallbackRegistrar.add("WMap.Coordinates",	boost::bind(&LLFloaterWorldMap::onCoordinatesCommit, this));
 259	mCommitCallbackRegistrar.add("WMap.Location",		boost::bind(&LLFloaterWorldMap::onLocationCommit, this));
 260	mCommitCallbackRegistrar.add("WMap.AvatarCombo",	boost::bind(&LLFloaterWorldMap::onAvatarComboCommit, this));
 261	mCommitCallbackRegistrar.add("WMap.Landmark",		boost::bind(&LLFloaterWorldMap::onLandmarkComboCommit, this));
 262	mCommitCallbackRegistrar.add("WMap.SearchResult",	boost::bind(&LLFloaterWorldMap::onCommitSearchResult, this));
 263	mCommitCallbackRegistrar.add("WMap.GoHome",			boost::bind(&LLFloaterWorldMap::onGoHome, this));	
 264	mCommitCallbackRegistrar.add("WMap.Teleport",		boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));	
 265	mCommitCallbackRegistrar.add("WMap.ShowTarget",		boost::bind(&LLFloaterWorldMap::onShowTargetBtn, this));	
 266	mCommitCallbackRegistrar.add("WMap.ShowAgent",		boost::bind(&LLFloaterWorldMap::onShowAgentBtn, this));		
 267	mCommitCallbackRegistrar.add("WMap.Clear",			boost::bind(&LLFloaterWorldMap::onClearBtn, this));		
 268	mCommitCallbackRegistrar.add("WMap.CopySLURL",		boost::bind(&LLFloaterWorldMap::onCopySLURL, this));
 269	
 270	gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLFloaterWorldMap::onChangeMaturity, this));
 271}
 272
 273// static
 274void* LLFloaterWorldMap::createWorldMapView(void* data)
 275{
 276	return new LLWorldMapView();
 277}
 278
 279BOOL LLFloaterWorldMap::postBuild()
 280{
 281	mPanel = getChild<LLPanel>("objects_mapview");
 282	
 283	LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");
 284	avatar_combo->selectFirstItem();
 285	avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) );
 286	avatar_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
 287	mListFriendCombo = dynamic_cast<LLCtrlListInterface *>(avatar_combo);
 288	
 289	LLSearchEditor *location_editor = getChild<LLSearchEditor>("location");
 290	location_editor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1));
 291	location_editor->setKeystrokeCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this));
 292	
 293	getChild<LLScrollListCtrl>("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));
 294	mListSearchResults = childGetListInterface("search_results");
 295	
 296	LLComboBox *landmark_combo = getChild<LLComboBox>( "landmark combo");
 297	landmark_combo->selectFirstItem();
 298	landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) );
 299	landmark_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
 300	mListLandmarkCombo = dynamic_cast<LLCtrlListInterface *>(landmark_combo);
 301	
 302	mCurZoomVal = log(LLWorldMapView::sMapScale)/log(2.f);
 303	getChild<LLUICtrl>("zoom slider")->setValue(LLWorldMapView::sMapScale);
 304	
 305	setDefaultBtn(NULL);
 306	
 307	mZoomTimer.stop();
 308	
 309	onChangeMaturity();
 310	
 311	return TRUE;
 312}
 313
 314// virtual
 315LLFloaterWorldMap::~LLFloaterWorldMap()
 316{
 317	// All cleaned up by LLView destructor
 318	mPanel = NULL;
 319	
 320	// Inventory deletes all observers on shutdown
 321	mInventory = NULL;
 322	mInventoryObserver = NULL;
 323	
 324	// avatar tracker will delete this for us.
 325	mFriendObserver = NULL;
 326	
 327	gFloaterWorldMap = NULL;
 328}
 329
 330//static
 331LLFloaterWorldMap* LLFloaterWorldMap::getInstance()
 332{
 333	return LLFloaterReg::getTypedInstance<LLFloaterWorldMap>("world_map");
 334}
 335
 336// virtual
 337void LLFloaterWorldMap::onClose(bool app_quitting)
 338{
 339	// While we're not visible, discard the overlay images we're using
 340	LLWorldMap::getInstance()->clearImageRefs();
 341}
 342
 343// virtual
 344void LLFloaterWorldMap::onOpen(const LLSD& key)
 345{
 346	bool center_on_target = (key.asString() == "center");
 347	
 348	mIsClosing = FALSE;
 349	
 350	LLWorldMapView* map_panel;
 351	map_panel = (LLWorldMapView*)gFloaterWorldMap->mPanel;
 352	map_panel->clearLastClick();
 353	
 354	{
 355		// reset pan on show, so it centers on you again
 356		if (!center_on_target)
 357		{
 358			LLWorldMapView::setPan(0, 0, TRUE);
 359		}
 360		map_panel->updateVisibleBlocks();
 361		
 362		// Reload items as they may have changed
 363		LLWorldMap::getInstance()->reloadItems();
 364		
 365		// We may already have a bounding box for the regions of the world,
 366		// so use that to adjust the view.
 367		adjustZoomSliderBounds();
 368		
 369		// Could be first show
 370		//LLFirstUse::useMap();
 371		
 372		// Start speculative download of landmarks
 373		const LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
 374		LLInventoryModelBackgroundFetch::instance().start(landmark_folder_id);
 375		
 376		getChild<LLUICtrl>("location")->setFocus( TRUE);
 377		gFocusMgr.triggerFocusFlash();
 378		
 379		buildAvatarIDList();
 380		buildLandmarkIDLists();
 381		
 382		// If nothing is being tracked, set flag so the user position will be found
 383		mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
 384	}
 385	
 386	if (center_on_target)
 387	{
 388		centerOnTarget(FALSE);
 389	}
 390}
 391
 392// static
 393void LLFloaterWorldMap::reloadIcons(void*)
 394{
 395	LLWorldMap::getInstance()->reloadItems();
 396}
 397
 398// virtual
 399BOOL LLFloaterWorldMap::handleHover(S32 x, S32 y, MASK mask)
 400{
 401	BOOL handled;
 402	handled = LLFloater::handleHover(x, y, mask);
 403	return handled;
 404}
 405
 406BOOL LLFloaterWorldMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
 407{
 408	if (!isMinimized() && isFrontmost())
 409	{
 410		if(mPanel->pointInView(x, y))
 411		{
 412			F32 slider_value = (F32)getChild<LLUICtrl>("zoom slider")->getValue().asReal();
 413			slider_value += ((F32)clicks * -0.3333f);
 414			getChild<LLUICtrl>("zoom slider")->setValue(LLSD(slider_value));
 415			return TRUE;
 416		}
 417	}
 418	
 419	return LLFloater::handleScrollWheel(x, y, clicks);
 420}
 421
 422
 423// virtual
 424void LLFloaterWorldMap::reshape( S32 width, S32 height, BOOL called_from_parent )
 425{
 426	LLFloater::reshape( width, height, called_from_parent );
 427}
 428
 429
 430// virtual
 431void LLFloaterWorldMap::draw()
 432{
 433	static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white);
 434	static LLUIColor map_track_disabled_color = LLUIColorTable::instance().getColor("MapTrackDisabledColor", LLColor4::white);
 435	
 436	// On orientation island, users don't have a home location yet, so don't
 437	// let them teleport "home".  It dumps them in an often-crowed welcome
 438	// area (infohub) and they get confused. JC
 439	LLViewerRegion* regionp = gAgent.getRegion();
 440	bool agent_on_prelude = (regionp && regionp->isPrelude());
 441	bool enable_go_home = gAgent.isGodlike() || !agent_on_prelude;
 442	getChildView("Go Home")->setEnabled(enable_go_home);
 443	
 444	updateLocation();
 445	
 446	LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus(); 
 447	if (LLTracker::TRACKING_AVATAR == tracking_status)
 448	{
 449		getChild<LLUICtrl>("avatar_icon")->setColor( map_track_color);
 450	}
 451	else
 452	{
 453		getChild<LLUICtrl>("avatar_icon")->setColor( map_track_disabled_color);
 454	}
 455	
 456	if (LLTracker::TRACKING_LANDMARK == tracking_status)
 457	{
 458		getChild<LLUICtrl>("landmark_icon")->setColor( map_track_color);
 459	}
 460	else
 461	{
 462		getChild<LLUICtrl>("landmark_icon")->setColor( map_track_disabled_color);
 463	}
 464	
 465	if (LLTracker::TRACKING_LOCATION == tracking_status)
 466	{
 467		getChild<LLUICtrl>("location_icon")->setColor( map_track_color);
 468	}
 469	else
 470	{
 471		if (mCompletingRegionName != "")
 472		{
 473			F64 seconds = LLTimer::getElapsedSeconds();
 474			double value = fmod(seconds, 2);
 475			value = 0.5 + 0.5*cos(value * F_PI);
 476			LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0);
 477			getChild<LLUICtrl>("location_icon")->setColor( loading_color);
 478		}
 479		else
 480		{
 481			getChild<LLUICtrl>("location_icon")->setColor( map_track_disabled_color);
 482		}
 483	}
 484	
 485	// check for completion of tracking data
 486	if (mWaitingForTracker)
 487	{
 488		centerOnTarget(TRUE);
 489	}
 490	
 491	getChildView("Teleport")->setEnabled((BOOL)tracking_status);
 492	//	getChildView("Clear")->setEnabled((BOOL)tracking_status);
 493	getChildView("Show Destination")->setEnabled((BOOL)tracking_status || LLWorldMap::getInstance()->isTracking());
 494	getChildView("copy_slurl")->setEnabled((mSLURL.isValid()) );
 495	
 496	setMouseOpaque(TRUE);
 497	getDragHandle()->setMouseOpaque(TRUE);
 498	
 499	//RN: snaps to zoom value because interpolation caused jitter in the text rendering
 500	if (!mZoomTimer.getStarted() && mCurZoomVal != (F32)getChild<LLUICtrl>("zoom slider")->getValue().asReal())
 501	{
 502		mZoomTimer.start();
 503	}
 504	F32 interp = mZoomTimer.getElapsedTimeF32() / MAP_ZOOM_TIME;
 505	if (interp > 1.f)
 506	{
 507		interp = 1.f;
 508		mZoomTimer.stop();
 509	}
 510	mCurZoomVal = lerp(mCurZoomVal, (F32)getChild<LLUICtrl>("zoom slider")->getValue().asReal(), interp);
 511	F32 map_scale = 256.f*pow(2.f, mCurZoomVal);
 512	LLWorldMapView::setScale( map_scale );
 513	
 514	// Enable/disable checkboxes depending on the zoom level
 515	// If above threshold level (i.e. low res) -> Disable all checkboxes
 516	// If under threshold level (i.e. high res) -> Enable all checkboxes
 517	bool enable = LLWorldMapView::showRegionInfo();
 518	getChildView("people_chk")->setEnabled(enable);
 519	getChildView("infohub_chk")->setEnabled(enable);
 520	getChildView("telehub_chk")->setEnabled(enable);
 521	getChildView("land_for_sale_chk")->setEnabled(enable);
 522	getChildView("event_chk")->setEnabled(enable);
 523	getChildView("events_mature_chk")->setEnabled(enable);
 524	getChildView("events_adult_chk")->setEnabled(enable);
 525	
 526	LLFloater::draw();
 527}
 528
 529
 530//-------------------------------------------------------------------------
 531// Internal utility functions
 532//-------------------------------------------------------------------------
 533
 534
 535void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const std::string& name )
 536{
 537	LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
 538	if (!iface) return;
 539	
 540	buildAvatarIDList();
 541	if(iface->setCurrentByID(avatar_id) || gAgent.isGodlike())
 542	{
 543		// *HACK: Adjust Z values automatically for liaisons & gods so
 544		// they swoop down when they click on the map. Requested
 545		// convenience.
 546		if(gAgent.isGodlike())
 547		{
 548			getChild<LLUICtrl>("spin z")->setValue(LLSD(200.f));
 549		}
 550		// Don't re-request info if we already have it or we won't have it in time to teleport
 551		if (mTrackedStatus != LLTracker::TRACKING_AVATAR || name != mTrackedAvatarName)
 552		{
 553			mTrackedStatus = LLTracker::TRACKING_AVATAR;
 554			mTrackedAvatarName = name;
 555			LLTracker::trackAvatar(avatar_id, name);
 556		}
 557	}
 558	else
 559	{
 560		LLTracker::stopTracking(NULL);
 561	}
 562	setDefaultBtn("Teleport");
 563}
 564
 565void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
 566{
 567	LLCtrlSelectionInterface *iface = childGetSelectionInterface("landmark combo");
 568	if (!iface) return;
 569	
 570	buildLandmarkIDLists();
 571	BOOL found = FALSE;
 572	S32 idx;
 573	for (idx = 0; idx < mLandmarkItemIDList.count(); idx++)
 574	{
 575		if ( mLandmarkItemIDList.get(idx) == landmark_item_id)
 576		{
 577			found = TRUE;
 578			break;
 579		}
 580	}
 581	
 582	if (found && iface->setCurrentByID( landmark_item_id ) ) 
 583	{
 584		LLUUID asset_id = mLandmarkAssetIDList.get( idx );
 585		std::string name;
 586		LLComboBox* combo = getChild<LLComboBox>( "landmark combo");
 587		if (combo) name = combo->getSimple();
 588		mTrackedStatus = LLTracker::TRACKING_LANDMARK;
 589		LLTracker::trackLandmark(mLandmarkAssetIDList.get( idx ),	// assetID
 590								 mLandmarkItemIDList.get( idx ), // itemID
 591								 name);			// name
 592		
 593		if( asset_id != sHomeID )
 594		{
 595			// start the download process
 596			gLandmarkList.getAsset( asset_id);
 597		}
 598		
 599		// We have to download both region info and landmark data, so set busy. JC
 600		//		getWindow()->incBusyCount();
 601	}
 602	else
 603	{
 604		LLTracker::stopTracking(NULL);
 605	}
 606	setDefaultBtn("Teleport");
 607}
 608
 609
 610void LLFloaterWorldMap::trackEvent(const LLItemInfo &event_info)
 611{
 612	mTrackedStatus = LLTracker::TRACKING_LOCATION;
 613	LLTracker::trackLocation(event_info.getGlobalPosition(), event_info.getName(), event_info.getToolTip(), LLTracker::LOCATION_EVENT);
 614	setDefaultBtn("Teleport");
 615}
 616
 617void LLFloaterWorldMap::trackGenericItem(const LLItemInfo &item)
 618{
 619	mTrackedStatus = LLTracker::TRACKING_LOCATION;
 620	LLTracker::trackLocation(item.getGlobalPosition(), item.getName(), item.getToolTip(), LLTracker::LOCATION_ITEM);
 621	setDefaultBtn("Teleport");
 622}
 623
 624void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
 625{
 626	LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global);
 627	if (!sim_info)
 628	{
 629		// We haven't found a region for that point yet, leave the tracking to the world map
 630		LLWorldMap::getInstance()->setTracking(pos_global);
 631		LLTracker::stopTracking(NULL);
 632		S32 world_x = S32(pos_global.mdV[0] / 256);
 633		S32 world_y = S32(pos_global.mdV[1] / 256);
 634		LLWorldMapMessage::getInstance()->sendMapBlockRequest(world_x, world_y, world_x, world_y, true);
 635		setDefaultBtn("");
 636		
 637		// clicked on a non-region - turn off coord display
 638		enableTeleportCoordsDisplay( false );
 639		
 640		return;
 641	}
 642	if (sim_info->isDown())
 643	{
 644		// Down region. Show the blue circle of death!
 645		// i.e. let the world map that this and tell it it's invalid
 646		LLWorldMap::getInstance()->setTracking(pos_global);
 647		LLWorldMap::getInstance()->setTrackingInvalid();
 648		LLTracker::stopTracking(NULL);
 649		setDefaultBtn("");
 650		
 651		// clicked on a down region - turn off coord display
 652		enableTeleportCoordsDisplay( false );
 653		
 654		return;
 655	}
 656	
 657	std::string sim_name = sim_info->getName();
 658	F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS );
 659	F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS );
 660	std::string full_name = llformat("%s (%d, %d, %d)", 
 661									 sim_name.c_str(), 
 662									 llround(region_x), 
 663									 llround(region_y),
 664									 llround((F32)pos_global.mdV[VZ]));
 665	
 666	std::string tooltip("");
 667	mTrackedStatus = LLTracker::TRACKING_LOCATION;
 668	LLTracker::trackLocation(pos_global, full_name, tooltip);
 669	LLWorldMap::getInstance()->cancelTracking();		// The floater is taking over the tracking
 670	
 671	LLVector3d coord_pos = LLTracker::getTrackedPositionGlobal();
 672	updateTeleportCoordsDisplay( coord_pos );
 673	
 674	// we have a valid region - turn on coord display
 675	enableTeleportCoordsDisplay( true );
 676	
 677	setDefaultBtn("Teleport");
 678}
 679
 680// enable/disable teleport destination coordinates 
 681void LLFloaterWorldMap::enableTeleportCoordsDisplay( bool enabled )
 682{
 683	childSetEnabled("teleport_coordinate_x", enabled );
 684	childSetEnabled("teleport_coordinate_y", enabled );
 685	childSetEnabled("teleport_coordinate_z", enabled );
 686}
 687
 688// update display of teleport destination coordinates - pos is in global coordinates
 689void LLFloaterWorldMap::updateTeleportCoordsDisplay( const LLVector3d& pos )
 690{
 691	// if we're going to update their value, we should also enable them
 692	enableTeleportCoordsDisplay( true );
 693	
 694	// convert global specified position to a local one
 695	F32 region_local_x = (F32)fmod( pos.mdV[VX], (F64)REGION_WIDTH_METERS );
 696	F32 region_local_y = (F32)fmod( pos.mdV[VY], (F64)REGION_WIDTH_METERS );
 697	F32 region_local_z = (F32)llclamp( pos.mdV[VZ], 0.0, (F64)REGION_HEIGHT_METERS );
 698
 699	// write in the values
 700	childSetValue("teleport_coordinate_x", region_local_x );
 701	childSetValue("teleport_coordinate_y", region_local_y );
 702	childSetValue("teleport_coordinate_z", region_local_z );
 703}
 704
 705void LLFloaterWorldMap::updateLocation()
 706{
 707	bool gotSimName;
 708	
 709	LLTracker::ETrackingStatus status = LLTracker::getTrackingStatus();
 710	
 711	// These values may get updated by a message, so need to check them every frame
 712	// The fields may be changed by the user, so only update them if the data changes
 713	LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
 714	if (pos_global.isExactlyZero())
 715	{
 716		LLVector3d agentPos = gAgent.getPositionGlobal();
 717		
 718		// Set to avatar's current postion if nothing is selected
 719		if ( status == LLTracker::TRACKING_NOTHING && mSetToUserPosition )
 720		{
 721			// Make sure we know where we are before setting the current user position
 722			std::string agent_sim_name;
 723			gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal( agentPos, agent_sim_name );
 724			if ( gotSimName )
 725			{
 726				mSetToUserPosition = FALSE;
 727				
 728				// Fill out the location field
 729				getChild<LLUICtrl>("location")->setValue(agent_sim_name);
 730				
 731				// update the coordinate display with location of avatar in region
 732				updateTeleportCoordsDisplay( agentPos );
 733				
 734				// Figure out where user is
 735				// Set the current SLURL
 736				mSLURL = LLSLURL(agent_sim_name, gAgent.getPositionGlobal());
 737			}
 738		}
 739		
 740		return; // invalid location
 741	}
 742	std::string sim_name;
 743	gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal( pos_global, sim_name );
 744	if ((status != LLTracker::TRACKING_NOTHING) &&
 745		(status != mTrackedStatus || pos_global != mTrackedLocation || sim_name != mTrackedSimName))
 746	{
 747		mTrackedStatus = status;
 748		mTrackedLocation = pos_global;
 749		mTrackedSimName = sim_name;
 750		
 751		if (status == LLTracker::TRACKING_AVATAR)
 752		{
 753			// *HACK: Adjust Z values automatically for liaisons &
 754			// gods so they swoop down when they click on the
 755			// map. Requested convenience.
 756			if(gAgent.isGodlike())
 757			{
 758				pos_global[2] = 200;
 759			}
 760		}
 761		
 762		getChild<LLUICtrl>("location")->setValue(sim_name);
 763		
 764		// refresh coordinate display to reflect where user clicked.
 765		LLVector3d coord_pos = LLTracker::getTrackedPositionGlobal();
 766		updateTeleportCoordsDisplay( coord_pos );
 767		
 768		// simNameFromPosGlobal can fail, so don't give the user an invalid SLURL
 769		if ( gotSimName )
 770		{
 771			mSLURL = LLSLURL(sim_name, pos_global);
 772		}
 773		else
 774		{	// Empty SLURL will disable the "Copy SLURL to clipboard" button
 775			mSLURL = LLSLURL();
 776		}
 777	}
 778}
 779
 780void LLFloaterWorldMap::trackURL(const std::string& region_name, S32 x_coord, S32 y_coord, S32 z_coord)
 781{
 782	LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromName(region_name);
 783	z_coord = llclamp(z_coord, 0, 4096);
 784	if (sim_info)
 785	{
 786		LLVector3 local_pos;
 787		local_pos.mV[VX] = (F32)x_coord;
 788		local_pos.mV[VY] = (F32)y_coord;
 789		local_pos.mV[VZ] = (F32)z_coord;
 790		LLVector3d global_pos = sim_info->getGlobalPos(local_pos);
 791		trackLocation(global_pos);
 792		setDefaultBtn("Teleport");
 793	}
 794	else
 795	{
 796		// fill in UI based on URL
 797		gFloaterWorldMap->getChild<LLUICtrl>("location")->setValue(region_name);
 798		
 799		// Save local coords to highlight position after region global
 800		// position is returned.
 801		gFloaterWorldMap->mCompletingRegionPos.set(
 802												   (F32)x_coord, (F32)y_coord, (F32)z_coord);
 803		
 804		// pass sim name to combo box
 805		gFloaterWorldMap->mCompletingRegionName = region_name;
 806		LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name);
 807		LLStringUtil::toLower(gFloaterWorldMap->mCompletingRegionName);
 808		LLWorldMap::getInstance()->setTrackingCommit();
 809	}
 810}
 811
 812void LLFloaterWorldMap::observeInventory(LLInventoryModel* model)
 813{
 814	if(mInventory)
 815	{
 816		mInventory->removeObserver(mInventoryObserver);
 817		delete mInventoryObserver;
 818		mInventory = NULL;
 819		mInventoryObserver = NULL;
 820	}
 821	if(model)
 822	{
 823		mInventory = model;
 824		mInventoryObserver = new LLMapInventoryObserver;
 825		// Inventory deletes all observers on shutdown
 826		mInventory->addObserver(mInventoryObserver);
 827		inventoryChanged();
 828	}
 829}
 830
 831void LLFloaterWorldMap::inventoryChanged()
 832{
 833	if(!LLTracker::getTrackedLandmarkItemID().isNull())
 834	{
 835		LLUUID item_id = LLTracker::getTrackedLandmarkItemID();
 836		buildLandmarkIDLists();
 837		trackLandmark(item_id);
 838	}
 839}
 840
 841void LLFloaterWorldMap::observeFriends()
 842{
 843	if(!mFriendObserver)
 844	{
 845		mFriendObserver = new LLMapFriendObserver;
 846		LLAvatarTracker::instance().addObserver(mFriendObserver);
 847		friendsChanged();
 848	}
 849}
 850
 851void LLFloaterWorldMap::friendsChanged()
 852{
 853	LLAvatarTracker& t = LLAvatarTracker::instance();
 854	const LLUUID& avatar_id = t.getAvatarID();
 855	buildAvatarIDList();
 856	if(avatar_id.notNull())
 857	{
 858		LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
 859		const LLRelationship* buddy_info = t.getBuddyInfo(avatar_id);
 860		if(!iface ||
 861		   !iface->setCurrentByID(avatar_id) || 
 862		   (buddy_info && !buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)) ||
 863		   gAgent.isGodlike())
 864		{
 865			LLTracker::stopTracking(NULL);
 866		}
 867	}
 868}
 869
 870// No longer really builds a list.  Instead, just updates mAvatarCombo.
 871void LLFloaterWorldMap::buildAvatarIDList()
 872{
 873	LLCtrlListInterface *list = mListFriendCombo;
 874	if (!list) return;
 875	
 876    // Delete all but the "None" entry
 877	S32 list_size = list->getItemCount();
 878	if (list_size > 1)
 879	{
 880		list->selectItemRange(1, -1);
 881		list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
 882	}
 883	
 884	// Get all of the calling cards for avatar that are currently online
 885	LLCollectMappableBuddies collector;
 886	LLAvatarTracker::instance().applyFunctor(collector);
 887	LLCollectMappableBuddies::buddy_map_t::iterator it;
 888	LLCollectMappableBuddies::buddy_map_t::iterator end;
 889	it = collector.mMappable.begin();
 890	end = collector.mMappable.end();
 891	for( ; it != end; ++it)
 892	{
 893		list->addSimpleElement((*it).first, ADD_BOTTOM, (*it).second);
 894	}
 895	
 896	list->setCurrentByID( LLAvatarTracker::instance().getAvatarID() );
 897	list->selectFirstItem();
 898}
 899
 900
 901void LLFloaterWorldMap::buildLandmarkIDLists()
 902{
 903	LLCtrlListInterface *list = mListLandmarkCombo;
 904	if (!list) return;
 905	
 906    // Delete all but the "None" entry
 907	S32 list_size = list->getItemCount();
 908	if (list_size > 1)
 909	{
 910		list->selectItemRange(1, -1);
 911		list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
 912	}
 913	
 914	mLandmarkItemIDList.reset();
 915	mLandmarkAssetIDList.reset();
 916	
 917	// Get all of the current landmarks
 918	mLandmarkAssetIDList.put( LLUUID::null );
 919	mLandmarkItemIDList.put( LLUUID::null );
 920	
 921	mLandmarkAssetIDList.put( sHomeID );
 922	mLandmarkItemIDList.put( sHomeID );
 923	
 924	LLInventoryModel::cat_array_t cats;
 925	LLInventoryModel::item_array_t items;
 926	LLIsType is_landmark(LLAssetType::AT_LANDMARK);
 927	gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
 928									cats,
 929									items,
 930									LLInventoryModel::EXCLUDE_TRASH,
 931									is_landmark);
 932	
 933	std::sort(items.begin(), items.end(), LLViewerInventoryItem::comparePointers());
 934	
 935	S32 count = items.count();
 936	for(S32 i = 0; i < count; ++i)
 937	{
 938		LLInventoryItem* item = items.get(i);
 939		
 940		list->addSimpleElement(item->getName(), ADD_BOTTOM, item->getUUID());
 941		
 942		mLandmarkAssetIDList.put( item->getAssetUUID() );
 943		mLandmarkItemIDList.put( item->getUUID() );
 944	}
 945	
 946	list->selectFirstItem();
 947}
 948
 949
 950F32 LLFloaterWorldMap::getDistanceToDestination(const LLVector3d &destination, 
 951												F32 z_attenuation) const
 952{
 953	LLVector3d delta = destination - gAgent.getPositionGlobal();
 954	// by attenuating the z-component we effectively 
 955	// give more weight to the x-y plane
 956	delta.mdV[VZ] *= z_attenuation;
 957	F32 distance = (F32)delta.magVec();
 958	return distance;
 959}
 960
 961
 962void LLFloaterWorldMap::clearLocationSelection(BOOL clear_ui)
 963{
 964	LLCtrlListInterface *list = mListSearchResults;
 965	if (list)
 966	{
 967		list->operateOnAll(LLCtrlListInterface::OP_DELETE);
 968	}
 969	LLWorldMap::getInstance()->cancelTracking();
 970	mCompletingRegionName = "";
 971}
 972
 973
 974void LLFloaterWorldMap::clearLandmarkSelection(BOOL clear_ui)
 975{
 976	if (clear_ui || !childHasKeyboardFocus("landmark combo"))
 977	{
 978		LLCtrlListInterface *list = mListLandmarkCombo;
 979		if (list)
 980		{
 981			list->selectByValue( "None" );
 982		}
 983	}
 984}
 985
 986
 987void LLFloaterWorldMap::clearAvatarSelection(BOOL clear_ui)
 988{
 989	if (clear_ui || !childHasKeyboardFocus("friend combo"))
 990	{
 991		mTrackedStatus = LLTracker::TRACKING_NOTHING;
 992		LLCtrlListInterface *list = mListFriendCombo;
 993		if (list)
 994		{
 995			list->selectByValue( "None" );
 996		}
 997	}
 998}
 999
1000
1001// Adjust the maximally zoomed out limit of the zoom slider so you
1002// can see the whole world, plus a little.
1003void LLFloaterWorldMap::adjustZoomSliderBounds()
1004{
1005	// Merov: we switched from using the "world size" (which varies depending where the user went) to a fixed
1006	// width of 512 regions max visible at a time. This makes the zoom slider works in a consistent way across
1007	// sessions and doesn't prevent the user to pan the world if it was to grow a lot beyond that limit.
1008	// Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window.
1009	S32 world_width_regions	 = MAX_VISIBLE_REGIONS;
1010	S32 world_height_regions = MAX_VISIBLE_REGIONS;
1011	
1012	// Find how much space we have to display the world
1013	LLWorldMapView* map_panel;
1014	map_panel = (LLWorldMapView*)mPanel;
1015	LLRect view_rect = map_panel->getRect();
1016	
1017	// View size in pixels
1018	S32 view_width = view_rect.getWidth();
1019	S32 view_height = view_rect.getHeight();
1020	
1021	// Pixels per region to display entire width/height
1022	F32 width_pixels_per_region = (F32) view_width / (F32) world_width_regions;
1023	F32 height_pixels_per_region = (F32) view_height / (F32) world_height_regions;
1024	
1025	F32 pixels_per_region = llmin(width_pixels_per_region,
1026								  height_pixels_per_region);
1027	
1028	// Round pixels per region to an even number of slider increments
1029	S32 slider_units = llfloor(pixels_per_region / 0.2f);
1030	pixels_per_region = slider_units * 0.2f;
1031	
1032	// Make sure the zoom slider can be moved at least a little bit.
1033	// Likewise, less than the increment pixels per region is just silly.
1034	pixels_per_region = llclamp(pixels_per_region, 1.f, ZOOM_MAX);
1035	
1036	F32 min_power = log(pixels_per_region/256.f)/log(2.f);
1037	
1038	getChild<LLSliderCtrl>("zoom slider")->setMinValue(min_power);
1039}
1040
1041
1042//-------------------------------------------------------------------------
1043// User interface widget callbacks
1044//-------------------------------------------------------------------------
1045
1046void LLFloaterWorldMap::onGoHome()
1047{
1048	gAgent.teleportHome();
1049	closeFloater();
1050}
1051
1052
1053void LLFloaterWorldMap::onLandmarkComboPrearrange( )
1054{
1055	if( mIsClosing )
1056	{
1057		return;
1058	}
1059	
1060	LLCtrlListInterface *list = mListLandmarkCombo;
1061	if (!list) return;
1062	
1063	LLUUID current_choice = list->getCurrentID();
1064	
1065	buildLandmarkIDLists();
1066	
1067	if( current_choice.isNull() || !list->setCurrentByID( current_choice ) )
1068	{
1069		LLTracker::stopTracking(NULL);
1070	}
1071	
1072}
1073
1074void LLFloaterWorldMap::onComboTextEntry()
1075{
1076	// Reset the tracking whenever we start typing into any of the search fields,
1077	// so that hitting <enter> does an auto-complete versus teleporting us to the
1078	// previously selected landmark/friend.
1079	LLTracker::stopTracking(NULL);
1080}
1081
1082void LLFloaterWorldMap::onSearchTextEntry( )
1083{
1084	onComboTextEntry();
1085	updateSearchEnabled();
1086}
1087
1088
1089void LLFloaterWorldMap::onLandmarkComboCommit()
1090{
1091	if( mIsClosing )
1092	{
1093		return;
1094	}
1095	
1096	LLCtrlListInterface *list = mListLandmarkCombo;
1097	if (!list) return;
1098	
1099	LLUUID asset_id;
1100	LLUUID item_id = list->getCurrentID();
1101	
1102	LLTracker::stopTracking(NULL);
1103	
1104	//RN: stopTracking() clears current combobox selection, need to reassert it here
1105	list->setCurrentByID(item_id);
1106	
1107	if( item_id.isNull() )
1108	{
1109	}
1110	else if( item_id == sHomeID )
1111	{
1112		asset_id = sHomeID;
1113	}
1114	else
1115	{
1116		LLInventoryItem* item = gInventory.getItem( item_id );
1117		if( item )
1118		{
1119			asset_id = item->getAssetUUID();
1120		}
1121		else
1122		{
1123			// Something went wrong, so revert to a safe value.
1124			item_id.setNull();
1125		}
1126	}
1127	
1128	trackLandmark( item_id);
1129	onShowTargetBtn();
1130	
1131	// Reset to user postion if nothing is tracked
1132	mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
1133}
1134
1135// static 
1136void LLFloaterWorldMap::onAvatarComboPrearrange( )
1137{
1138	if( mIsClosing )
1139	{
1140		return;
1141	}
1142	
1143	LLCtrlListInterface *list = mListFriendCombo;
1144	if (!list) return;
1145	
1146	LLUUID current_choice;
1147	
1148	if( LLAvatarTracker::instance().haveTrackingInfo() )
1149	{
1150		current_choice = LLAvatarTracker::instance().getAvatarID();
1151	}
1152	
1153	buildAvatarIDList();
1154	
1155	if( !list->setCurrentByID( current_choice ) || current_choice.isNull() )
1156	{
1157		LLTracker::stopTracking(NULL);
1158	}
1159}
1160
1161void LLFloaterWorldMap::onAvatarComboCommit()
1162{
1163	if( mIsClosing )
1164	{
1165		return;
1166	}
1167	
1168	LLCtrlListInterface *list = mListFriendCombo;
1169	if (!list) return;
1170	
1171	const LLUUID& new_avatar_id = list->getCurrentID();
1172	if (new_avatar_id.notNull())
1173	{
1174		std::string name;
1175		LLComboBox* combo = getChild<LLComboBox>("friend combo");
1176		if (combo) name = combo->getSimple();
1177		trackAvatar(new_avatar_id, name);
1178		onShowTargetBtn();
1179	}
1180	else
1181	{	// Reset to user postion if nothing is tracked
1182		mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
1183	}
1184}
1185
1186void LLFloaterWorldMap::avatarTrackFromSlapp( const LLUUID& id ) 
1187{
1188	trackAvatar( id, "av" );		
1189	onShowTargetBtn();
1190}
1191
1192void LLFloaterWorldMap::onLocationFocusChanged( LLFocusableElement* focus )
1193{
1194	updateSearchEnabled();
1195}
1196
1197void LLFloaterWorldMap::updateSearchEnabled()
1198{
1199	if (childHasKeyboardFocus("location") && 
1200		getChild<LLUICtrl>("location")->getValue().asString().length() > 0)
1201	{
1202		setDefaultBtn("DoSearch");
1203	}
1204	else
1205	{
1206		setDefaultBtn(NULL);
1207	}
1208}
1209
1210void LLFloaterWorldMap::onLocationCommit()
1211{
1212	if( mIsClosing )
1213	{
1214		return;
1215	}
1216	
1217	clearLocationSelection(FALSE);
1218	mCompletingRegionName = "";
1219	mLastRegionName = "";
1220	
1221	std::string str = getChild<LLUICtrl>("location")->getValue().asString();
1222	
1223	// Trim any leading and trailing spaces in the search target
1224	std::string saved_str = str;
1225	LLStringUtil::trim( str );
1226	if ( str != saved_str )
1227	{	// Set the value in the UI if any spaces were removed
1228		getChild<LLUICtrl>("location")->setValue(str);
1229	}
1230
1231	// Don't try completing empty name (STORM-1427).
1232	if (str.empty())
1233	{
1234		return;
1235	}
1236	
1237	LLStringUtil::toLower(str);
1238	mCompletingRegionName = str;
1239	LLWorldMap::getInstance()->setTrackingCommit();
1240	if (str.length() >= 3)
1241	{
1242		LLWorldMapMessage::getInstance()->sendNamedRegionRequest(str);
1243	}
1244	else
1245	{
1246		str += "#";
1247		LLWorldMapMessage::getInstance()->sendNamedRegionRequest(str);
1248	}
1249}
1250
1251void LLFloaterWorldMap::onCoordinatesCommit()
1252{
1253	if( mIsClosing )
1254	{
1255		return;
1256	}
1257	
1258	S32 x_coord = (S32)childGetValue("teleport_coordinate_x").asReal();
1259	S32 y_coord = (S32)childGetValue("teleport_coordinate_y").asReal();
1260	S32 z_coord = (S32)childGetValue("teleport_coordinate_z").asReal();
1261	
1262	const std::string region_name = childGetValue("location").asString();
1263	
1264	trackURL( region_name, x_coord, y_coord, z_coord );
1265}
1266
1267void LLFloaterWorldMap::onClearBtn()
1268{
1269	mTrackedStatus = LLTracker::TRACKING_NOTHING;
1270	LLTracker::stopTracking((void *)(intptr_t)TRUE);
1271	LLWorldMap::getInstance()->cancelTracking();
1272	mSLURL = LLSLURL();					// Clear the SLURL since it's invalid
1273	mSetToUserPosition = TRUE;	// Revert back to the current user position
1274}
1275
1276void LLFloaterWorldMap::onShowTargetBtn()
1277{
1278	centerOnTarget(TRUE);
1279}
1280
1281void LLFloaterWorldMap::onShowAgentBtn()
1282{
1283	LLWorldMapView::setPan( 0, 0, FALSE); // FALSE == animate
1284	// Set flag so user's location will be displayed if not tracking anything else
1285	mSetToUserPosition = TRUE;	
1286}
1287
1288void LLFloaterWorldMap::onClickTeleportBtn()
1289{
1290	teleport();
1291}
1292
1293void LLFloaterWorldMap::onCopySLURL()
1294{
1295	getWindow()->copyTextToClipboard(utf8str_to_wstring(mSLURL.getSLURLString()));
1296	
1297	LLSD args;
1298	args["SLURL"] = mSLURL.getSLURLString();
1299	
1300	LLNotificationsUtil::add("CopySLURL", args);
1301}
1302
1303// protected
1304void LLFloaterWorldMap::centerOnTarget(BOOL animate)
1305{
1306	LLVector3d pos_global;
1307	if(LLTracker::getTrackingStatus() != LLTracker::TRACKING_NOTHING)
1308	{
1309		LLVector3d tracked_position = LLTracker::getTrackedPositionGlobal();
1310		//RN: tracker doesn't allow us to query completion, so we check for a tracking position of
1311		// absolute zero, and keep trying in the draw loop
1312		if (tracked_position.isExactlyZero())
1313		{
1314			mWaitingForTracker = TRUE;
1315			return;
1316		}
1317		else
1318		{
1319			// We've got the position finally, so we're no longer busy. JC
1320			//			getWindow()->decBusyCount();
1321			pos_global = LLTracker::getTrackedPositionGlobal() - gAgentCamera.getCameraPositionGlobal();
1322		}
1323	}
1324	else if(LLWorldMap::getInstance()->isTracking())
1325	{
1326		pos_global = LLWorldMap::getInstance()->getTrackedPositionGlobal() - gAgentCamera.getCameraPositionGlobal();;
1327		
1328		
1329		
1330	}
1331	else
1332	{
1333		// default behavior = center on agent
1334		pos_global.clearVec();
1335	}
1336	
1337	LLWorldMapView::setPan( -llfloor((F32)(pos_global.mdV[VX] * (F64)LLWorldMapView::sMapScale / REGION_WIDTH_METERS)), 
1338						   -llfloor((F32)(pos_global.mdV[VY] * (F64)LLWorldMapView::sMapScale / REGION_WIDTH_METERS)),
1339						   !animate);
1340	mWaitingForTracker = FALSE;
1341}
1342
1343// protected
1344void LLFloaterWorldMap::fly()
1345{
1346	LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
1347	
1348	// Start the autopilot and close the floater, 
1349	// so we can see where we're flying
1350	if (!pos_global.isExactlyZero())
1351	{
1352		gAgent.startAutoPilotGlobal( pos_global );
1353		closeFloater();
1354	}
1355	else
1356	{
1357		make_ui_sound("UISndInvalidOp");
1358	}
1359}
1360
1361
1362// protected
1363void LLFloaterWorldMap::teleport()
1364{
1365	BOOL teleport_home = FALSE;
1366	LLVector3d pos_global;
1367	LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
1368	
1369	LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
1370	if (LLTracker::TRACKING_AVATAR == tracking_status
1371		&& av_tracker.haveTrackingInfo() )
1372	{
1373		pos_global = av_tracker.getGlobalPos();
1374		pos_global.mdV[VZ] = getChild<LLUICtrl>("spin z")->getValue();
1375	}
1376	else if ( LLTracker::TRACKING_LANDMARK == tracking_status)
1377	{
1378		if( LLTracker::getTrackedLandmarkAssetID() == sHomeID )
1379		{
1380			teleport_home = TRUE;
1381		}
1382		else
1383		{
1384			LLLandmark* landmark = gLandmarkList.getAsset( LLTracker::getTrackedLandmarkAssetID() );
1385			LLUUID region_id;
1386			if(landmark
1387			   && !landmark->getGlobalPos(pos_global)
1388			   && landmark->getRegionID(region_id))
1389			{
1390				LLLandmark::requestRegionHandle(
1391												gMessageSystem,
1392												gAgent.getRegionHost(),
1393												region_id,
1394												NULL);
1395			}
1396		}
1397	}
1398	else if ( LLTracker::TRACKING_LOCATION == tracking_status)
1399	{
1400		pos_global = LLTracker::getTrackedPositionGlobal();
1401	}
1402	else
1403	{
1404		make_ui_sound("UISndInvalidOp");
1405	}
1406	
1407	// Do the teleport, which will also close the floater
1408	if (teleport_home)
1409	{
1410		gAgent.teleportHome();
1411	}
1412	else if (!pos_global.isExactlyZero())
1413	{
1414		if(LLTracker::TRACKING_LANDMARK == tracking_status)
1415		{
1416			gAgent.teleportViaLandmark(LLTracker::getTrackedLandmarkAssetID());
1417		}
1418		else
1419		{
1420			gAgent.teleportViaLocation( pos_global );
1421		}
1422	}
1423}
1424
1425void LLFloaterWorldMap::flyToLandmark()
1426{
1427	LLVector3d destination_pos_global;
1428	if( !LLTracker::getTrackedLandmarkAssetID().isNull() )
1429	{
1430		if (LLTracker::hasLandmarkPosition())
1431		{
1432			gAgent.startAutoPilotGlobal( LLTracker::getTrackedPositionGlobal() );
1433		}
1434	}
1435}
1436
1437void LLFloaterWorldMap::teleportToLandmark()
1438{
1439	BOOL has_destination = FALSE;
1440	LLUUID destination_id; // Null means "home"
1441	
1442	if( LLTracker::getTrackedLandmarkAssetID() == sHomeID )
1443	{
1444		has_destination = TRUE;
1445	}
1446	else
1447	{
1448		LLLandmark* landmark = gLandmarkList.getAsset( LLTracker::getTrackedLandmarkAssetID() );
1449		LLVector3d global_pos;
1450		if(landmark && landmark->getGlobalPos(global_pos))
1451		{
1452			destination_id = LLTracker::getTrackedLandmarkAssetID();
1453			has_destination = TRUE;
1454		}
1455		else if(landmark)
1456		{
1457			// pop up an anonymous request request.
1458			LLUUID region_id;
1459			if(landmark->getRegionID(region_id))
1460			{
1461				LLLandmark::requestRegionHandle(
1462												gMessageSystem,
1463												gAgent.getRegionHost(),
1464												region_id,
1465												NULL);
1466			}
1467		}
1468	}
1469	
1470	if( has_destination )
1471	{
1472		gAgent.teleportViaLandmark( destination_id );
1473	}
1474}
1475
1476
1477void LLFloaterWorldMap::teleportToAvatar()
1478{
1479	LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
1480	if(av_tracker.haveTrackingInfo())
1481	{
1482		LLVector3d pos_global = av_tracker.getGlobalPos();
1483		gAgent.teleportViaLocation( pos_global );
1484	}
1485}
1486
1487
1488void LLFloaterWorldMap::flyToAvatar()
1489{
1490	if( LLAvatarTracker::instance().haveTrackingInfo() )
1491	{
1492		gAgent.startAutoPilotGlobal( LLAvatarTracker::instance().getGlobalPos() );
1493	}
1494}
1495
1496void LLFloaterWorldMap::updateSims(bool found_null_sim)
1497{
1498	if (mCompletingRegionName == "")
1499	{
1500		return;
1501	}
1502	
1503	LLScrollListCtrl *list = getChild<LLScrollListCtrl>("search_results");
1504	list->operateOnAll(LLCtrlListInterface::OP_DELETE);
1505	
1506	S32 name_length = mCompletingRegionName.length();
1507	
1508	LLSD match;
1509
1510	S32 num_results = 0;
1511
1512	std::vector<std::pair <U64, LLSimInfo*> > sim_info_vec(LLWorldMap::getInstance()->getRegionMap().begin(), LLWorldMap::getInstance()->getRegionMap().end());
1513	std::sort(sim_info_vec.begin(), sim_info_vec.end(), SortRegionNames());
1514
1515	for (std::vector<std::pair <U64, LLSimInfo*> >::const_iterator it = sim_info_vec.begin(); it != sim_info_vec.end(); ++it)
1516	{
1517		LLSimInfo* info = it->second;
1518		std::string sim_name_lower = info->getName();
1519		LLStringUtil::toLower(sim_name_lower);
1520		
1521		if (sim_name_lower.substr(0, name_length) == mCompletingRegionName)
1522		{
1523			if (sim_name_lower == mCompletingRegionName)
1524			{
1525				match = info->getName();
1526			}
1527			
1528			LLSD value;
1529			value["id"] = info->getName();
1530			value["columns"][0]["column"] = "sim_name";
1531			value["columns"][0]["value"] = info->getName();
1532			list->addElement(value);
1533			num_results++;
1534		}
1535	}
1536	
1537	if (found_null_sim)
1538	{
1539		mCompletingRegionName = "";
1540	}
1541	
1542	if (num_results > 0)
1543	{
1544		// if match found, highlight it and go
1545		if (!match.isUndefined())
1546		{
1547			list->selectByValue(match);
1548		}
1549		// else select first found item
1550		else
1551		{
1552			list->selectFirstItem();
1553		}
1554		getChild<LLUICtrl>("search_results")->setFocus(TRUE);
1555		onCommitSearchResult();
1556	}
1557	else
1558	{
1559		// if we found nothing, say "none"
1560		list->setCommentText(LLTrans::getString("worldmap_results_none_found"));
1561		list->operateOnAll(LLCtrlListInterface::OP_DESELECT);
1562	}
1563}
1564
1565
1566void LLFloaterWorldMap::onCommitSearchResult()
1567{
1568	LLCtrlListInterface *list = mListSearchResults;
1569	if (!list) return;
1570	
1571	LLSD selected_value = list->getSelectedValue();
1572	std::string sim_name = selected_value.asString();
1573	if (sim_name.empty())
1574	{
1575		return;
1576	}
1577	LLStringUtil::toLower(sim_name);
1578	
1579	std::map<U64, LLSimInfo*>::const_iterator it;
1580	for (it = LLWorldMap::getInstance()->getRegionMap().begin(); it != LLWorldMap::getInstance()->getRegionMap().end(); ++it)
1581	{
1582		LLSimInfo* info = it->second;
1583		
1584		if (info->isName(sim_name))
1585		{
1586			LLVector3d pos_global = info->getGlobalOrigin();
1587			
1588			const F64 SIM_COORD_DEFAULT = 128.0;
1589			LLVector3 pos_local(SIM_COORD_DEFAULT, SIM_COORD_DEFAULT, 0.0f);
1590			
1591			// Did this value come from a trackURL() request?
1592			if (!mCompletingRegionPos.isExactlyZero())
1593			{
1594				pos_local = mCompletingRegionPos;
1595				mCompletingRegionPos.clear();
1596			}
1597			pos_global.mdV[VX] += (F64)pos_local.mV[VX];
1598			pos_global.mdV[VY] += (F64)pos_local.mV[VY];
1599			pos_global.mdV[VZ] = (F64)pos_local.mV[VZ];
1600			
1601			getChild<LLUICtrl>("location")->setValue(sim_name);
1602			trackLocation(pos_global);
1603			setDefaultBtn("Teleport");
1604			break;
1605		}
1606	}
1607	
1608	onShowTargetBtn();
1609}
1610
1611void LLFloaterWorldMap::onChangeMaturity()
1612{
1613	bool can_access_mature = gAgent.canAccessMature();
1614	bool can_access_adult = gAgent.canAccessAdult();
1615	
1616	getChildView("events_mature_icon")->setVisible( can_access_mature);
1617	getChildView("events_mature_label")->setVisible( can_access_mature);
1618	getChildView("events_mature_chk")->setVisible( can_access_mature);
1619	
1620	getChildView("events_adult_icon")->setVisible( can_access_adult);
1621	getChildView("events_adult_label")->setVisible( can_access_adult);
1622	getChildView("events_adult_chk")->setVisible( can_access_adult);
1623	
1624	// disable mature / adult events.
1625	if (!can_access_mature)
1626	{
1627		gSavedSettings.setBOOL("ShowMatureEvents", FALSE);
1628	}
1629	if (!can_access_adult)
1630	{
1631		gSavedSettings.setBOOL("ShowAdultEvents", FALSE);
1632	}
1633}