PATH-773: fix up how the location and grid selectors work on the login panel

master
Oz Linden 2012-06-25 17:04:32 -04:00
parent f92e7d30a8
commit 1b8bbc7b86
10 changed files with 408 additions and 361 deletions

View File

@ -772,7 +772,7 @@ void LLFloaterPreference::onBtnOK()
llinfos << "Can't close preferences!" << llendl;
}
LLPanelLogin::updateLocationCombo( false );
LLPanelLogin::updateLocationSelectorsVisibility();
}
// static
@ -789,7 +789,7 @@ void LLFloaterPreference::onBtnApply( )
apply();
saveSettings();
LLPanelLogin::updateLocationCombo( false );
LLPanelLogin::updateLocationSelectorsVisibility();
}
// static

View File

@ -104,7 +104,6 @@ public:
// Public methods
//---------------------------------------------------------------------------
LLPanelLogin::LLPanelLogin(const LLRect &rect,
BOOL show_server,
void (*callback)(S32 option, void* user_data),
void *cb_data)
: LLPanel(),
@ -119,7 +118,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
// instance management
if (LLPanelLogin::sInstance)
{
llwarns << "Duplicate instance of login view deleted" << llendl;
LL_WARNS("AppInit") << "Duplicate instance of login view deleted" << LL_ENDL;
// Don't leave bad pointer in gFocusMgr
gFocusMgr.setDefaultKeyboardFocus(NULL);
@ -152,12 +151,36 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
LLSLURL slurl(gSavedSettings.getString("LoginLocation"));
LLStartUp::setStartSLURL(slurl);
}
updateLocationCombo(false);
LLComboBox* location_combo = getChild<LLComboBox>("start_location_combo");
updateLocationSelectorsVisibility(); // separate so that it can be called from preferences
location_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this));
LLComboBox* server_choice_combo = getChild<LLComboBox>("server_combo");
server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this));
LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
server_choice_combo->setCommitCallback(onSelectServer, NULL);
server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1));
updateServerCombo();
// Load all of the grids, sorted, and then add a bar and the current grid at the top
server_choice_combo->removeall();
std::string current_grid = LLGridManager::getInstance()->getGrid();
std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids();
for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin();
grid_choice != known_grids.end();
grid_choice++)
{
if (!grid_choice->first.empty() && current_grid != grid_choice->first)
{
LL_DEBUGS("AppInit")<<"adding "<<grid_choice->first<<LL_ENDL;
server_choice_combo->add(grid_choice->second, grid_choice->first);
}
}
server_choice_combo->sortByName();
server_choice_combo->addSeparator(ADD_TOP);
LL_DEBUGS("AppInit")<<"adding current "<<current_grid<<LL_ENDL;
server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(),
current_grid,
ADD_TOP);
server_choice_combo->selectFirstItem();
childSetAction("connect_btn", onClickConnect, this);
@ -167,10 +190,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
std::string version = llformat("%s (%d)",
LLVersionInfo::getShortVersion().c_str(),
LLVersionInfo::getBuild());
//LLTextBox* channel_text = getChild<LLTextBox>("channel_text");
//channel_text->setTextArg("[CHANNEL]", channel); // though not displayed
//channel_text->setTextArg("[VERSION]", version);
//channel_text->setClickedCallback(onClickVersion, this);
LLTextBox* forgot_password_text = getChild<LLTextBox>("forgot_password_text");
forgot_password_text->setClickedCallback(onClickForgotPassword, NULL);
@ -192,9 +211,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
// Show last logged in user favorites in "Start at" combo.
addUsersWithFavoritesToUsername();
getChild<LLComboBox>("username_combo")->setTextChangedCallback(boost::bind(&LLPanelLogin::addFavoritesToStartLocation, this));
updateLocationCombo(false);
}
void LLPanelLogin::addUsersWithFavoritesToUsername()
@ -403,11 +419,10 @@ void LLPanelLogin::showLoginWidgets()
// static
void LLPanelLogin::show(const LLRect &rect,
BOOL show_server,
void (*callback)(S32 option, void* user_data),
void* callback_data)
{
new LLPanelLogin(rect, show_server, callback, callback_data);
new LLPanelLogin(rect, callback, callback_data);
if( !gFocusMgr.getKeyboardFocus() )
{
@ -567,21 +582,6 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,
remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue();
}
// static
BOOL LLPanelLogin::isGridComboDirty()
{
BOOL user_picked = FALSE;
if (!sInstance)
{
llwarns << "Attempted getServer with no login view shown" << llendl;
}
else
{
LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
user_picked = combo->isDirty();
}
return user_picked;
}
// static
BOOL LLPanelLogin::areCredentialFieldsDirty()
@ -611,83 +611,69 @@ BOOL LLPanelLogin::areCredentialFieldsDirty()
// static
void LLPanelLogin::updateLocationCombo( bool force_visible )
void LLPanelLogin::updateLocationSelectorsVisibility()
{
if (!sInstance)
if (sInstance)
{
return;
BOOL show_start = gSavedSettings.getBOOL("ShowStartLocation");
sInstance->getChildView("start_location_combo")->setVisible(show_start);
sInstance->getChildView("start_location_text")->setVisible(show_start);
BOOL show_server = gSavedSettings.getBOOL("ForceShowGrid");
LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
server_choice_combo->setVisible( show_server );
}
LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
switch(LLStartUp::getStartSLURL().getType())
{
case LLSLURL::LOCATION:
{
combo->setCurrentByIndex( 2 );
combo->setTextEntry(LLStartUp::getStartSLURL().getLocationString());
break;
}
case LLSLURL::HOME_LOCATION:
combo->setCurrentByIndex(1);
break;
default:
combo->setCurrentByIndex(0);
break;
}
BOOL show_start = TRUE;
if ( ! force_visible )
show_start = gSavedSettings.getBOOL("ShowStartLocation");
sInstance->getChildView("start_location_combo")->setVisible( show_start);
sInstance->getChildView("start_location_text")->setVisible( show_start);
BOOL show_server = gSavedSettings.getBOOL("ForceShowGrid");
sInstance->getChildView("server_combo_text")->setVisible( show_server);
sInstance->getChildView("server_combo")->setVisible( show_server);
}
// static
void LLPanelLogin::updateStartSLURL()
// static - called from LLStartUp::setStartSLURL
void LLPanelLogin::onUpdateStartSLURL(const LLSLURL& new_start_slurl)
{
if (!sInstance) return;
LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
S32 index = combo->getCurrentIndex();
switch (index)
LL_DEBUGS("AppInit")<<new_start_slurl.asString()<<LL_ENDL;
LLComboBox* location_combo = sInstance->getChild<LLComboBox>("start_location_combo");
/*
* Determine whether or not the new_start_slurl modifies the grid.
*
* Note that some forms that could be in the slurl are grid-agnostic.,
* such as "home". Other forms, such as
* https://grid.example.com/region/Party%20Town/20/30/5
* specify a particular grid; in those cases we want to change the grid
* and the grid selector to match the new value.
*/
if ( LLSLURL::LOCATION == new_start_slurl.getType() )
{
case 0:
std::string slurl_grid = LLGridManager::getInstance()->getGrid(new_start_slurl.getGrid());
if ( ! slurl_grid.empty() ) // is that a valid grid?
{
LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST));
break;
}
case 1:
{
LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
break;
}
default:
{
LLSLURL slurl = LLSLURL(combo->getValue().asString());
if(slurl.getType() == LLSLURL::LOCATION)
if ( slurl_grid != LLGridManager::getInstance()->getGrid() ) // new grid?
{
// we've changed the grid, so update the grid selection
LLStartUp::setStartSLURL(slurl);
// the slurl changes the grid, so update everything to match
LLGridManager::getInstance()->setGridChoice(slurl_grid);
// update the grid selector to match the slurl
LLComboBox* server_combo = sInstance->getChild<LLComboBox>("server_combo");
std::string server_label(LLGridManager::getInstance()->getGridLabel(slurl_grid));
server_combo->setSimple(server_label);
updateServer(); // to change the links and splash screen
}
break;
}
location_combo->setTextEntry(new_start_slurl.getLocationString());
}
else
{
// the grid specified by the slurl is not known
LLNotificationsUtil::add("InvalidLocationSLURL");
location_combo->setTextEntry(LLStringUtil::null);
}
}
}
void LLPanelLogin::setLocation(const LLSLURL& slurl)
{
LLStartUp::setStartSLURL(slurl);
updateServer();
LL_DEBUGS("AppInit")<<"setting Location "<<slurl.asString()<<LL_ENDL;
LLStartUp::setStartSLURL(slurl); // calls onUpdateStartSLURL, above
}
// static
@ -775,6 +761,7 @@ void LLPanelLogin::loadLoginPage()
LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
if (web_browser->getCurrentNavUrl() != oStr.str())
{
LL_DEBUGS("AppInit")<<oStr.str()<<LL_ENDL;
web_browser->navigateTo( oStr.str(), "text/html" );
}
}
@ -812,15 +799,9 @@ void LLPanelLogin::onClickConnect(void *)
LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
LLSD combo_val = combo->getSelectedValue();
if (combo_val.isUndefined())
{
combo_val = combo->getValue();
}
if(combo_val.isUndefined())
{
LLNotificationsUtil::add("StartRegionEmpty");
return;
}
// the grid definitions may come from a user-supplied grids.xml, so they may not be good
LL_DEBUGS("AppInit")<<"grid "<<combo_val.asString()<<LL_ENDL;
try
{
LLGridManager::getInstance()->setGridChoice(combo_val.asString());
@ -832,9 +813,10 @@ void LLPanelLogin::onClickConnect(void *)
LLNotificationsUtil::add("InvalidGrid", args);
return;
}
updateStartSLURL();
std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
// The start location SLURL has already been sent to LLStartUp::setStartSLURL
std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
if(username.empty())
{
@ -923,8 +905,6 @@ void LLPanelLogin::updateServer()
{
try
{
updateServerCombo();
// if they've selected another grid, we should load the credentials
// for that grid and set them to the UI.
if(sInstance && !sInstance->areCredentialFieldsDirty())
@ -933,9 +913,15 @@ void LLPanelLogin::updateServer()
bool remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue();
sInstance->setFields(credential, remember);
}
// update the login panel links
bool system_grid = LLGridManager::getInstance()->isSystemGrid();
sInstance->getChildView("create_new_account_text")->setVisible( system_grid);
sInstance->getChildView("forgot_password_text")->setVisible( system_grid);
// grid changed so show new splash screen (possibly)
loadLoginPage();
updateLocationCombo(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION);
}
catch (LLInvalidGridName ex)
{
@ -947,94 +933,64 @@ void LLPanelLogin::updateServer()
}
}
void LLPanelLogin::updateServerCombo()
void LLPanelLogin::onSelectServer()
{
if (!sInstance)
{
return;
}
// We add all of the possible values, sorted, and then add a bar and the current value at the top
LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
server_choice_combo->removeall();
std::string current_grid = LLGridManager::getInstance()->getGrid();
std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids();
for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin();
grid_choice != known_grids.end();
grid_choice++)
{
if (!grid_choice->first.empty() && current_grid != grid_choice->first)
{
LL_DEBUGS("AppInit")<<"adding "<<grid_choice->first<<LL_ENDL;
server_choice_combo->add(grid_choice->second, grid_choice->first);
}
}
server_choice_combo->sortByName();
server_choice_combo->addSeparator(ADD_TOP);
LL_DEBUGS("AppInit")<<"adding current "<<current_grid<<LL_ENDL;
server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(),
current_grid,
ADD_TOP);
server_choice_combo->selectFirstItem();
}
// static
void LLPanelLogin::onSelectServer(LLUICtrl*, void*)
{
// *NOTE: The paramters for this method are ignored.
// LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*)
// calls this method.
// The user twiddled with the grid choice ui.
// apply the selection to the grid setting.
LLPointer<LLCredential> credential;
LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
LLSD combo_val = combo->getSelectedValue();
if (combo_val.isUndefined())
{
combo_val = combo->getValue();
}
LL_INFOS("AppInit") << "onSelectServer "<<combo_val.asString()<< LL_ENDL;
LLComboBox* server_combo = getChild<LLComboBox>("server_combo");
LLSD server_combo_val = server_combo->getSelectedValue();
LL_INFOS("AppInit") << "grid "<<server_combo_val.asString()<< LL_ENDL;
LLGridManager::getInstance()->setGridChoice(server_combo_val.asString());
combo = sInstance->getChild<LLComboBox>("start_location_combo");
combo->setCurrentByIndex(1);
LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation")));
LLGridManager::getInstance()->setGridChoice(combo_val.asString());
// This new selection will override preset uris
// from the command line.
/*
* Determine whether or not the value in the start_location_combo makes sense
* with the new grid value.
*
* Note that some forms that could be in the location combo are grid-agnostic,
* such as "MyRegion/128/128/0". There could be regions with that name on any
* number of grids, so leave them alone. Other forms, such as
* https://grid.example.com/region/Party%20Town/20/30/5 specify a particular
* grid; in those cases we want to clear the location.
*/
LLComboBox* location_combo = getChild<LLComboBox>("start_location_combo");
S32 index = location_combo->getCurrentIndex();
switch (index)
{
case 0: // last location
case 1: // home location
// do nothing - these are grid-agnostic locations
break;
default:
{
std::string location = location_combo->getValue().asString();
LLSLURL slurl(location); // generata a slurl from the location combo contents
if ( slurl.getType() == LLSLURL::LOCATION
&& slurl.getGrid() != LLGridManager::getInstance()->getGrid()
)
{
// the grid specified by the location is not this one, so clear the combo
location_combo->setCurrentByIndex(0); // last location on the new grid
location_combo->setTextEntry(LLStringUtil::null);
}
}
break;
}
updateServer();
updateLocationCombo(false);
updateLoginPanelLinks();
}
void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe)
void LLPanelLogin::onLocationSLURL()
{
if (!sInstance)
{
return;
}
LLComboBox* location_combo = getChild<LLComboBox>("start_location_combo");
std::string location = location_combo->getValue().asString();
LL_DEBUGS("AppInit")<<location<<LL_ENDL;
LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
if(fe == combo)
{
onSelectServer(combo, NULL);
}
LLStartUp::setStartSLURL(location); // calls onUpdateStartSLURL, above
}
void LLPanelLogin::updateLoginPanelLinks()
{
bool system_grid = LLGridManager::getInstance()->isSystemGrid();
// need to call through sInstance, as it's called from onSelectServer, which
// is static.
sInstance->getChildView("create_new_account_text")->setVisible( system_grid);
sInstance->getChildView("forgot_password_text")->setVisible( system_grid);
}
std::string canonicalize_username(const std::string& name)
{

View File

@ -44,7 +44,7 @@ class LLPanelLogin:
{
LOG_CLASS(LLPanelLogin);
public:
LLPanelLogin(const LLRect &rect, BOOL show_server,
LLPanelLogin(const LLRect &rect,
void (*callback)(S32 option, void* user_data),
void *callback_data);
~LLPanelLogin();
@ -57,7 +57,7 @@ public:
// hidden on startup for reg-in-client
static void showLoginWidgets();
static void show(const LLRect &rect, BOOL show_server,
static void show(const LLRect &rect,
void (*callback)(S32 option, void* user_data),
void* callback_data);
@ -65,11 +65,12 @@ public:
static void getFields(LLPointer<LLCredential>& credential, BOOL& remember);
static BOOL isGridComboDirty();
static BOOL areCredentialFieldsDirty();
static void setLocation(const LLSLURL& slurl);
static void updateLocationCombo(bool force_visible); // simply update the combo box
/// Call when preferences that control visibility may have changed
static void updateLocationSelectorsVisibility();
static void closePanel();
void setSiteIsAlive( bool alive );
@ -82,22 +83,24 @@ public:
/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
static void updateServer(); // update the combo box, change the login page to the new server, clear the combo
/// to be called from LLStartUp::setStartSLURL
static void onUpdateStartSLURL(const LLSLURL& new_start_slurl);
private:
friend class LLPanelLoginListener;
void reshapeBrowser();
void addFavoritesToStartLocation();
void addUsersWithFavoritesToUsername();
void onSelectServer();
void onLocationSLURL();
static void onClickConnect(void*);
static void onClickNewAccount(void*);
static void onClickVersion(void*);
static void onClickForgotPassword(void*);
static void onClickHelp(void*);
static void onPassKey(LLLineEditor* caller, void* user_data);
static void onSelectServer(LLUICtrl*, void*);
static void onServerComboLostFocus(LLFocusableElement*);
static void updateServerCombo();
static void updateStartSLURL();
static void updateLoginPanelLinks();
private:
LLPointer<LLUIImage> mLogoImage;

View File

@ -56,14 +56,13 @@ LLSLURL::LLSLURL(const std::string& slurl)
{
// by default we go to agni.
mType = INVALID;
LL_INFOS("AppInit") << "SLURL: " << slurl << LL_ENDL;
if(slurl == SIM_LOCATION_HOME)
{
mType = HOME_LOCATION;
}
else if(slurl.empty() || (slurl == SIM_LOCATION_LAST))
{
mType = LAST_LOCATION;
}
else
@ -80,6 +79,7 @@ LLSLURL::LLSLURL(const std::string& slurl)
// these slurls are typically passed in from the 'starting location' box on the login panel,
// where the user can type in <regionname>/<x>/<y>/<z>
std::string fixed_slurl = LLGridManager::getInstance()->getSLURLBase();
// the slurl that was passed in might have a prepended /, or not. So,
// we strip off the prepended '/' so we don't end up with http://slurl.com/secondlife/<region>/<x>/<y>/<z>
// or some such.
@ -138,7 +138,7 @@ LLSLURL::LLSLURL(const std::string& slurl)
// so parse the grid name to derive the grid ID
if (!slurl_uri.hostName().empty())
{
mGrid = LLGridManager::getInstance()->getGrid(slurl_uri.hostName());
mGrid = LLGridManager::getInstance()->getGridId(slurl_uri.hostName());
}
else if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)
{
@ -150,12 +150,13 @@ LLSLURL::LLSLURL(const std::string& slurl)
{
// for app style slurls, where no grid name is specified, assume the currently
// selected or logged in grid.
mGrid = LLGridManager::getInstance()->getGrid();
mGrid = LLGridManager::getInstance()->getGridId();
}
if(mGrid.empty())
{
// we couldn't find the grid in the grid manager, so bail
LL_WARNS("AppInit")<<"unable to find grid"<<LL_ENDL;
return;
}
// set the type as appropriate.
@ -334,7 +335,7 @@ LLSLURL::LLSLURL(const std::string& grid,
LLSLURL::LLSLURL(const std::string& region,
const LLVector3& position)
{
*this = LLSLURL(LLGridManager::getInstance()->getGrid(),
*this = LLSLURL(LLGridManager::getInstance()->getGridId(),
region, position);
}
@ -343,7 +344,7 @@ LLSLURL::LLSLURL(const std::string& grid,
const std::string& region,
const LLVector3d& global_position)
{
*this = LLSLURL(grid,
*this = LLSLURL(LLGridManager::getInstance()->getGridId(grid),
region, LLVector3(global_position.mdV[VX],
global_position.mdV[VY],
global_position.mdV[VZ]));
@ -353,7 +354,7 @@ LLSLURL::LLSLURL(const std::string& grid,
LLSLURL::LLSLURL(const std::string& region,
const LLVector3d& global_position)
{
*this = LLSLURL(LLGridManager::getInstance()->getGrid(),
*this = LLSLURL(LLGridManager::getInstance()->getGridId(),
region, global_position);
}
@ -426,7 +427,7 @@ std::string LLSLURL::getLoginString() const
unescaped_start << "last";
break;
default:
LL_WARNS("AppInit") << "Unexpected SLURL type for login string" << (int)mType << LL_ENDL;
LL_WARNS("AppInit") << "Unexpected SLURL type ("<<(int)mType <<")for login string"<< LL_ENDL;
break;
}
return xml_escape_string(unescaped_start.str());
@ -465,18 +466,47 @@ std::string LLSLURL::getLocationString() const
(int)llround(mPosition[1]),
(int)llround(mPosition[2]));
}
// static
const std::string LLSLURL::typeName[NUM_SLURL_TYPES] =
{
"INVALID",
"LOCATION",
"HOME_LOCATION",
"LAST_LOCATION",
"APP",
"HELP"
};
std::string LLSLURL::getTypeString(SLURL_TYPE type)
{
std::string name;
if ( type >= INVALID && type < NUM_SLURL_TYPES )
{
name = LLSLURL::typeName[type];
}
else
{
name = llformat("Out of Range (%d)",type);
}
return name;
}
std::string LLSLURL::asString() const
{
std::ostringstream result;
result << " mAppCmd:" << getAppCmd() <<
" mAppPath:" + getAppPath().asString() <<
" mAppQueryMap:" + getAppQueryMap().asString() <<
" mAppQuery: " + getAppQuery() <<
" mGrid: " + getGrid() <<
" mRegion: " + getRegion() <<
" mPosition: " <<
" mType: " << mType <<
" mPosition: " << mPosition;
result
<< " mType: " << LLSLURL::getTypeString(mType)
<< " mGrid: " + getGrid()
<< " mRegion: " + getRegion()
<< " mPosition: " << mPosition
<< " mAppCmd:" << getAppCmd()
<< " mAppPath:" + getAppPath().asString()
<< " mAppQueryMap:" + getAppQueryMap().asString()
<< " mAppQuery: " + getAppQuery()
;
return result.str();
}

View File

@ -51,13 +51,15 @@ public:
static const char* SLURL_APP_PATH;
static const char* SLURL_REGION_PATH;
// if you modify this enumeration, update typeName as well
enum SLURL_TYPE {
INVALID,
LOCATION,
HOME_LOCATION,
LAST_LOCATION,
APP,
HELP
HELP,
NUM_SLURL_TYPES // must be last
};
@ -92,6 +94,10 @@ public:
std::string asString() const ;
protected:
static const std::string typeName[NUM_SLURL_TYPES];
/// Get a human-readable version of the type for logging
static std::string getTypeString(SLURL_TYPE type);
SLURL_TYPE mType;
// used for Apps and Help

View File

@ -1921,7 +1921,8 @@ bool idle_startup()
{
llinfos << "gAgentStartLocation : " << gAgentStartLocation << llendl;
LLSLURL start_slurl = LLStartUp::getStartSLURL();
LL_DEBUGS("AppInit") << "start slurl "<<start_slurl.asString()<<LL_ENDL;
if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) ||
((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) ||
((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home")))
@ -2183,21 +2184,13 @@ void login_show()
{
LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL;
#ifdef LL_RELEASE_FOR_DOWNLOAD
BOOL bUseDebugLogin = gSavedSettings.getBOOL("UseDebugLogin");
#else
BOOL bUseDebugLogin = TRUE;
#endif
// Hide the toolbars: may happen to come back here if login fails after login agent but before login in region
if (gToolBarView)
{
gToolBarView->setVisible(FALSE);
}
LLPanelLogin::show( gViewerWindow->getWindowRectScaled(),
bUseDebugLogin || gSavedSettings.getBOOL("SecondLifeEnterprise"),
login_callback, NULL );
LLPanelLogin::show( gViewerWindow->getWindowRectScaled(), login_callback, NULL );
}
// Callback for when login screen is closed. Option 0 = connect, option 1 = quit.
@ -2276,7 +2269,7 @@ bool login_alert_status(const LLSD& notification, const LLSD& response)
// break;
case 2: // Teleport
// Restart the login process, starting at our home locaton
LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
break;
default:
@ -2826,22 +2819,21 @@ bool LLStartUp::dispatchURL()
void LLStartUp::setStartSLURL(const LLSLURL& slurl)
{
sStartSLURL = slurl;
LL_DEBUGS("AppInit")<<slurl.asString()<<LL_ENDL;
switch(slurl.getType())
{
case LLSLURL::HOME_LOCATION:
{
gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_HOME);
break;
}
gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_HOME);
break;
case LLSLURL::LAST_LOCATION:
{
gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_LAST);
break;
}
gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_LAST);
break;
default:
LLGridManager::getInstance()->setGridChoice(slurl.getGrid());
break;
break;
}
LLPanelLogin::onUpdateStartSLURL(slurl); // updates grid if needed
}
/**

View File

@ -354,15 +354,13 @@ void LLGridManager::addSystemGrid(const std::string& label,
grid[GRID_ID_VALUE] = login_id;
}
// only add the system grids beyond agni to the visible list
// if we're building a debug version.
if (name == std::string(MAINGRID))
{
grid[GRID_SLURL_BASE] = MAIN_GRID_SLURL_BASE;
}
else
{
grid[GRID_SLURL_BASE] = llformat(SYSTEM_GRID_SLURL_BASE, label.c_str());
grid[GRID_SLURL_BASE] = llformat(SYSTEM_GRID_SLURL_BASE, grid[GRID_ID_VALUE].asString().c_str());
}
addGrid(grid);
}
@ -384,28 +382,22 @@ std::map<std::string, std::string> LLGridManager::getKnownGrids()
void LLGridManager::setGridChoice(const std::string& grid)
{
// Set the grid choice based on a string.
// The string must be a grid label from the gGridInfo table
LL_DEBUGS("GridManager")<<"requested "<<grid<<LL_ENDL;
std::string grid_name = getGrid(grid); // resolved either the name or the id to the name
// loop through. We could do just a hash lookup but we also want to match
// on the id
std::string grid_name = grid;
if(!mGridList.has(grid_name))
if(!grid_name.empty())
{
// case insensitive
grid_name = getGrid(grid);
LL_INFOS("GridManager")<<"setting "<<grid_name<<LL_ENDL;
mGrid = grid_name;
gSavedSettings.setString("CurrentGrid", grid_name);
updateIsInProductionGrid();
}
if(grid_name.empty())
else
{
// the grid was not in the list of grids.
LLSD grid_data = LLSD::emptyMap();
grid_data[GRID_VALUE] = grid;
addGrid(grid_data);
LL_WARNS("GridManager")<<"unknown grid "<<grid<<LL_ENDL;
}
mGrid = grid;
gSavedSettings.setString("CurrentGrid", grid);
updateIsInProductionGrid();
}
std::string LLGridManager::getGrid( const std::string &grid )
@ -435,6 +427,14 @@ std::string LLGridManager::getGrid( const std::string &grid )
}
}
}
if (grid_name.empty())
{
LL_WARNS("GridManager")<<"No name found for grid '"<<grid<<"'"<<LL_ENDL;
}
else
{
LL_DEBUGS("GridManager")<<"grid '"<<grid<<"' name is '"<<grid_name<<"'"<<LL_ENDL;
}
return grid_name;
}
@ -589,27 +589,39 @@ bool LLGridManager::isSystemGrid(const std::string& grid)
// build a slurl for the given region within the selected grid
std::string LLGridManager::getSLURLBase(const std::string& grid)
{
std::string grid_base;
if(mGridList.has(grid) && mGridList[grid].has(GRID_SLURL_BASE))
std::string grid_base = "";
std::string grid_name = getGrid(grid);
if( ! grid_name.empty() && mGridList.has(grid_name) )
{
return mGridList[grid][GRID_SLURL_BASE].asString();
}
else
{
return llformat(DEFAULT_SLURL_BASE, grid.c_str());
if (mGridList[grid_name].has(GRID_SLURL_BASE))
{
grid_base = mGridList[grid_name][GRID_SLURL_BASE].asString();
}
else
{
grid_base = llformat(DEFAULT_SLURL_BASE, grid_name.c_str());
}
}
LL_DEBUGS("GridManager")<<"returning '"<<grid_base<<"'"<<LL_ENDL;
return grid_base;
}
// build a slurl for the given region within the selected grid
std::string LLGridManager::getAppSLURLBase(const std::string& grid)
{
std::string grid_base;
if(mGridList.has(grid) && mGridList[grid].has(GRID_APP_SLURL_BASE))
std::string grid_base = "";
std::string grid_name = getGrid(grid);
if(!grid_name.empty() && mGridList.has(grid))
{
return mGridList[grid][GRID_APP_SLURL_BASE].asString();
}
else
{
return llformat(DEFAULT_APP_SLURL_BASE, grid.c_str());
if (mGridList[grid].has(GRID_APP_SLURL_BASE))
{
grid_base = mGridList[grid][GRID_APP_SLURL_BASE].asString();
}
else
{
grid_base = llformat(DEFAULT_APP_SLURL_BASE, grid_name.c_str());
}
}
LL_DEBUGS("GridManager")<<"returning '"<<grid_base<<"'"<<LL_ENDL;
return grid_base;
}

View File

@ -921,6 +921,14 @@ You need to enter either the Username or both the First and Last name of your av
'[GRID]' is not a valid grid identifier.
</notification>
<notification
icon="alertmodal.tga"
name="InvalidLocationSLURL"
type="alertmodal">
<tag>fail</tag>
Your start location did not specify a valid grid.
</notification>
<notification
icon="alertmodal.tga"
name="DeleteClassified"
@ -1212,7 +1220,7 @@ There was a problem saving a compiled script due to the following reason: [REASO
icon="alertmodal.tga"
name="StartRegionEmpty"
type="alertmodal">
Oops, Your Start Region is not defined.
Your Start Region is not defined.
Please type the Region name in Start Location box or choose My Last Location or My Home as your Start Location.
<tag>fail</tag>
<usetemplate

View File

@ -200,17 +200,6 @@
right="-10"
width="200">
Need help logging in? </text>
<!-- <text
follows="right|bottom"
font="SansSerifSmall"
halign="right"
height="28"
top_pad="2"
name="channel_text"
width="180"
word_wrap="true">
[VERSION]
</text>-->
</layout_panel>
</layout_stack>
</panel>

View File

@ -1,4 +1,4 @@
/**
/**
* @file llsecapi_test.cpp
* @author Roxie
* @date 2009-02-10
@ -7,21 +7,21 @@
* $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$
*/
@ -31,8 +31,8 @@
#include "../llslurl.h"
#include "../../llxml/llcontrol.h"
#include "llsdserialize.h"
//----------------------------------------------------------------------------
// Mock objects for the dependencies of the code we're testing
//----------------------------------------------------------------------------
// Mock objects for the dependencies of the code we're testing
LLControlGroup::LLControlGroup(const std::string& name)
: LLInstanceTracker<LLControlGroup, std::string>(name) {}
@ -80,6 +80,39 @@ LLPointer<LLControlVariable> LLControlGroup::getControl(const std::string& name)
}
LLControlGroup gSavedSettings("test");
const char *gSampleGridFile =
"<?xml version=\"1.0\"?>"
"<llsd>"
" <map>"
" <key>foo.bar.com</key>"
" <map>"
" <key>helper_uri</key><string>https://foobar/helpers/</string>"
" <key>label</key><string>Foobar Grid</string>"
" <key>login_page</key><string>foobar/loginpage</string>"
" <key>login_uri</key>"
" <array>"
" <string>foobar/loginuri</string>"
" </array>"
" <key>name</key><string>foo.bar.com</string>"
" <key>credential_type</key><string>agent</string>"
" <key>grid_login_id</key><string>FooBar</string>"
" </map>"
" <key>my.grid.com</key>"
" <map>"
" <key>helper_uri</key><string>https://mygrid/helpers/</string>"
" <key>label</key><string>My Grid</string>"
" <key>login_page</key><string>mygrid/loginpage</string>"
" <key>login_uri</key>"
" <array>"
" <string>mygrid/loginuri</string>"
" </array>"
" <key>name</key><string>my.grid.com</string>"
" <key>credential_type</key><string>agent</string>"
" <key>grid_login_id</key><string>MyGrid</string>"
" </map>"
" </map>"
"</llsd>"
;
// -------------------------------------------------------------------------------------------
// TUT
@ -90,171 +123,189 @@ namespace tut
struct slurlTest
{
slurlTest()
{
{
LLGridManager::getInstance()->initialize(std::string(""));
}
~slurlTest()
{
}
};
// Tut templating thingamagic: test group, object and test instance
typedef test_group<slurlTest> slurlTestFactory;
typedef slurlTestFactory::object slurlTestObject;
tut::slurlTestFactory tut_test("LLSlurl");
// ---------------------------------------------------------------------------------------
// Test functions
// Test functions
// ---------------------------------------------------------------------------------------
// construction from slurl string
template<> template<>
void slurlTestObject::test<1>()
{
llofstream gridfile("grid_test.xml");
gridfile << gSampleGridFile;
gridfile.close();
LLGridManager::getInstance()->initialize("grid_test.xml");
LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com");
LLSLURL slurl = LLSLURL("");
ensure_equals("null slurl", (int)slurl.getType(), LLSLURL::LAST_LOCATION);
slurl = LLSLURL("http://slurl.com/secondlife/myregion");
ensure_equals("slurl.com slurl, region only - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("slurl.com slurl, region only", slurl.getSLURLString(),
ensure_equals("slurl.com slurl, region only", slurl.getSLURLString(),
"http://maps.secondlife.com/secondlife/myregion/128/128/0");
slurl = LLSLURL("http://maps.secondlife.com/secondlife/myregion/1/2/3");
ensure_equals("maps.secondlife.com slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("maps.secondlife.com slurl, region + coords", slurl.getSLURLString(),
ensure_equals("maps.secondlife.com slurl, region + coords", slurl.getSLURLString(),
"http://maps.secondlife.com/secondlife/myregion/1/2/3");
slurl = LLSLURL("secondlife://myregion");
ensure_equals("secondlife: slurl, region only - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("secondlife: slurl, region only", slurl.getSLURLString(),
ensure_equals("secondlife: slurl, region only", slurl.getSLURLString(),
"http://maps.secondlife.com/secondlife/myregion/128/128/0");
slurl = LLSLURL("secondlife://myregion/1/2/3");
ensure_equals("secondlife: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("secondlife slurl, region + coords", slurl.getSLURLString(),
ensure_equals("secondlife slurl, region + coords", slurl.getSLURLString(),
"http://maps.secondlife.com/secondlife/myregion/1/2/3");
slurl = LLSLURL("/myregion");
ensure_equals("/region slurl, region- type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("/region slurl, region ", slurl.getSLURLString(),
ensure_equals("/region slurl, region ", slurl.getSLURLString(),
"http://maps.secondlife.com/secondlife/myregion/128/128/0");
slurl = LLSLURL("/myregion/1/2/3");
ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("/ slurl, region + coords", slurl.getSLURLString(),
"http://maps.secondlife.com/secondlife/myregion/1/2/3");
ensure_equals("/ slurl, region + coords", slurl.getSLURLString(),
"http://maps.secondlife.com/secondlife/myregion/1/2/3");
slurl = LLSLURL("my region/1/2/3");
ensure_equals(" slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals(" slurl, region + coords", slurl.getSLURLString(),
"http://maps.secondlife.com/secondlife/my%20region/1/2/3");
LLGridManager::getInstance()->setGridChoice("my.grid.com");
ensure_equals(" slurl, region + coords", slurl.getSLURLString(),
"http://maps.secondlife.com/secondlife/my%20region/1/2/3");
LLGridManager::getInstance()->setGridChoice("my.grid.com");
slurl = LLSLURL("https://my.grid.com/region/my%20region/1/2/3");
ensure_equals("grid slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("grid slurl, region + coords", slurl.getSLURLString(),
"https://my.grid.com/region/my%20region/1/2/3");
ensure_equals("grid slurl, region + coords", slurl.getSLURLString(),
"https://my.grid.com/region/my%20region/1/2/3");
slurl = LLSLURL("https://my.grid.com/region/my region");
ensure_equals("grid slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("grid slurl, region + coords", slurl.getSLURLString(),
ensure_equals("grid slurl, region + coords", slurl.getSLURLString(),
"https://my.grid.com/region/my%20region/128/128/0");
LLGridManager::getInstance()->setGridChoice("foo.bar.com");
LLGridManager::getInstance()->setGridChoice("foo.bar.com");
slurl = LLSLURL("/myregion/1/2/3");
ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("/ slurl, region + coords", slurl.getSLURLString(),
"https://foo.bar.com/region/myregion/1/2/3");
ensure_equals("/ slurl, region + coords", slurl.getSLURLString(),
"https://foo.bar.com/region/myregion/1/2/3");
slurl = LLSLURL("myregion/1/2/3");
ensure_equals(": slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals(" slurl, region + coords", slurl.getSLURLString(),
"https://foo.bar.com/region/myregion/1/2/3");
ensure_equals(" slurl, region + coords", slurl.getSLURLString(),
"https://foo.bar.com/region/myregion/1/2/3");
slurl = LLSLURL(LLSLURL::SIM_LOCATION_HOME);
ensure_equals("home", slurl.getType(), LLSLURL::HOME_LOCATION);
slurl = LLSLURL(LLSLURL::SIM_LOCATION_LAST);
ensure_equals("last", slurl.getType(), LLSLURL::LAST_LOCATION);
slurl = LLSLURL("secondlife:///app/foo/bar?12345");
ensure_equals("app", slurl.getType(), LLSLURL::APP);
ensure_equals("appcmd", slurl.getAppCmd(), "foo");
ensure_equals("apppath", slurl.getAppPath().size(), 1);
ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar");
ensure_equals("appquery", slurl.getAppQuery(), "12345");
ensure_equals("grid1", "foo.bar.com", slurl.getGrid());
slurl = LLSLURL("secondlife://Aditi/app/foo/bar?12345");
ensure_equals("app", slurl.getType(), LLSLURL::APP);
ensure_equals("appcmd", slurl.getAppCmd(), "foo");
ensure_equals("apppath", slurl.getAppPath().size(), 1);
ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar");
ensure_equals("appquery", slurl.getAppQuery(), "12345");
ensure_equals("grid2", "util.aditi.lindenlab.com", slurl.getGrid());
LLGridManager::getInstance()->setGridChoice("foo.bar.com");
slurl = LLSLURL("secondlife:///app/foo/bar?12345");
ensure_equals("app", slurl.getType(), LLSLURL::APP);
ensure_equals("appcmd", slurl.getAppCmd(), "foo");
ensure_equals("apppath", slurl.getAppPath().size(), 1);
ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar");
ensure_equals("appquery", slurl.getAppQuery(), "12345");
ensure_equals("grid1", slurl.getGrid(), "FooBar");
slurl = LLSLURL("secondlife://Aditi/app/foo/bar?12345");
ensure_equals("app", slurl.getType(), LLSLURL::APP);
ensure_equals("appcmd", slurl.getAppCmd(), "foo");
ensure_equals("apppath", slurl.getAppPath().size(), 1);
ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar");
ensure_equals("appquery", slurl.getAppQuery(), "12345");
ensure_equals("grid2", slurl.getGrid(), "Aditi");
LLGridManager::getInstance()->setGridChoice("foo.bar.com");
slurl = LLSLURL("secondlife:///secondlife/myregion/1/2/3");
ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("location", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("region" , "myregion", slurl.getRegion());
ensure_equals("grid3", "util.agni.lindenlab.com", slurl.getGrid());
ensure_equals("grid3", slurl.getGrid(), "util.agni.lindenlab.com");
slurl = LLSLURL("secondlife://Aditi/secondlife/myregion/1/2/3");
ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("location", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("region" , "myregion", slurl.getRegion());
ensure_equals("grid4", "util.aditi.lindenlab.com", slurl.getGrid());
ensure_equals("grid4", slurl.getGrid(), "Aditi" );
LLGridManager::getInstance()->setGridChoice("my.grid.com");
slurl = LLSLURL("https://my.grid.com/app/foo/bar?12345");
ensure_equals("app", slurl.getType(), LLSLURL::APP);
ensure_equals("app", slurl.getType(), LLSLURL::APP);
ensure_equals("appcmd", slurl.getAppCmd(), "foo");
ensure_equals("apppath", slurl.getAppPath().size(), 1);
ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar");
ensure_equals("appquery", slurl.getAppQuery(), "12345");
ensure_equals("appquery", slurl.getAppQuery(), "12345");
}
// construction from grid/region/vector combos
template<> template<>
void slurlTestObject::test<2>()
{
LLSLURL slurl = LLSLURL("mygrid.com", "my region");
ensure_equals("grid/region - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("grid/region", slurl.getSLURLString(),
"https://mygrid.com/region/my%20region/128/128/0");
slurl = LLSLURL("mygrid.com", "my region", LLVector3(1,2,3));
ensure_equals("grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals(" grid/region/vector", slurl.getSLURLString(),
"https://mygrid.com/region/my%20region/1/2/3");
llofstream gridfile("grid_test.xml");
gridfile << gSampleGridFile;
gridfile.close();
LLGridManager::getInstance()->setGridChoice("foo.bar.com.bar");
slurl = LLSLURL("my region", LLVector3(1,2,3));
LLGridManager::getInstance()->initialize("grid_test.xml");
LLSLURL slurl = LLSLURL("my.grid.com", "my region");
ensure_equals("grid/region - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals("grid/region", slurl.getSLURLString(),
"https://my.grid.com/region/my%20region/128/128/0");
slurl = LLSLURL("my.grid.com", "my region", LLVector3(1,2,3));
ensure_equals("grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals(" grid/region/vector", slurl.getSLURLString(),
"https://foo.bar.com.bar/region/my%20region/1/2/3");
LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com");
ensure_equals(" grid/region/vector", slurl.getSLURLString(),
"https://my.grid.com/region/my%20region/1/2/3");
LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com");
slurl = LLSLURL("my region", LLVector3(1,2,3));
ensure_equals("default grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals(" default grid/region/vector", slurl.getSLURLString(),
"http://maps.secondlife.com/secondlife/my%20region/1/2/3");
ensure_equals(" default grid/region/vector", slurl.getSLURLString(),
"http://maps.secondlife.com/secondlife/my%20region/1/2/3");
LLGridManager::getInstance()->setGridChoice("MyGrid");
slurl = LLSLURL("my region", LLVector3(1,2,3));
ensure_equals("default grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION);
ensure_equals(" default grid/region/vector", slurl.getSLURLString(),
"https://my.grid.com/region/my%20region/1/2/3");
}
// Accessors
template<> template<>
void slurlTestObject::test<3>()
{
LLGridManager::getInstance()->setGridChoice("my.grid.com");
llofstream gridfile("grid_test.xml");
gridfile << gSampleGridFile;
gridfile.close();
LLGridManager::getInstance()->initialize("grid_test.xml");
LLGridManager::getInstance()->setGridChoice("my.grid.com");
LLSLURL slurl = LLSLURL("https://my.grid.com/region/my%20region/1/2/3");
ensure_equals("login string", slurl.getLoginString(), "uri:my region&amp;1&amp;2&amp;3");
ensure_equals("location string", slurl.getLocationString(), "my region/1/2/3");
ensure_equals("grid", slurl.getGrid(), "my.grid.com");
ensure_equals("region", slurl.getRegion(), "my region");
ensure_equals("position", slurl.getPosition(), LLVector3(1, 2, 3));
}
}