From 32750132db47eb335c56f6c880902cf7195e1825 Mon Sep 17 00:00:00 2001
From: Andrew Productengine <adyukov@productengine.com>
Date: Thu, 9 Dec 2010 19:54:40 +0200
Subject: [PATCH] STORM-34 ADDITIONAL_FIX Implemented storing of multi-user
 favorites and showing them on login screen.

- Changed the way SLURLs are cached a little, because previous one introduced problems with theit order.

- Also allowed saving of favorites to disk even if not all of them received SLURL info - this is done to avoid favorites not saving when there is at least one "dead" landmark among them.

- "Username" field on login screen is now not a lineeditor, but combobox (to enable autocompletion), but without button (Esbee asked for this in ticket for security reasons, and perhaps for visual consistency).

- Elements of this combobox are names of users whose favorites we have saved in file.

- Contents of "Start at:" combobox are changed depending on changes in "Username"- if username is present in favorites file, favorites for this user are added there.

- New callback was added to LLCombobox and used in this fix, because present ones weren't enough to easily track changes in text entry.
---
 indra/llui/llcombobox.cpp                     |  9 +++
 indra/llui/llcombobox.h                       |  5 +-
 indra/newview/llfavoritesbar.cpp              |  3 +-
 indra/newview/llpanellogin.cpp                | 68 ++++++++++++++-----
 indra/newview/llpanellogin.h                  |  2 +-
 indra/newview/llviewerinventory.cpp           | 22 +++---
 indra/newview/llviewerinventory.h             |  1 +
 .../skins/default/xui/en/panel_login.xml      | 21 +++---
 8 files changed, 93 insertions(+), 38 deletions(-)

diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 70014fe4f55..9f32ade2809 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -94,6 +94,7 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
 	mMaxChars(p.max_chars),
 	mPrearrangeCallback(p.prearrange_callback()),
 	mTextEntryCallback(p.text_entry_callback()),
+	mTextChangedCallback(p.text_changed_callback()),
 	mListPosition(p.list_position),
 	mLastSelectedIndex(-1),
 	mLabel(p.label)
@@ -833,6 +834,10 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor)
 			mList->deselectAllItems();
 			mLastSelectedIndex = -1;
 		}
+		if (mTextChangedCallback != NULL)
+		{
+			(mTextChangedCallback)(line_editor, LLSD());
+		}
 		return;
 	}
 
@@ -877,6 +882,10 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor)
 		// RN: presumably text entry
 		updateSelection();
 	}
+	if (mTextChangedCallback != NULL)
+	{
+		(mTextChangedCallback)(line_editor, LLSD());
+	}
 }
 
 void LLComboBox::updateSelection()
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index 5f0e4a68430..74d64269bdf 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -73,7 +73,8 @@ class LLComboBox
 											allow_new_values;
 		Optional<S32>						max_chars;
 		Optional<commit_callback_t> 		prearrange_callback,
-											text_entry_callback;
+											text_entry_callback,
+											text_changed_callback;
 
 		Optional<EPreferredPosition, PreferredPositionValues>	list_position;
 		
@@ -190,6 +191,7 @@ class LLComboBox
 
 	void			setPrearrangeCallback( commit_callback_t cb ) { mPrearrangeCallback = cb; }
 	void			setTextEntryCallback( commit_callback_t cb ) { mTextEntryCallback = cb; }
+	void			setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; }
 
 	void			setButtonVisible(BOOL visible);
 
@@ -220,6 +222,7 @@ class LLComboBox
 	BOOL				mTextEntryTentative;
 	commit_callback_t	mPrearrangeCallback;
 	commit_callback_t	mTextEntryCallback;
+	commit_callback_t	mTextChangedCallback;
 	commit_callback_t	mSelectionCallback;
 	boost::signals2::connection mTopLostSignalConnection;
 	S32                 mLastSelectedIndex;
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index 4f872210650..9f1d3a2a7dc 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -611,10 +611,9 @@ void LLFavoritesBarCtrl::changed(U32 mask)
 		LLIsType is_type(LLAssetType::AT_LANDMARK);
 		gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
 		
-		S32 sortField = 0;
 		for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
 		{
-			(*i)->setSortField(++sortField);
+			(*i)->getSLURL();
 		}
 		updateButtons();
 	}
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 16ea303c779..c50e8c48b57 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -266,26 +266,51 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 	// Show last logged in user favorites in "Start at" combo if corresponding option is enabled.
 	if (gSavedSettings.getBOOL("ShowFavoritesOnLogin"))
 	{
-		addFavoritesToStartLocation();
+	    addUsersWithFavoritesToUsername();
+		getChild<LLComboBox>("username_combo")->setTextChangedCallback(boost::bind(&LLPanelLogin::addFavoritesToStartLocation, this));
 	}
 
 	updateLocationCombo(false);
 
 }
 
-void LLPanelLogin::addFavoritesToStartLocation()
+void LLPanelLogin::addUsersWithFavoritesToUsername()
 {
+	LLComboBox* combo = getChild<LLComboBox>("username_combo");
+	if (!combo) return;
 	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
 	LLSD fav_llsd;
 	llifstream file;
 	file.open(filename);
 	if (!file.is_open()) return;
+	LLSDSerialize::fromXML(fav_llsd, file);
+	for (LLSD::map_const_iterator iter = fav_llsd.beginMap();
+		iter != fav_llsd.endMap(); ++iter)
+	{
+		combo->add(iter->first);
+	}
+}
+
+void LLPanelLogin::addFavoritesToStartLocation()
+{
 	LLComboBox* combo = getChild<LLComboBox>("start_location_combo");
-	combo->addSeparator();
+	if (!combo) return;
+	int num_items = combo->getItemCount();
+	for (int i = num_items - 1; i > 2; i--)
+	{
+		combo->remove(i);
+	}
+	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
+	LLSD fav_llsd;
+	llifstream file;
+	file.open(filename);
+	if (!file.is_open()) return;
 	LLSDSerialize::fromXML(fav_llsd, file);
 	for (LLSD::map_const_iterator iter = fav_llsd.beginMap();
 		iter != fav_llsd.endMap(); ++iter)
 	{
+		if(iter->first != getChild<LLComboBox>("username_combo")->getSimple()) continue;
+		combo->addSeparator();
 		LLSD user_llsd = iter->second;
 		for (LLSD::array_const_iterator iter1 = user_llsd.beginArray();
 			iter1 != user_llsd.endArray(); ++iter1)
@@ -297,7 +322,7 @@ void LLPanelLogin::addFavoritesToStartLocation()
 				combo->add(label, value);
 			}
 		}
-
+		break;
 	}
 }
 
@@ -461,13 +486,14 @@ void LLPanelLogin::giveFocus()
 	if( sInstance )
 	{
 		// Grab focus and move cursor to first blank input field
-		std::string username = sInstance->getChild<LLUICtrl>("username_edit")->getValue().asString();
+		std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
 		std::string pass = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
 
 		BOOL have_username = !username.empty();
 		BOOL have_pass = !pass.empty();
 
 		LLLineEditor* edit = NULL;
+		LLComboBox* combo = NULL;
 		if (have_username && !have_pass)
 		{
 			// User saved his name but not his password.  Move
@@ -477,7 +503,7 @@ void LLPanelLogin::giveFocus()
 		else
 		{
 			// User doesn't have a name, so start there.
-			edit = sInstance->getChild<LLLineEditor>("username_edit");
+			combo = sInstance->getChild<LLComboBox>("username_combo");
 		}
 
 		if (edit)
@@ -485,6 +511,10 @@ void LLPanelLogin::giveFocus()
 			edit->setFocus(TRUE);
 			edit->selectAll();
 		}
+		else if (combo)
+		{
+			combo->setFocus(TRUE);
+		}
 	}
 #endif
 }
@@ -498,8 +528,8 @@ void LLPanelLogin::showLoginWidgets()
 	// *TODO: Append all the usual login parameters, like first_login=Y etc.
 	std::string splash_screen_url = sInstance->getString("real_url");
 	web_browser->navigateTo( splash_screen_url, "text/html" );
-	LLUICtrl* username_edit = sInstance->getChild<LLUICtrl>("username_edit");
-	username_edit->setFocus(TRUE);
+	LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo");
+	username_combo->setFocus(TRUE);
 }
 
 // static
@@ -543,15 +573,19 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential,
 		    login_id += " ";
 		    login_id += lastname;
 	    }
-		sInstance->getChild<LLUICtrl>("username_edit")->setValue(login_id);	
+		sInstance->getChild<LLComboBox>("username_combo")->setLabel(login_id);	
 	}
 	else if((std::string)identifier["type"] == "account")
 	{
-		sInstance->getChild<LLUICtrl>("username_edit")->setValue((std::string)identifier["account_name"]);		
+		sInstance->getChild<LLComboBox>("username_combo")->setLabel((std::string)identifier["account_name"]);		
 	}
 	else
 	{
-	  sInstance->getChild<LLUICtrl>("username_edit")->setValue(std::string());	
+	  sInstance->getChild<LLComboBox>("username_combo")->setLabel(std::string());	
+	}
+	if (gSavedSettings.getBOOL("ShowFavoritesOnLogin"))
+	{
+		sInstance->addFavoritesToStartLocation();
 	}
 	// if the password exists in the credential, set the password field with
 	// a filler to get some stars
@@ -600,7 +634,7 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,
 		authenticator = credential->getAuthenticator();
 	}
 
-	std::string username = sInstance->getChild<LLUICtrl>("username_edit")->getValue().asString();
+	std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
 	LLStringUtil::trim(username);
 	std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
 
@@ -692,15 +726,15 @@ BOOL LLPanelLogin::areCredentialFieldsDirty()
 	}
 	else
 	{
-		std::string username = sInstance->getChild<LLUICtrl>("username_edit")->getValue().asString();
+		std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
 		LLStringUtil::trim(username);
 		std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
-		LLLineEditor* ctrl = sInstance->getChild<LLLineEditor>("username_edit");
-		if(ctrl && ctrl->isDirty())
+		LLComboBox* combo = sInstance->getChild<LLComboBox>("username_combo");
+		if(combo && combo->isDirty())
 		{
 			return true;
 		}
-		ctrl = sInstance->getChild<LLLineEditor>("password_edit");
+		LLLineEditor* ctrl = sInstance->getChild<LLLineEditor>("password_edit");
 		if(ctrl && ctrl->isDirty()) 
 		{
 			return true;
@@ -1007,7 +1041,7 @@ void LLPanelLogin::onClickConnect(void *)
 			return;
 		}
 		updateStartSLURL();
-		std::string username = sInstance->getChild<LLUICtrl>("username_edit")->getValue().asString();
+		std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
 
 		
 		if(username.empty())
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index 8a8888a0532..1ef6539ecc5 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -85,8 +85,8 @@ class LLPanelLogin:
 private:
 	friend class LLPanelLoginListener;
 	void reshapeBrowser();
-	// adds favorites of last logged in user from file to "Start at" combobox.
 	void addFavoritesToStartLocation();
+	void addUsersWithFavoritesToUsername();
 	static void onClickConnect(void*);
 	static void onClickNewAccount(void*);
 //	static bool newAccountAlertCallback(const LLSD& notification, const LLSD& response);
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 941e81d36fd..4fa79b18552 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -1562,6 +1562,13 @@ void LLFavoritesOrderStorage::saveFavoritesSLURLs()
 	if (user_dir.empty()) return;
 
 	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
+	llifstream in_file;
+	in_file.open(filename);
+	LLSD fav_llsd;
+	if (in_file.is_open())
+	{
+		LLSDSerialize::fromXML(fav_llsd, in_file);
+	}
 
 	const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
 	LLInventoryModel::cat_array_t cats;
@@ -1579,18 +1586,10 @@ void LLFavoritesOrderStorage::saveFavoritesSLURLs()
 		if (slurl_iter != mSLURLs.end())
 		{
 			value["slurl"] = slurl_iter->second;
+			user_llsd[(*it)->getSortField()] = value;
 		}
-		else
-		{
-			llwarns << "Fetching SLURLs for \"Favorites\" is not complete!" << llendl;
-			return;
-		}
-
-		user_llsd[(*it)->getSortField()] = value;
 	}
 
-	LLSD fav_llsd;
-	// this level in LLSD is not needed now and is just a stub, but will be needed later when implementing save of multiple users favorites in one file.
 	LLAvatarName av_name;
 	LLAvatarNameCache::get( gAgentID, &av_name );
 	fav_llsd[av_name.getLegacyName()] = user_llsd;
@@ -1680,6 +1679,11 @@ S32 LLViewerInventoryItem::getSortField() const
 void LLViewerInventoryItem::setSortField(S32 sortField)
 {
 	LLFavoritesOrderStorage::instance().setSortIndex(mUUID, sortField);
+	getSLURL();
+}
+
+void LLViewerInventoryItem::getSLURL()
+{
 	LLFavoritesOrderStorage::instance().getSLURL(mAssetUUID);
 }
 
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 1af06a1be82..41542a4e0ff 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -62,6 +62,7 @@ class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::tr
 	virtual const std::string& getName() const;
 	virtual S32 getSortField() const;
 	virtual void setSortField(S32 sortField);
+	virtual void getSLURL(); //Caches SLURL for landmark. //*TODO: Find a better way to do it and remove this method from here.
 	virtual const LLPermissions& getPermissions() const;
 	virtual const bool getIsFullPerm() const; // 'fullperm' in the popular sense: modify-ok & copy-ok & transfer-ok, no special god rules applied
 	virtual const LLUUID& getCreatorUUID() const;
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index b181ca3bbad..5ad8d1fd403 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -64,23 +64,28 @@ left="20"
 width="150">
 Username:
 </text>
-<line_editor
+<combo_box
+allow_text_entry="true"
 follows="left|bottom"
 height="22"
-label="bobsmith12 or Steller Sunshine"
 left_delta="0"
-max_length_bytes="63"
-name="username_edit"
-prevalidate_callback="ascii" 
+max_chars="128"
+prevalidate_callback="ascii"
 select_on_focus="true"
 tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine"
 top_pad="0"
-width="150" />
+name="username_combo"
+width="178">
+  <combo_box.combo_button
+   visible ="false"/>
+  <combo_box.drop_down_button
+   visible ="false"/>
+</combo_box>
 <text
 follows="left|bottom"
 font="SansSerifSmall"
 height="15"
-left_pad="8"
+left_pad="-19"
 name="password_text"
 top="20"
     width="150">
@@ -127,7 +132,7 @@ top="20"
  </text>
 <combo_box
 allow_text_entry="true"
-control_name="LoginLocation"
+control_name="NextLoginLocation"
   follows="left|bottom"
   height="23"
 max_chars="128"
-- 
GitLab