diff options
29 files changed, 464 insertions, 44 deletions
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 843f72d8e4..45f9de8e8d 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1440,7 +1440,7 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char)  BOOL LLLineEditor::canDoDelete() const  { -	return ( !mReadOnly && (!mPassDelete || (hasSelection() || (getCursor() < mText.length()))) ); +	return ( !mReadOnly && mText.length() > 0 && (!mPassDelete || (hasSelection() || (getCursor() < mText.length()))) );  }  void LLLineEditor::doDelete() diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 736de651da..3375c13c94 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -765,3 +765,35 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC  {  	return getUrl(url);  } + +// +// LLUrlEntryIcon describes an icon with <icon>...</icon> tags +// +LLUrlEntryIcon::LLUrlEntryIcon() +{ +	mPattern = boost::regex("<icon\\s*>\\s*([^<]*)?\\s*</icon\\s*>", +							boost::regex::perl|boost::regex::icase); +	mDisabledLink = true; +} + +std::string LLUrlEntryIcon::getUrl(const std::string &url) const +{ +	return LLStringUtil::null; +} + +std::string LLUrlEntryIcon::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ +	return LLStringUtil::null; +} + +std::string LLUrlEntryIcon::getIcon(const std::string &url) +{ +	// Grep icon info between <icon>...</icon> tags +	// matches[1] contains the icon name/path +	boost::match_results<std::string::const_iterator> matches; +	mIcon = (boost::regex_match(url, matches, mPattern) && matches[1].matched) +		? matches[1] +		: LLStringUtil::null; +	LLStringUtil::trim(mIcon); +	return mIcon; +} diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 29575d752c..71f030677a 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -77,7 +77,7 @@ public:  	virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) { return url; }  	/// Return an icon that can be displayed next to Urls of this type -	std::string getIcon() const { return mIcon; } +	virtual std::string getIcon(const std::string &url) { return mIcon; }  	/// Return the color to render the displayed text  	LLUIColor getColor() const { return mColor; } @@ -296,4 +296,17 @@ public:  	/*virtual*/ std::string getUrl(const std::string &string) const;  }; +/// +/// LLUrlEntryIcon describes an icon with <icon>...</icon> tags +/// +class LLUrlEntryIcon : public LLUrlEntryBase +{ +public: +	LLUrlEntryIcon(); +	/*virtual*/ std::string getUrl(const std::string &string) const; +	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); +	/*virtual*/ std::string getIcon(const std::string &url); +}; + +  #endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 0a70aa586a..4341286eb4 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -45,6 +45,7 @@ LLUrlRegistry::LLUrlRegistry()  {  	// Urls are matched in the order that they were registered  	registerUrl(new LLUrlEntryNoLink()); +	registerUrl(new LLUrlEntryIcon());  	registerUrl(new LLUrlEntrySLURL());  	registerUrl(new LLUrlEntryHTTP());  	registerUrl(new LLUrlEntryHTTPLabel()); @@ -135,7 +136,8 @@ static bool stringHasUrl(const std::string &text)  			text.find(".net") != std::string::npos ||  			text.find(".edu") != std::string::npos ||  			text.find(".org") != std::string::npos || -			text.find("<nolink>") != std::string::npos); +			text.find("<nolink>") != std::string::npos || +			text.find("<icon") != std::string::npos);  }  bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb) @@ -177,7 +179,7 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL  						match_entry->getUrl(url),  						match_entry->getLabel(url, cb),  						match_entry->getTooltip(url), -						match_entry->getIcon(), +						match_entry->getIcon(url),  						match_entry->getColor(),  						match_entry->getMenuName(),  						match_entry->getLocation(url), diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 4ca23e14a1..a6dbe00759 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -10994,5 +10994,16 @@        <integer>2048</integer>      </map>      <!-- End of back compatibility settings --> +    <key>teleport_offer_invitation_max_length</key> +    <map> +      <key>Comment</key> +      <string>Maximum length of teleport offer invitation line editor. 254 - max_location_url_length(76) = 178</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>S32</string> +      <key>Value</key> +      <integer>178</integer> +    </map>  </map>  </llsd> diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 466f2d499d..8a880e5ace 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -2031,6 +2031,39 @@ void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake)  	}  } +bool LLAgentWearables::moveWearable(const LLViewerInventoryItem* item, bool closer_to_body) +{ +	if (!item) return false; +	if (!item->isWearableType()) return false; + +	wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(item->getWearableType()); +	if (wearable_iter == mWearableDatas.end()) return false; + +	wearableentry_vec_t& wearable_vec = wearable_iter->second; +	if (wearable_vec.empty()) return false; + +	const LLUUID& asset_id = item->getAssetUUID(); + +	//nowhere to move if the wearable is already on any boundary (closest to the body/furthest from the body) +	if (closer_to_body && asset_id == wearable_vec.front()->getAssetID()) return false; +	if (!closer_to_body && asset_id == wearable_vec.back()->getAssetID()) return false; + +	for (U32 i = 0; i < wearable_vec.size(); ++i) +	{ +		LLWearable* wearable = wearable_vec[i]; +		if (!wearable) continue; +		if (wearable->getAssetID() != asset_id) continue; +		 +		//swapping wearables +		U32 swap_i = closer_to_body ? i-1 : i+1; +		wearable_vec[i] = wearable_vec[swap_i]; +		wearable_vec[swap_i] = wearable; +		return true; +	} + +	return false; +} +  void LLAgentWearables::updateServer()  {  	sendAgentWearablesUpdate(); diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 585fd3f8b3..d3b18f68f1 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -82,6 +82,8 @@ public:  	void			animateAllWearableParams(F32 delta, BOOL upload_bake); +	bool			moveWearable(const LLViewerInventoryItem* item, bool closer_to_body); +  	//--------------------------------------------------------------------  	// Accessors  	//-------------------------------------------------------------------- diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 9e02886e4f..6aefecc787 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -122,6 +122,38 @@ private:  	bool mAppend;  }; + +//Inventory callback updating "dirty" state when destroyed +class LLUpdateDirtyState: public LLInventoryCallback +{ +public: +	LLUpdateDirtyState() {} +	virtual ~LLUpdateDirtyState(){ LLAppearanceMgr::getInstance()->updateIsDirty(); } +	virtual void fire(const LLUUID&) {} +}; + + +//Inventory collect functor collecting wearables of a specific wearable type +class LLFindClothesOfType : public LLInventoryCollectFunctor +{ +public: +	LLFindClothesOfType(EWearableType type) : mWearableType(type) {} +	virtual ~LLFindClothesOfType() {} +	virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) +	{ +		if (!item) return false; +		if (item->getType() != LLAssetType::AT_CLOTHING) return false; +		 +		LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); +		if (!vitem || vitem->getWearableType() != mWearableType) return false; + +		return true; +	} + +	const EWearableType mWearableType; +}; + +  LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy():  	mFireCount(0)  { @@ -1593,8 +1625,11 @@ bool LLAppearanceMgr::updateBaseOutfit()  	// in a Base Outfit we do not remove items, only links  	purgeCategory(base_outfit_id, false); + +	LLPointer<LLInventoryCallback> dirty_state_updater = new LLUpdateDirtyState(); +  	//COF contains only links so we copy to the Base Outfit only links -	shallowCopyCategoryContents(getCOF(), base_outfit_id, NULL); +	shallowCopyCategoryContents(getCOF(), base_outfit_id, dirty_state_updater);  	return true;  } @@ -1802,6 +1837,63 @@ void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)  	}  } + +bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body) +{ +	if (!item || !item->isWearableType()) return false; +	if (item->getType() != LLAssetType::AT_CLOTHING) return false; +	if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false; + +	LLInventoryModel::cat_array_t cats; +	LLInventoryModel::item_array_t items; +	LLFindClothesOfType filter_wearables_of_type(item->getWearableType()); +	gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); +	if (items.empty()) return false; + +	//*TODO all items are not guarantied to have valid descriptions (check?) +	std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType())); + +	if (closer_to_body && items.front() == item) return false; +	if (!closer_to_body && items.back() == item) return false; +	 +	LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item); +	if (items.end() == it) return false; + + +	//swapping descriptions +	closer_to_body ? --it : ++it; +	LLViewerInventoryItem* swap_item = *it; +	if (!swap_item) return false; +	std::string tmp = swap_item->LLInventoryItem::getDescription(); +	swap_item->setDescription(item->LLInventoryItem::getDescription()); +	item->setDescription(tmp); + + +	//items need to be updated on a dataserver +	item->setComplete(TRUE); +	item->updateServer(FALSE); +	gInventory.updateItem(item); + +	swap_item->setComplete(TRUE); +	swap_item->updateServer(FALSE); +	gInventory.updateItem(swap_item); + +	//to cause appearance of the agent to be updated +	bool result = false; +	if (result = gAgentWearables.moveWearable(item, closer_to_body)) +	{ +		gAgentAvatarp->wearableUpdated(item->getWearableType(), TRUE); +	} + +	setOutfitDirty(true); + +	//*TODO do we need to notify observers here in such a way? +	gInventory.notifyObservers(); + +	return result; +} + +  //#define DUMP_CAT_VERBOSE  void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg) diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index efb5274c5b..a308a3efa9 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -141,6 +141,8 @@ public:  	LLUUID makeNewOutfitLinks(const std::string& new_folder_name); +	bool moveWearable(LLViewerInventoryItem* item, bool closer_to_body); +  protected:  	LLAppearanceMgr();  	~LLAppearanceMgr(); diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 909878207c..f03026715d 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -1767,6 +1767,8 @@ void LLOutgoingCallDialog::show(const LLSD& key)  			getChild<LLTextBox>("leaving")->setVisible(true);  		}  		break; +	// STATE_READY is here to show appropriate text for ad-hoc and group calls when floater is shown(EXT-6893) +	case LLVoiceChannel::STATE_READY :  	case LLVoiceChannel::STATE_RINGING :  		if(show_oldchannel)  		{ diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index e11df06d86..0341f2c693 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -375,7 +375,6 @@ void LLNavigationBar::draw()  	if(mPurgeTPHistoryItems)  	{  		LLTeleportHistory::getInstance()->purgeItems(); -		onTeleportHistoryChanged();  		mPurgeTPHistoryItems = false;  	} diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index ad42d80467..cce4f94028 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -168,26 +168,21 @@ void LLOutfitsList::refreshList(const LLUUID& category_id)  		std::string name = cat->getName(); -		// *TODO: create accordion tabs and lists from XML. -		LLAccordionCtrlTab::Params params; -		params.name(name); -		params.title(name); -		params.rect(LLRect(0, 0, 315, 20)); -		params.display_children(false); -		LLAccordionCtrlTab* tab  = LLUICtrlFactory::create<LLAccordionCtrlTab>(params); +		static LLXMLNodePtr accordionXmlNode = getAccordionTabXMLNode(); -		mAccordion->addCollapsibleCtrl(tab); - -		LLFlatListView::Params list_params; -		LLWearableItemsList* list  = LLUICtrlFactory::create<LLWearableItemsList>(list_params); +		accordionXmlNode->setAttributeString("name", name); +		accordionXmlNode->setAttributeString("title", name); +		LLAccordionCtrlTab* tab = LLUICtrlFactory::defaultBuilder<LLAccordionCtrlTab>(accordionXmlNode, NULL, NULL); -		tab->addChild(list, 0); -		tab->setDisplayChildren(false); +		// *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated. +		tab->setDisplayChildren(false);  +		mAccordion->addCollapsibleCtrl(tab);  		// Map the new tab with outfit category UUID.  		mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab));  		// Start observing the new outfit category. +		LLWearableItemsList* list  = tab->getChild<LLWearableItemsList>("wearable_items_list");  		mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id));  		// Fetch the new outfit contents. @@ -262,4 +257,21 @@ void LLOutfitsList::setFilterSubString(const std::string& string)  	mFilterSubString = string;  } + +////////////////////////////////////////////////////////////////////////// +// Private methods +////////////////////////////////////////////////////////////////////////// +LLXMLNodePtr LLOutfitsList::getAccordionTabXMLNode() +{ +	LLXMLNodePtr xmlNode = NULL; +	bool success = LLUICtrlFactory::getLayeredXMLNode("outfit_accordion_tab.xml", xmlNode); +	if (!success) +	{ +		llwarns << "Failed to read xml of Outfit's Accordion Tab from outfit_accordion_tab.xml" << llendl; +		return NULL; +	} + +	return xmlNode; +} +  // EOF diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index 892e0a862a..f1756ce873 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -59,6 +59,14 @@ public:  	void setFilterSubString(const std::string& string);  private: +	/** +	 * Reads xml with accordion tab and Flat list from xml file. +	 * +	 * @return LLPointer to XMLNode with accordion tab and flat list. +	 */ +	LLXMLNodePtr getAccordionTabXMLNode(); + +  	LLInventoryCategoriesObserver* 	mCategoriesObserver;  	LLAccordionCtrl*				mAccordion; diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 8da19d1574..f7d76bc069 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -656,6 +656,9 @@ void LLPanelGroupNotices::setGroupID(const LLUUID& id)  	if(mViewMessage)   		mViewMessage->clear(); + +	if(mViewInventoryName) +		mViewInventoryName->clear();  	activate();  } diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index e139cb31d6..ae181e2819 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -73,6 +73,9 @@ const U64 WEARABLE_MASK = (1LL << LLInventoryType::IT_WEARABLE);  const U64 ATTACHMENT_MASK = (1LL << LLInventoryType::IT_ATTACHMENT) | (1LL << LLInventoryType::IT_OBJECT);  const U64 ALL_ITEMS_MASK = WEARABLE_MASK | ATTACHMENT_MASK; +static const std::string SAVE_BTN("save_btn"); +static const std::string REVERT_BTN("revert_btn"); +  class LLInventoryLookObserver : public LLInventoryObserver  {  public: @@ -221,10 +224,9 @@ BOOL LLPanelOutfitEdit::postBuild()  	mEditWearableBtn->setVisible(FALSE);  	mEditWearableBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this)); -	childSetAction("revert_btn", boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance())); +	childSetAction(REVERT_BTN, boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance())); -	childSetAction("save_btn", boost::bind(&LLPanelOutfitEdit::saveOutfit, this, false)); -	childSetAction("save_as_btn", boost::bind(&LLPanelOutfitEdit::saveOutfit, this, true)); +	childSetAction(SAVE_BTN, boost::bind(&LLPanelOutfitEdit::saveOutfit, this, false));  	childSetAction("save_flyout_btn", boost::bind(&LLPanelOutfitEdit::showSaveMenu, this));  	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar save_registar; @@ -234,10 +236,22 @@ BOOL LLPanelOutfitEdit::postBuild()  	mWearableListManager = new LLFilteredWearableListManager(  		getChild<LLInventoryItemsList>("filtered_wearables_list"), ALL_ITEMS_MASK); +		 +	childSetAction("move_closer_btn", boost::bind(&LLPanelOutfitEdit::moveWearable, this, true)); +	childSetAction("move_further_btn", boost::bind(&LLPanelOutfitEdit::moveWearable, this, false));  	return TRUE;  } +void LLPanelOutfitEdit::moveWearable(bool closer_to_body) +{ +	LLViewerInventoryItem* wearable_to_move = gInventory.getItem(mLookContents->getSelectionInterface()->getCurrentID()); +	LLAppearanceMgr::getInstance()->moveWearable(wearable_to_move, closer_to_body); + +	//*TODO why not to listen to inventory? +	updateLookInfo(); +} +  void LLPanelOutfitEdit::showAddWearablesPanel()  {  	childSetVisible("add_wearables_panel", childGetValue("add_btn")); @@ -267,6 +281,8 @@ void LLPanelOutfitEdit::saveOutfit(bool as_new)  	{  		panel_outfits_inventory->onSave();  	} + +	//*TODO how to get to know when base outfit is updated or new outfit is created?  }  void LLPanelOutfitEdit::showSaveMenu() @@ -542,10 +558,12 @@ void LLPanelOutfitEdit::lookFetched(void)  		columns[0]["value"] = item->getName();  		columns[1]["column"] = "look_item_sort";  		columns[1]["type"] = "text"; // TODO: multi-wearable sort "type" should go here. -		columns[1]["value"] = "BAR"; // TODO: Multi-wearable sort index should go here +		columns[1]["value"] = item->LLInventoryItem::getDescription();  		mLookContents->addElement(row);  	} + +	updateVerbs();  }  void LLPanelOutfitEdit::updateLookInfo() @@ -589,4 +607,15 @@ void LLPanelOutfitEdit::displayCurrentOutfit()  	updateLookInfo();  } +//private +void LLPanelOutfitEdit::updateVerbs() +{ +	bool outfit_is_dirty = LLAppearanceMgr::getInstance()->isOutfitDirty(); +	 +	childSetEnabled(SAVE_BTN, outfit_is_dirty); +	childSetEnabled(REVERT_BTN, outfit_is_dirty); + +	mSaveMenu->setItemEnabled("save_outfit", outfit_is_dirty); +} +  // EOF diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index 308ee23115..b6f121d484 100644 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -87,6 +87,8 @@ public:  		// Sends a request for data about the given parcel, which will  		// only update the location if there is none already available. +	void moveWearable(bool closer_to_body); +  	void showAddWearablesPanel();  	void showWearablesFilter();  	void showFilteredWearablesPanel(); @@ -110,6 +112,8 @@ public:  private: +	void updateVerbs(); +  	//*TODO got rid of mCurrentOutfitID  	LLUUID				mCurrentOutfitID; diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp index dcc85392f7..15684337f4 100644 --- a/indra/newview/llteleporthistory.cpp +++ b/indra/newview/llteleporthistory.cpp @@ -136,6 +136,7 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)  		if (mCurrentItem < 0 || mCurrentItem >= (int) mItems.size()) // sanity check  		{  			llwarns << "Invalid current item. (this should not happen)" << llendl; +			llassert(!"Invalid current teleport histiry item");  			return;  		}  		LLVector3 new_pos_local = gAgent.getPosAgentFromGlobal(new_pos); @@ -166,6 +167,17 @@ void LLTeleportHistory::onHistoryChanged()  void LLTeleportHistory::purgeItems()  { +	if (mItems.size() == 0) // no entries yet (we're called before login) +	{ +		// If we don't return here the history will get into inconsistent state, hence: +		// 1) updateCurrentLocation() will malfunction, +		//    so further teleports will not properly update the history; +		// 2) mHistoryChangedSignal subscribers will be notified +		//    of such an invalid change. (EXT-6798) +		// Both should not happen. +		return; +	} +  	if (mItems.size() > 0)  	{  		mItems.erase(mItems.begin(), mItems.end()-1); diff --git a/indra/newview/llteleporthistorystorage.cpp b/indra/newview/llteleporthistorystorage.cpp index c635f91423..430d62e15e 100644 --- a/indra/newview/llteleporthistorystorage.cpp +++ b/indra/newview/llteleporthistorystorage.cpp @@ -89,6 +89,13 @@ void LLTeleportHistoryStorage::onTeleportHistoryChange()  	if (!th)  		return; +	// Hacky sanity check. (EXT-6798) +	if (th->getItems().size() == 0) +	{ +		llassert(!"Inconsistent teleport history state"); +		return; +	} +  	const LLTeleportHistoryItem &item = th->getItems()[th->getCurrentItemIndex()];  	addItem(item.mTitle, item.mGlobalPos); diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp index 986ccdf19b..2b529a4e50 100644 --- a/indra/newview/lltoastalertpanel.cpp +++ b/indra/newview/lltoastalertpanel.cpp @@ -50,6 +50,7 @@  #include "llnotifications.h"  #include "llfunctorregistry.h"  #include "llrootview.h" +#include "llviewercontrol.h" // for gSavedSettings  const S32 MAX_ALLOWED_MSG_WIDTH = 400;  const F32 DEFAULT_BUTTON_DELAY = 0.5f; @@ -279,7 +280,18 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal  			mLineEditor->reshape(leditor_rect.getWidth(), leditor_rect.getHeight());  			mLineEditor->setRect(leditor_rect);  			mLineEditor->setText(edit_text_contents); -			mLineEditor->setMaxTextLength(STD_STRING_STR_LEN - 1); + +			// decrease limit of line editor of teleport offer dialog to avoid truncation of +			// location URL in invitation message, see EXT-6891 +			if ("OfferTeleport" == mNotification->getName()) +			{ +				mLineEditor->setMaxTextLength(gSavedSettings.getS32( +						"teleport_offer_invitation_max_length")); +			} +			else +			{ +				mLineEditor->setMaxTextLength(STD_STRING_STR_LEN - 1); +			}  			LLToastPanel::addChild(mLineEditor); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index f434d15843..a23e42ea9e 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -67,6 +67,40 @@  #include "llviewermessage.h"  ///---------------------------------------------------------------------------- +/// Helper class to store special inventory item names  +///---------------------------------------------------------------------------- +class LLLocalizedInventoryItemsDictionary : public LLSingleton<LLLocalizedInventoryItemsDictionary> +{ +public: +	std::map<std::string, std::string> mInventoryItemsDict; + +	LLLocalizedInventoryItemsDictionary() +	{ +		mInventoryItemsDict["New Shape"]		= LLTrans::getString("New Shape"); +		mInventoryItemsDict["New Skin"]			= LLTrans::getString("New Skin"); +		mInventoryItemsDict["New Hair"]			= LLTrans::getString("New Hair"); +		mInventoryItemsDict["New Eyes"]			= LLTrans::getString("New Eyes"); +		mInventoryItemsDict["New Shirt"]		= LLTrans::getString("New Shirt"); +		mInventoryItemsDict["New Pants"]		= LLTrans::getString("New Pants"); +		mInventoryItemsDict["New Shoes"]		= LLTrans::getString("New Shoes"); +		mInventoryItemsDict["New Socks"]		= LLTrans::getString("New Socks"); +		mInventoryItemsDict["New Jacket"]		= LLTrans::getString("New Jacket"); +		mInventoryItemsDict["New Gloves"]		= LLTrans::getString("New Gloves"); +		mInventoryItemsDict["New Undershirt"]	= LLTrans::getString("New Undershirt"); +		mInventoryItemsDict["New Undershirt"]	= LLTrans::getString("New Undershirt"); +		mInventoryItemsDict["New Skirt"]		= LLTrans::getString("New Skirt"); +		mInventoryItemsDict["New Alpha"]		= LLTrans::getString("New Alpha"); +		mInventoryItemsDict["New Tattoo"]		= LLTrans::getString("New Tattoo"); +		mInventoryItemsDict["Invalid Wearable"] = LLTrans::getString("Invalid Wearable"); + +		mInventoryItemsDict["New Script"]		= LLTrans::getString("New Script"); +		mInventoryItemsDict["New Folder"]		= LLTrans::getString("New Folder"); +		mInventoryItemsDict["Contents"]			= LLTrans::getString("Contents"); +	} +}; + + +///----------------------------------------------------------------------------  /// Local function declarations, constants, enums, and typedefs  ///---------------------------------------------------------------------------- @@ -316,6 +350,18 @@ BOOL LLViewerInventoryItem::unpackMessage(LLSD item)  BOOL LLViewerInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)  {  	BOOL rv = LLInventoryItem::unpackMessage(msg, block, block_num); + +	std::string localized_str; + +	std::map<std::string, std::string>::const_iterator dictionary_iter; + +	dictionary_iter = LLLocalizedInventoryItemsDictionary::getInstance()->mInventoryItemsDict.find(mName); + +	if(dictionary_iter != LLLocalizedInventoryItemsDictionary::getInstance()->mInventoryItemsDict.end()) +	{ +		mName = dictionary_iter->second; +	} +  	mIsComplete = TRUE;  	return rv;  } @@ -867,6 +913,25 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,  						   U32 next_owner_perm,  						   LLPointer<LLInventoryCallback> cb)  { +	//check if name is equal to one of special inventory items names +	//EXT-5839 +	std::string server_name = name; + +	{ +		std::map<std::string, std::string>::const_iterator dictionary_iter; + +		for (dictionary_iter = LLLocalizedInventoryItemsDictionary::getInstance()->mInventoryItemsDict.begin(); +			 dictionary_iter != LLLocalizedInventoryItemsDictionary::getInstance()->mInventoryItemsDict.end(); +			 dictionary_iter++) +		{ +			const std::string& localized_name = dictionary_iter->second; +			if(localized_name == name) +			{ +				server_name = dictionary_iter->first; +			} +		} +	} +  	LLMessageSystem* msg = gMessageSystem;  	msg->newMessageFast(_PREHASH_CreateInventoryItem);  	msg->nextBlock(_PREHASH_AgentData); @@ -880,7 +945,7 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,  	msg->addS8Fast(_PREHASH_Type, (S8)asset_type);  	msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);  	msg->addU8Fast(_PREHASH_WearableType, (U8)wtype); -	msg->addStringFast(_PREHASH_Name, name); +	msg->addStringFast(_PREHASH_Name, server_name);  	msg->addStringFast(_PREHASH_Description, desc);  	gAgent.sendReliableMessage(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index ba0c8d464d..e12457550a 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1933,7 +1933,7 @@ protected:  	}  }; -static void parse_lure_bucket(const std::string& bucket, +static bool parse_lure_bucket(const std::string& bucket,  							  U64& region_handle,  							  LLVector3& pos,  							  LLVector3& look_at, @@ -1945,15 +1945,25 @@ static void parse_lure_bucket(const std::string& bucket,  	tokenizer tokens(bucket, sep);  	tokenizer::iterator iter = tokens.begin(); -	S32 gx = boost::lexical_cast<S32>((*(iter)).c_str()); -	S32 gy = boost::lexical_cast<S32>((*(++iter)).c_str()); -	S32 rx = boost::lexical_cast<S32>((*(++iter)).c_str()); -	S32 ry = boost::lexical_cast<S32>((*(++iter)).c_str()); -	S32 rz = boost::lexical_cast<S32>((*(++iter)).c_str()); -	S32 lx = boost::lexical_cast<S32>((*(++iter)).c_str()); -	S32 ly = boost::lexical_cast<S32>((*(++iter)).c_str()); -	S32 lz = boost::lexical_cast<S32>((*(++iter)).c_str()); - +	S32 gx,gy,rx,ry,rz,lx,ly,lz; +	try +	{ +		gx = boost::lexical_cast<S32>((*(iter)).c_str()); +		gy = boost::lexical_cast<S32>((*(++iter)).c_str()); +		rx = boost::lexical_cast<S32>((*(++iter)).c_str()); +		ry = boost::lexical_cast<S32>((*(++iter)).c_str()); +		rz = boost::lexical_cast<S32>((*(++iter)).c_str()); +		lx = boost::lexical_cast<S32>((*(++iter)).c_str()); +		ly = boost::lexical_cast<S32>((*(++iter)).c_str()); +		lz = boost::lexical_cast<S32>((*(++iter)).c_str()); +	} +	catch( boost::bad_lexical_cast& ) +	{ +		LL_WARNS("parse_lure_bucket") +			<< "Couldn't parse lure bucket." +			<< LL_ENDL; +		return false; +	}  	// Grab region access  	region_access = SIM_ACCESS_MIN;  	if (++iter != tokens.end()) @@ -1978,6 +1988,7 @@ static void parse_lure_bucket(const std::string& bucket,  	look_at.setVec((F32)lx, (F32)ly, (F32)lz);  	region_handle = to_region_handle(gx, gy); +	return true;  }  void process_improved_im(LLMessageSystem *msg, void **user_data) @@ -2615,15 +2626,21 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  				U64 region_handle;  				U8 region_access;  				std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); -				parse_lure_bucket(region_info, region_handle, pos, look_at, region_access); +				std::string region_access_str = LLStringUtil::null; +				std::string region_access_icn = LLStringUtil::null; -				std::string region_access_str = LLViewerRegion::accessToString(region_access); +				if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) +				{ +					region_access_str = LLViewerRegion::accessToString(region_access); +					region_access_icn = LLViewerRegion::getAccessIcon(region_access); +				}  				LLSD args;  				// *TODO: Translate -> [FIRST] [LAST] (maybe)  				args["NAME_SLURL"] = LLSLURL::buildCommand("agent", from_id, "about");  				args["MESSAGE"] = message; -				args["MATURITY"] = region_access_str; +				args["MATURITY_STR"] = region_access_str; +				args["MATURITY_ICON"] = region_access_icn;  				LLSD payload;  				payload["from_id"] = from_id;  				payload["lure_id"] = session_id; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 07d4ac664f..c48668df9a 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -627,6 +627,26 @@ std::string LLViewerRegion::accessToString(U8 sim_access)  }  // static +std::string LLViewerRegion::getAccessIcon(U8 sim_access) +{ +	switch(sim_access) +	{ +	case SIM_ACCESS_MATURE: +		return "Parcel_M_Dark"; + +	case SIM_ACCESS_ADULT: +		return "Parcel_R_Light"; + +	case SIM_ACCESS_PG: +		return "Parcel_PG_Light"; + +	case SIM_ACCESS_MIN: +	default: +		return ""; +	} +} + +// static  std::string LLViewerRegion::accessToShortString(U8 sim_access)  {  	switch(sim_access)		/* Flawfinder: ignore */ diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 49d0900f2a..5c4d5a61fd 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -203,6 +203,9 @@ public:  	// Returns "M", "PG", "A" etc.  	static std::string accessToShortString(U8 sim_access); + +	// Return access icon name +	static std::string getAccessIcon(U8 sim_access);  	// helper function which just makes sure all interested parties  	// can process the message. diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index b2de31218b..20266706da 100644 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -235,9 +235,7 @@ LLWearable* LLWearableList::createNewWearable( EWearableType type )  	LLWearable *wearable = generateNewWearable();  	wearable->setType( type ); -	LLSD item_name = LLSD().with("[WEARABLE_ITEM]", wearable->getTypeLabel()); -	std::string name = LLTrans::getString("NewWearable"); -	LLStringUtil::format(name, item_name); +	std::string name = LLTrans::getString( LLWearableDictionary::getTypeDefaultNewName(wearable->getType()) );  	wearable->setName( name );  	LLPermissions perm; diff --git a/indra/newview/skins/default/xui/en/floater_outgoing_call.xml b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml index 5ea207675b..9db6568ee3 100644 --- a/indra/newview/skins/default/xui/en/floater_outgoing_call.xml +++ b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml @@ -119,7 +119,7 @@ No Answer.  Please try again later.       layout="topleft"       left="77"       name="leaving" -     top="52" +     top="62"       width="315"       word_wrap="true">  Leaving [CURRENT_CHAT]. diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 5d184fea3a..4479a3dd4d 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -5168,7 +5168,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th     type="offer">  [NAME_SLURL] has offered to teleport you to their location: -[MESSAGE], ([MATURITY]) +[MESSAGE] - [MATURITY_STR] <icon>[MATURITY_ICON]</icon>      <form name="form">        <button         index="0" diff --git a/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml b/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml new file mode 100644 index 0000000000..d00b1bfb7b --- /dev/null +++ b/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<!-- *NOTE: mantipov: this xml is intended to be used inside panel_outfits_list.xml for each outfit folder--> +<!-- All accordion tabs in the My Appearance/My Outfits panel will be created from this one at runtume--> +<accordion_tab + display_children="false" + follows="all" + height="40" + layout="topleft" + name="Mockup Tab" + title="Mockup Tab" + width="0"> +    <wearable_items_list +     allow_select="true" +     follows="all" +     keep_one_selected="true" +     name="wearable_items_list" +    /> +</accordion_tab> diff --git a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml index 184ea54fcb..5dbd8bfe6a 100644 --- a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml @@ -17,7 +17,7 @@       layout="topleft"       left_delta="3"       left="0" -     max_length="512" +     max_length="1024"       name="chat_box"       text_pad_left="5"       text_pad_right="25" diff --git a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml index b1f0ff15cb..314d2389ae 100644 --- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml +++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml @@ -222,6 +222,30 @@                   top="1"                   width="31" />                  <button +                 follows="bottom|left" +                 height="25" +                 image_hover_unselected="Toolbar_Middle_Over" +                 image_overlay="Movement_Forward_On" +                 image_selected="Toolbar_Middle_Selected" +                 image_unselected="Toolbar_Middle_Off" +                 layout="topleft" +                 left_pad="1" +                 name="move_closer_btn" +                 top="1" +                 width="31" /> +                <button +                 follows="bottom|left" +                 height="25" +                 image_hover_unselected="Toolbar_Middle_Over" +                 image_overlay="Movement_Backward_On" +                 image_selected="Toolbar_Middle_Selected" +                 image_unselected="Toolbar_Middle_Off" +                 layout="topleft" +                 left_pad="1" +                 name="move_further_btn" +                 top="1" +                 width="31" /> +                <button                   follows="bottom|right"                   height="25"                   image_hover_unselected="Toolbar_Middle_Over"  | 
