diff options
| author | James Cook <james@lindenlab.com> | 2010-01-11 14:06:09 -0800 | 
|---|---|---|
| committer | James Cook <james@lindenlab.com> | 2010-01-11 14:06:09 -0800 | 
| commit | a36087f5c1851b0bd5eec5788609f35b8a524384 (patch) | |
| tree | d7057930083ba9499fc8b3783a531b24ac9ea7f1 | |
| parent | a570c39bd3ca9ca567ef6a778305b8231535eb70 (diff) | |
| parent | 370a8592ac4c3b6eb6fd9f6ddd35960b763e634f (diff) | |
Merge, sync from viewer-2-0, fixed conflict in llinspectavatar.cpp
46 files changed, 2141 insertions, 138 deletions
| diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 3400a72385..187a9a984e 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -1919,6 +1919,16 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G  : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled)  {  	stop_glerror(); +	 +	checkState(); + +	if (!depth_enabled) +	{ // always disable depth writes if depth testing is disabled +	  // GL spec defines this as a requirement, but some implementations allow depth writes with testing disabled +	  // The proper way to write to depth buffer with testing disabled is to enable testing and use a depth_func of GL_ALWAYS +		write_enabled = FALSE; +	} +  	if (depth_enabled != sDepthEnabled)  	{  		gGL.flush(); @@ -1942,6 +1952,7 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G  LLGLDepthTest::~LLGLDepthTest()  { +	checkState();  	if (sDepthEnabled != mPrevDepthEnabled )  	{  		gGL.flush(); @@ -1963,6 +1974,32 @@ LLGLDepthTest::~LLGLDepthTest()  	}  } +void LLGLDepthTest::checkState() +{ +	if (gDebugGL) +	{ +		GLint func = 0; +		GLboolean mask = FALSE; + +		glGetIntegerv(GL_DEPTH_FUNC, &func); +		glGetBooleanv(GL_DEPTH_WRITEMASK, &mask); + +		if (glIsEnabled(GL_DEPTH_TEST) != sDepthEnabled || +			sWriteEnabled != mask || +			sDepthFunc != func) +		{ +			if (gDebugSession) +			{ +				gFailLog << "Unexpected depth testing state." << std::endl; +			} +			else +			{ +				LL_GL_ERRS << "Unexpected depth testing state." << LL_ENDL; +			} +		} +	} +} +  LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P)  {  	for (U32 i = 0; i < 4; i++) diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h index 4a51cac438..968a37cab0 100644 --- a/indra/llrender/llglstates.h +++ b/indra/llrender/llglstates.h @@ -46,6 +46,8 @@ public:  	~LLGLDepthTest(); +	void checkState(); +  	GLboolean mPrevDepthEnabled;  	GLenum mPrevDepthFunc;  	GLboolean mPrevWriteEnabled; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index fc45df8153..f97d81126e 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -162,6 +162,8 @@ void LLTexUnit::enable(eTextureType type)  			disable(); // Force a disable of a previous texture type if it's enabled.  		}  		mCurrTexType = type; + +		gGL.flush();  		glEnable(sGLTextureType[type]);  	}  } diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 82ec02d2eb..ce068618e2 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -26,6 +26,8 @@ include_directories(      )  set(llui_SOURCE_FILES +    llaccordionctrl.cpp +    llaccordionctrltab.cpp      llbutton.cpp      llcheckboxctrl.cpp      llclipboard.cpp @@ -111,6 +113,8 @@ set(llui_SOURCE_FILES  set(llui_HEADER_FILES      CMakeLists.txt +    llaccordionctrl.h +    llaccordionctrltab.h      llbutton.h      llcallbackmap.h      llcheckboxctrl.h diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp new file mode 100644 index 0000000000..b5e870228a --- /dev/null +++ b/indra/llui/llaccordionctrl.cpp @@ -0,0 +1,578 @@ +/**  + * @file llaccordionctrl.cpp + * @brief Accordion panel  implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + *  + * Copyright (c) 2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "linden_common.h" + +#include "llaccordionctrl.h" +#include "llaccordionctrltab.h" + +#include "lluictrlfactory.h" // builds floaters from XML + +#include "llwindow.h" +#include "llfocusmgr.h" +#include "lllocalcliprect.h" + +#include "boost/bind.hpp" + +static const S32 DRAGGER_BAR_MARGIN = 4; +static const S32 DRAGGER_BAR_HEIGHT = 5; +static const S32 BORDER_MARGIN = 2; +static const S32 PARENT_BORDER_MARGIN = 5; + +static const S32 panel_delta = DRAGGER_BAR_MARGIN;  // Distanse between two panels  + +static const S32 HORIZONTAL_MULTIPLE = 8; +static const S32 VERTICAL_MULTIPLE = 16; +static const F32 MIN_AUTO_SCROLL_RATE = 120.f; +static const F32 MAX_AUTO_SCROLL_RATE = 500.f; +static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f; + + +// LLAccordionCtrl =================================================================| + +static LLDefaultChildRegistry::Register<LLAccordionCtrl>	t2("accordion"); + + +LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params) + , mFitParent(params.fit_parent) +{ +  mSingleExpansion = params.single_expansion; +	if(mFitParent && !mSingleExpansion) +	{ +		llinfos << "fit_parent works best when combined with single_expansion" << llendl; +	} +} + +LLAccordionCtrl::LLAccordionCtrl() : LLPanel() +{ +	mSingleExpansion = false; +	mFitParent = false; +	LLUICtrlFactory::getInstance()->buildPanel(this, "accordion_parent.xml");	 +} + +//--------------------------------------------------------------------------------- +void LLAccordionCtrl::draw() +{ +	LLRect local_rect(0, getRect().getHeight(), getRect().getWidth(), 0); +	 +	LLLocalClipRect clip(local_rect); +	 +	LLPanel::draw(); +} + + +//--------------------------------------------------------------------------------- +BOOL LLAccordionCtrl::postBuild() +{ +	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + +	LLRect scroll_rect; +	scroll_rect.setOriginAndSize(  +		getRect().getWidth() - scrollbar_size, +		1, +		scrollbar_size, +		getRect().getHeight() - 1); +	 + +	LLScrollbar::Params sbparams; +	sbparams.name("scrollable vertical"); +	sbparams.rect(scroll_rect); +	sbparams.orientation(LLScrollbar::VERTICAL); +	sbparams.doc_size(mInnerRect.getHeight()); +	sbparams.doc_pos(0); +	sbparams.page_size(mInnerRect.getHeight()); +	sbparams.step_size(VERTICAL_MULTIPLE); +	sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); +	sbparams.change_callback(boost::bind(&LLAccordionCtrl::onScrollPosChangeCallback, this, _1, _2)); +	 +	mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams); +	LLView::addChild( mScrollbar ); +	mScrollbar->setVisible( false ); +	mScrollbar->setFollowsRight(); +	mScrollbar->setFollowsTop(); +	mScrollbar->setFollowsBottom(); + +	//if it was created from xml... +	std::vector<LLUICtrl*> accordion_tabs; +	for(child_list_const_iter_t it = getChildList()->begin();  +		getChildList()->end() != it; ++it) +	{ +		LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(*it); +		if(accordion_tab == NULL) +			continue; +		if(std::find(mAccordionTabs.begin(),mAccordionTabs.end(),accordion_tab) == mAccordionTabs.end()) +		{ +			accordion_tabs.push_back(accordion_tab); +		} +	} + +	for(std::vector<LLUICtrl*>::reverse_iterator it = accordion_tabs.rbegin();it!=accordion_tabs.rend();++it) +		addCollapsibleCtrl(*it); + +	arrange	(); + +	if(mSingleExpansion) +	{ +		if(!mAccordionTabs[0]->getDisplayChildren()) +			mAccordionTabs[0]->setDisplayChildren(true); +		for(size_t i=1;i<mAccordionTabs.size();++i) +		{ +			if(mAccordionTabs[i]->getDisplayChildren()) +				mAccordionTabs[i]->setDisplayChildren(false); +		} +	} + +	return TRUE; +} + + +//--------------------------------------------------------------------------------- +LLAccordionCtrl::~LLAccordionCtrl() +{ +  mAccordionTabs.clear(); +} + +//--------------------------------------------------------------------------------- + +void LLAccordionCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) +{ +	// adjust our rectangle +	LLRect rcLocal = getRect(); +	rcLocal.mRight = rcLocal.mLeft + width; +	rcLocal.mTop = rcLocal.mBottom + height; + +	setRect(rcLocal); + +	arrange(); +} + +//--------------------------------------------------------------------------------- +BOOL LLAccordionCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ +	return LLPanel::handleRightMouseDown(x, y, mask); +} + +//--------------------------------------------------------------------------------- +void LLAccordionCtrl::shiftAccordionTabs(S16 panel_num, S32 delta) +{ +	for(size_t i = panel_num; i < mAccordionTabs.size(); i++ ) +	{ +		ctrlShiftVertical(mAccordionTabs[i],delta); +	}	 +} + + +//--------------------------------------------------------------------------------- +void LLAccordionCtrl::onCollapseCtrlCloseOpen(S16 panel_num)  +{ +	if(mSingleExpansion) +	{ +		for(size_t i=0;i<mAccordionTabs.size();++i) +		{ +			if(i==panel_num) +				continue; +			if(mAccordionTabs[i]->getDisplayChildren()) +				mAccordionTabs[i]->setDisplayChildren(false); +		} + +	} +	arrange(); +} + +void LLAccordionCtrl::show_hide_scrollbar(S32 width, S32 height) +{ +	calcRecuiredHeight(); +	if(getRecuiredHeight() > height ) +		showScrollbar(width,height); +	else +		hideScrollbar(width,height); +} + +void	LLAccordionCtrl::showScrollbar(S32 width, S32 height) +{ +	bool was_visible = mScrollbar->getVisible(); + +	mScrollbar->setVisible(true); +	 +	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + +	ctrlSetLeftTopAndSize(mScrollbar +		,width-scrollbar_size - PARENT_BORDER_MARGIN/2 +		,height-PARENT_BORDER_MARGIN +		,scrollbar_size +		,height-2*PARENT_BORDER_MARGIN); +	 +	mScrollbar->setPageSize(height); +	mScrollbar->setDocParams(mInnerRect.getHeight(),mScrollbar->getDocPos()); + +	if(was_visible) +	{ +		S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1); +		mScrollbar->setDocPos(scroll_pos); +	} +} + +void	LLAccordionCtrl::hideScrollbar( S32 width, S32 height ) +{ +	if(mScrollbar->getVisible() == false) +		return; +	mScrollbar->setVisible(false); + +	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + +	S32 panel_width = width - 2*BORDER_MARGIN; + +	//reshape all accordeons and shift all draggers +	for(size_t i=0;i<mAccordionTabs.size();++i) +	{ +		LLRect panel_rect = mAccordionTabs[i]->getRect(); +		ctrlSetLeftTopAndSize(mAccordionTabs[i],panel_rect.mLeft,panel_rect.mTop,panel_width,panel_rect.getHeight()); +	} + +	mScrollbar->setDocPos(0); + +	if(mAccordionTabs.size()>0) +	{ +		S32 panel_top = height - BORDER_MARGIN;		  // Top coordinate of the first panel +		S32 diff = panel_top - mAccordionTabs[0]->getRect().mTop; +		shiftAccordionTabs(0,diff); +	} +} + + +//--------------------------------------------------------------------------------- +S32 LLAccordionCtrl::calcRecuiredHeight() +{ +	S32 rec_height = 0; +	 +	std::vector<LLAccordionCtrlTab*>::iterator panel; +	for(panel=mAccordionTabs.begin(); panel!=mAccordionTabs.end(); ++panel) +	{ +		LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(*panel); +		if(accordion_tab && accordion_tab->getVisible()) +		{ +			rec_height += accordion_tab->getRect().getHeight(); +		} +	} + +	mInnerRect.setLeftTopAndSize(0,rec_height + BORDER_MARGIN*2,getRect().getWidth(),rec_height + BORDER_MARGIN); + +	return mInnerRect.getHeight(); +} + +//--------------------------------------------------------------------------------- +void LLAccordionCtrl::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height) +{ +	if(!panel) +		return; +	LLRect panel_rect = panel->getRect(); +	panel_rect.setLeftTopAndSize( left, top, width, height); +	panel->reshape( width, height, 1); +	panel->setRect(panel_rect); +} + +void LLAccordionCtrl::ctrlShiftVertical(LLView* panel,S32 delta) +{ +	if(!panel) +		return; +	panel->translate(0,delta); +} + +//--------------------------------------------------------------------------------- + +void LLAccordionCtrl::addCollapsibleCtrl(LLView* view) +{ +	LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view); +	if(!accordion_tab) +		return; +	if(std::find(getChildList()->begin(),getChildList()->end(),accordion_tab) == getChildList()->end()) +		addChild(accordion_tab); +	mAccordionTabs.push_back(accordion_tab); +	 +	accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, mAccordionTabs.size() - 1) ); + +} + + +void LLAccordionCtrl::arrange() +{ +	if( mAccordionTabs.size() == 0) +	{ +		//We do not arrange if we do not have what should be arranged +		return; +	} + +	//Calculate params	 +	S32 panel_left = BORDER_MARGIN;	  // Margin from left side of Splitter +	S32 panel_top = getRect().getHeight() - BORDER_MARGIN;		  // Top coordinate of the first panel +	S32 panel_width = getRect().getWidth() - 4;		  // Top coordinate of the first panel + +	 +	if(mAccordionTabs.size() == 1) +	{ +		LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[0]); +		 +		LLRect panel_rect = accordion_tab->getRect(); +		 +		S32 panel_height = getRect().getHeight() - 2*BORDER_MARGIN; + +		ctrlSetLeftTopAndSize(accordion_tab,panel_rect.mLeft,panel_top,panel_width,panel_height); +		 +		show_hide_scrollbar(getRect().getWidth(),getRect().getHeight()); +		return; + +	} + +	for(size_t i = 0; i < mAccordionTabs.size(); i++ ) +	{ +		LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); +		 +		if(accordion_tab->getVisible() == false) //skip hidden accordion tabs +			continue; +		 +		if(!accordion_tab->isExpanded() ) +		{ +			ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, accordion_tab->getRect().getHeight()); +			panel_top-=mAccordionTabs[i]->getRect().getHeight(); +		} +		else +		{ +			S32 panel_height = accordion_tab->getRect().getHeight(); +			 +			if(mFitParent) +			{ +				// all expanded tabs will have equal height +				panel_height = calcExpandedTabHeight(i, panel_top); +				ctrlSetLeftTopAndSize(accordion_tab, panel_left, panel_top, panel_width, panel_height); + +				// try to make accordion tab fit accordion view height. +				// Accordion View should implement getRequiredRect() and provide valid height +				S32 optimal_height = accordion_tab->getAccordionView()->getRequiredRect().getHeight(); +				optimal_height += accordion_tab->getHeaderHeight() + 2 * BORDER_MARGIN; +				if(optimal_height < panel_height) +				{ +					panel_height = optimal_height; +				} + +				// minimum tab height is equal to header height +				if(mAccordionTabs[i]->getHeaderHeight() > panel_height) +				{ +					panel_height = mAccordionTabs[i]->getHeaderHeight(); +				} +			} +			 +			ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height); +			panel_top-=panel_height; +			 +		} +	}	 + +	show_hide_scrollbar(getRect().getWidth(),getRect().getHeight()); + +	updateLayout(getRect().getWidth(),getRect().getHeight()); + +} + +//--------------------------------------------------------------------------------- + +BOOL LLAccordionCtrl::handleScrollWheel		( S32 x, S32 y, S32 clicks ) +{ +	if(LLPanel::handleScrollWheel(x,y,clicks)) +		return TRUE; +	if( mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) ) +		return TRUE; +	return false; + +} + +BOOL LLAccordionCtrl::handleKeyHere			(KEY key, MASK mask) +{ +	if( mScrollbar->getVisible() && mScrollbar->handleKeyHere( key,mask ) ) +		return TRUE; +	return LLPanel::handleKeyHere(key,mask); +} + +void	LLAccordionCtrl::updateLayout	(S32 width, S32 height) +{ +	S32 panel_top = height - BORDER_MARGIN ; +	if(mScrollbar->getVisible()) +		panel_top+=mScrollbar->getDocPos(); + +	S32 panel_width = width - 2*BORDER_MARGIN; + +	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); +	if(mScrollbar->getVisible()) +		panel_width-=scrollbar_size; + +	//set sizes for first panels and dragbars +	for(size_t i=0;i<mAccordionTabs.size();++i) +	{ +		if(!mAccordionTabs[i]->getVisible()) +			continue; +		LLRect panel_rect = mAccordionTabs[i]->getRect(); +		ctrlSetLeftTopAndSize(mAccordionTabs[i],panel_rect.mLeft,panel_top,panel_width,panel_rect.getHeight()); +		panel_top-=panel_rect.getHeight(); +	} +} + +void	LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*) +{ +	updateLayout(getRect().getWidth(),getRect().getHeight()); +} +void	LLAccordionCtrl::onOpen		(const LLSD& key) +{ +	for(size_t i=0;i<mAccordionTabs.size();++i) +	{ +		LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); +		LLPanel* panel = dynamic_cast<LLPanel*>(accordion_tab->getAccordionView()); +		if(panel!=NULL) +		{ +			panel->onOpen(key); +		} +	} +} +S32	LLAccordionCtrl::notifyParent(const LLSD& info) +{ +	if(info.has("action")) +	{ +		std::string str_action = info["action"]; +		if(str_action == "size_changes") +		{ +			// +			arrange(); +			return 1; +		} +		else if(str_action == "select_next") +		{ +			for(size_t i=0;i<mAccordionTabs.size();++i) +			{ +				LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); +				if(accordion_tab->hasFocus()) +				{ +					while(++i<mAccordionTabs.size()) +					{ +						if(mAccordionTabs[i]->getVisible()) +							break; +					} +					if(i<mAccordionTabs.size()) +					{ +						accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); +						accordion_tab->notify(LLSD().with("action","select_first")); +						return 1; +					} +					break; +				} +			} +			return 0; +		} +		else if(str_action == "select_prev") +		{ +			for(size_t i=0;i<mAccordionTabs.size();++i) +			{ +				LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); +				if(accordion_tab->hasFocus() && i>0) +				{ +					while(i>0) +					{ +						if(mAccordionTabs[--i]->getVisible()) +							break; +					} +					 +					accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); +					accordion_tab->notify(LLSD().with("action","select_last")); +					return 1; +				} +			} +			return 0; +		} +	} +	else if (info.has("scrollToShowRect")) +	{ +		LLRect screen_rc, local_rc; +		screen_rc.setValue(info["scrollToShowRect"]); +		screenRectToLocal(screen_rc, &local_rc); + +		// Translate to parent coordinatess to check if we are in visible rectangle +		local_rc.translate( getRect().mLeft, getRect().mBottom ); + +		if ( !getRect().contains (local_rc) ) +		{ +			// Back to local coords and calculate position for scroller +			S32 bottom = mScrollbar->getDocPos() - local_rc.mBottom + getRect().mBottom; +			S32 top = mScrollbar->getDocPos() - local_rc.mTop + getRect().mTop; + +			S32 scroll_pos = llclamp(mScrollbar->getDocPos(), +									 bottom, // min vertical scroll +									 top); // max vertical scroll  + +			mScrollbar->setDocPos( scroll_pos ); +		} +		return 1; +	} +	return LLPanel::notifyParent(info); +} +void	LLAccordionCtrl::reset		() +{ +	if(mScrollbar) +		mScrollbar->setDocPos(0); +} + +S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 available_height /* = 0 */) +{ +	if(tab_index < 0) +	{ +		return available_height; +	} + +	S32 collapsed_tabs_height = 0; +	S32 num_expanded = 0; + +	for(size_t n = tab_index; n < mAccordionTabs.size(); ++n) +	{ +		if(!mAccordionTabs[n]->isExpanded()) +		{ +			collapsed_tabs_height += mAccordionTabs[n]->getHeaderHeight(); +		} +		else +		{ +			++num_expanded; +		} +	} + +	if(0 == num_expanded) +	{ +		return available_height; +	} + +	S32 expanded_tab_height = available_height - collapsed_tabs_height - BORDER_MARGIN; // top BORDER_MARGIN is added in arrange(), here we add bottom BORDER_MARGIN +	expanded_tab_height /= num_expanded; +	return expanded_tab_height; +} diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h new file mode 100644 index 0000000000..4cb0f38281 --- /dev/null +++ b/indra/llui/llaccordionctrl.h @@ -0,0 +1,123 @@ +/**  + * @file LLAccordionCtrl.h + * @brief Accordion Panel implementation + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + *  + * Copyright (c) 2004-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_ACCORDIONCTRL_H +#define LL_ACCORDIONCTRL_H + +#include "llpanel.h" +#include "llscrollbar.h" + +#include <vector> +#include <algorithm> +#include <string> + +class LLAccordionCtrlTab; + +class LLAccordionCtrl: public LLPanel +{ +private: + +	std::vector<LLAccordionCtrlTab*> mAccordionTabs; + +	void ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height); +	void ctrlShiftVertical(LLView* panel,S32 delta); +	 +	void onCollapseCtrlCloseOpen(S16 panel_num);  +	void shiftAccordionTabs(S16 panel_num, S32 delta); + + +public: +	struct Params  +		: public LLInitParam::Block<Params, LLPanel::Params> +	{ +		Optional<bool>			single_expansion, +								fit_parent; /* Accordion will fit its parent size, controls that are placed into  +								accordion tabs are responsible for scrolling their content. +								*NOTE fit_parent works best when combined with single_expansion. +								Accordion view should implement getRequiredRect() and provide valid height*/ + +		Params() +			: single_expansion("single_expansion",false) +			, fit_parent("fit_parent", false) +		{}; +	}; + +	LLAccordionCtrl(const Params& params); + +    LLAccordionCtrl(); +    virtual ~LLAccordionCtrl(); + +	virtual BOOL postBuild(); +	 +	virtual BOOL handleRightMouseDown	( S32 x, S32 y, MASK mask);  +	virtual BOOL handleScrollWheel		( S32 x, S32 y, S32 clicks ); +	virtual BOOL handleKeyHere			(KEY key, MASK mask); +	// + +	// Call reshape after changing splitter's size +	virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + +	void addCollapsibleCtrl(LLView* view); +	void arrange(); + + +	void	draw(); +	 +	void	onScrollPosChangeCallback(S32, LLScrollbar*); + +	void	onOpen		(const LLSD& key); +	S32		notifyParent(const LLSD& info); + +	void	reset		(); + +private: +	// Calc Splitter's height that is necessary to display all child content +	S32		calcRecuiredHeight(); +	S32		getRecuiredHeight() const { return mInnerRect.getHeight(); } +	S32		calcExpandedTabHeight(S32 tab_index = 0, S32 available_height = 0); + +	void	updateLayout			(S32 width, S32 height); + +	void	show_hide_scrollbar		(S32 width, S32 height); + +	void	showScrollbar			(S32 width, S32 height); +	void	hideScrollbar			(S32 width, S32 height); + +private: +	LLRect			mInnerRect; +	LLScrollbar*	mScrollbar; +	bool			mSingleExpansion; +	bool			mFitParent; +}; + + +#endif // LL_LLSPLITTER_H diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp new file mode 100644 index 0000000000..9d6ba57c29 --- /dev/null +++ b/indra/llui/llaccordionctrltab.cpp @@ -0,0 +1,599 @@ +/**  + * @file LLAccordionCtrlTab.cpp + * @brief Collapsible control implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + *  + * Copyright (c) 2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lluictrl.h" + +#include "llaccordionctrltab.h" + +#include "lltextbox.h" + +static const std::string DD_BUTTON_NAME = "dd_button"; +static const std::string DD_TEXTBOX_NAME = "dd_textbox"; +static const std::string DD_HEADER_NAME = "dd_header"; + +static const S32 HEADER_HEIGHT = 20; +static const S32 HEADER_IMAGE_LEFT_OFFSET = 5; +static const S32 HEADER_TEXT_LEFT_OFFSET = 30; + +static LLDefaultChildRegistry::Register<LLAccordionCtrlTab> t1("accordion_tab"); + +class LLAccordionCtrlTab::LLAccordionCtrlTabHeader : public LLUICtrl +{ +public: +	friend class LLUICtrlFactory; + +	struct Params : public LLInitParam::Block<Params, LLAccordionCtrlTab::Params> +	{ +		Params(); +	}; + +	LLAccordionCtrlTabHeader(const LLAccordionCtrlTabHeader::Params& p); +	 +	virtual ~LLAccordionCtrlTabHeader(); + +	virtual void draw(); + +	virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + +	virtual BOOL postBuild(); + +	void	setTitle(const std::string& title); + +	virtual void onMouseEnter(S32 x, S32 y, MASK mask); +	virtual void onMouseLeave(S32 x, S32 y, MASK mask); +	virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); +private: + +	LLTextBox* mHeaderTextbox; + +	// Overlay images (arrows) +	LLPointer<LLUIImage> mImageCollapsed; +	LLPointer<LLUIImage> mImageExpanded; +	LLPointer<LLUIImage> mImageCollapsedPressed; +	LLPointer<LLUIImage> mImageExpandedPressed; + +	// Background images +	LLPointer<LLUIImage> mImageHeader; +	LLPointer<LLUIImage> mImageHeaderOver; +	LLPointer<LLUIImage> mImageHeaderPressed; +	LLPointer<LLUIImage> mImageHeaderFocused; + +	LLUIColor mHeaderBGColor; + +	bool mNeedsHighlight; +}; + +LLAccordionCtrlTab::LLAccordionCtrlTabHeader::Params::Params() +{ +} + +LLAccordionCtrlTab::LLAccordionCtrlTabHeader::LLAccordionCtrlTabHeader( +	const LLAccordionCtrlTabHeader::Params& p) +: LLUICtrl(p) +, mHeaderBGColor(p.header_bg_color()) +,mNeedsHighlight(false), +	mImageCollapsed(p.header_collapse_img), +	mImageCollapsedPressed(p.header_collapse_img_pressed), +	mImageExpanded(p.header_expand_img), +	mImageExpandedPressed(p.header_expand_img_pressed), +	mImageHeader(p.header_image), +	mImageHeaderOver(p.header_image_over), +	mImageHeaderPressed(p.header_image_pressed), +	mImageHeaderFocused(p.header_image_focused) +{ +	LLTextBox::Params textboxParams; +	textboxParams.name(DD_TEXTBOX_NAME); +	textboxParams.initial_value(p.title()); +	textboxParams.text_color(p.header_text_color()); +	textboxParams.follows.flags(FOLLOWS_NONE); +	textboxParams.font( p.font() ); +	textboxParams.font_shadow(LLFontGL::NO_SHADOW); +	textboxParams.use_ellipses = true; +	textboxParams.bg_visible = false; +	textboxParams.mouse_opaque = false; +	mHeaderTextbox = LLUICtrlFactory::create<LLTextBox>(textboxParams); +	addChild(mHeaderTextbox); +} + +LLAccordionCtrlTab::LLAccordionCtrlTabHeader::~LLAccordionCtrlTabHeader() +{ +} + +BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::postBuild() +{ +	return TRUE; +} + +void	LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitle(const std::string& title) +{ +	if(mHeaderTextbox) +		mHeaderTextbox->setText(title); +} + +void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw() +{ +	S32 width = getRect().getWidth(); +	S32 height = getRect().getHeight(); + +	gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get(),true); + +	LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent()); +	bool collapsible = (parent && parent->getCollapsible()); +	bool expanded = (parent && parent->getDisplayChildren()); + +	// Handle overlay images, if needed +	// Only show green "focus" background image if the accordion is open, +	// because the user's mental model of focus is that it goes away after +	// the accordion is closed. +	if (getParent()->hasFocus() +		&& !(collapsible && !expanded)) +	{ +		mImageHeaderFocused->draw(0,0,width,height); +	} +	else +	{ +		mImageHeader->draw(0,0,width,height); +	} + +	if(mNeedsHighlight) +	{ +		mImageHeaderOver->draw(0,0,width,height); +	} +	 + +	if(collapsible) +	{ +		LLPointer<LLUIImage> overlay_image; +		if(expanded) +		{ +			overlay_image = mImageExpanded; +		} +		else +		{ +			overlay_image = mImageCollapsed; +		} +		overlay_image->draw(HEADER_IMAGE_LEFT_OFFSET, +							(height - overlay_image->getHeight()) / 2); +	} +	 +	LLUICtrl::draw(); +} + +void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) +{ +	S32 header_height = mHeaderTextbox->getTextPixelHeight(); + +	LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET,(height+header_height)/2 ,width,(height-header_height)/2); +	mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight()); +	mHeaderTextbox->setRect(textboxRect); +} + +void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseEnter(S32 x, S32 y, MASK mask) +{ +	LLUICtrl::onMouseEnter(x, y, mask); +	mNeedsHighlight = true; +} +void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseLeave(S32 x, S32 y, MASK mask) +{ +	LLUICtrl::onMouseLeave(x, y, mask); +	mNeedsHighlight = false; +} +BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ +	if ( ( key == KEY_LEFT || key == KEY_RIGHT) && mask == MASK_NONE) +	{ +		return getParent()->handleKey(key, mask, called_from_parent); +	} +	return LLUICtrl::handleKey(key, mask, called_from_parent); +} + + +LLAccordionCtrlTab::Params::Params() +	: title("title") +	,display_children("expanded", true) +	,header_height("header_height", HEADER_HEIGHT), +	min_width("min_width", 0), +	min_height("min_height", 0) +	,collapsible("collapsible", true) +	,header_bg_color("header_bg_color") +	,dropdown_bg_color("dropdown_bg_color") +	,header_visible("header_visible",true) +	,padding_left("padding_left",2) +	,padding_right("padding_right",2) +	,padding_top("padding_top",2) +	,padding_bottom("padding_bottom",2) +	,header_expand_img("header_expand_img") +	,header_expand_img_pressed("header_expand_img_pressed") +	,header_collapse_img("header_collapse_img") +	,header_collapse_img_pressed("header_collapse_img_pressed") +	,header_image("header_image") +	,header_image_over("header_image_over") +	,header_image_pressed("header_image_pressed") +	,header_image_focused("header_image_focused") +	,header_text_color("header_text_color") +{ +	mouse_opaque(false); +} + +LLAccordionCtrlTab::LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&p) +	: LLUICtrl(p) +	,mDisplayChildren(p.display_children) +	,mCollapsible(p.collapsible) +	,mExpandedHeight(0) +	,mDropdownBGColor(p.dropdown_bg_color()) +	,mHeaderVisible(p.header_visible) +	,mPaddingLeft(p.padding_left) +	,mPaddingRight(p.padding_right) +	,mPaddingTop(p.padding_top) +	,mPaddingBottom(p.padding_bottom) +	,mCanOpenClose(true) +{ +	mStoredOpenCloseState = false; +	mWasStateStored = false; +	 +	mDropdownBGColor = LLColor4::white; +	LLAccordionCtrlTabHeader::Params headerParams; +	headerParams.name(DD_HEADER_NAME); +	headerParams.title(p.title); +	mHeader = LLUICtrlFactory::create<LLAccordionCtrlTabHeader>(headerParams); +	addChild(mHeader, 1); + +	reshape(100, 200,FALSE); +} + +LLAccordionCtrlTab::~LLAccordionCtrlTab() +{ +} + + +void LLAccordionCtrlTab::setDisplayChildren(bool display) +{ +	mDisplayChildren = display; +	LLRect rect = getRect(); + +	rect.mBottom = rect.mTop - (getDisplayChildren() ?  +		mExpandedHeight : HEADER_HEIGHT); +	setRect(rect); + +	for(child_list_const_iter_t it = getChildList()->begin(); +		getChildList()->end() != it; ++it) +	{ +		LLView* child = *it; +		if(DD_HEADER_NAME == child->getName()) +			continue; + +		child->setVisible(getDisplayChildren()); +	} +} + +void LLAccordionCtrlTab::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) +{ +	LLRect headerRect; + +	LLUICtrl::reshape(width, height, TRUE); + +	headerRect.setLeftTopAndSize( +		0,height,width,HEADER_HEIGHT); +	mHeader->setRect(headerRect); +	mHeader->reshape(headerRect.getWidth(), headerRect.getHeight()); + +	for(child_list_const_iter_t it = getChildList()->begin();  +		getChildList()->end() != it; ++it) +	{ +		LLView* child = *it; +		if(DD_HEADER_NAME == child->getName()) +			continue; +		if(!child->getVisible()) +			continue; + +		LLRect childRect = child->getRect(); +		S32 childWidth = width - getPaddingLeft() - getPaddingRight(); +		S32 childHeight = height - getHeaderHeight() - getPaddingTop() - getPaddingBottom(); + +		child->reshape(childWidth,childHeight); +		 +		childRect.setLeftTopAndSize( +			getPaddingLeft(), +			childHeight + getPaddingBottom(), +			childWidth,  +			childHeight); + +		child->setRect(childRect); +		 +		break;//suppose that there is only one panel +	} + +} + +void LLAccordionCtrlTab::changeOpenClose(bool is_open) +{ +	if(is_open) +		mExpandedHeight = getRect().getHeight(); + +	setDisplayChildren(!is_open); +	reshape(getRect().getWidth(), getRect().getHeight(), FALSE); +	if (mCommitSignal) +	{ +		(*mCommitSignal)(this, getDisplayChildren()); +	} +} + +BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask) +{ +	if(mCollapsible && mHeaderVisible && mCanOpenClose) +	{ +		if(y >= (getRect().getHeight() - HEADER_HEIGHT) ) +		{ +			LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME); +			header->setFocus(true); +			changeOpenClose(getDisplayChildren()); + +			//reset stored state +			mWasStateStored = false; +			return TRUE; +		} +	} +	return LLUICtrl::handleMouseDown(x,y,mask); +} + +BOOL LLAccordionCtrlTab::handleMouseUp(S32 x, S32 y, MASK mask) +{ +	return LLUICtrl::handleMouseUp(x,y,mask); +} + +boost::signals2::connection LLAccordionCtrlTab::setDropDownStateChangedCallback(commit_callback_t cb) +{ +	return setCommitCallback(cb); +} + +bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group) +{ +	if(DD_HEADER_NAME != child->getName()) +	{ +		reshape(child->getRect().getWidth() , child->getRect().getHeight() + HEADER_HEIGHT ); +		mExpandedHeight = getRect().getHeight(); +	} + +	bool res = LLUICtrl::addChild(child, tab_group); + +	if(DD_HEADER_NAME != child->getName()) +	{ +		if(!mCollapsible) +			setDisplayChildren(true); +		else +			setDisplayChildren(getDisplayChildren());	 +	} + +	return res; +} + +void LLAccordionCtrlTab::setAccordionView(LLView* panel) +{ +	addChild(panel,0); +} + + +LLView*	LLAccordionCtrlTab::getAccordionView() +{ +	for(child_list_const_iter_t it = getChildList()->begin();  +		getChildList()->end() != it; ++it) +	{ +		LLView* child = *it; +		if(DD_HEADER_NAME == child->getName()) +			continue; +		if(!child->getVisible()) +			continue; +		return child; +	} +	return NULL; +} + + +S32 LLAccordionCtrlTab::getHeaderHeight() +{ +	return mHeaderVisible?HEADER_HEIGHT:0;  +} + +void LLAccordionCtrlTab::setHeaderVisible(bool value)  +{ +	if(mHeaderVisible == value) +		return; +	mHeaderVisible = value; +	if(mHeader) +		mHeader->setVisible(value); +	reshape(getRect().getWidth(), getRect().getHeight(), FALSE); +}; + +//vurtual +BOOL LLAccordionCtrlTab::postBuild() +{ +	mHeader->setVisible(mHeaderVisible); +	return LLUICtrl::postBuild(); +} +bool	LLAccordionCtrlTab::notifyChildren	(const LLSD& info) +{ +	if(info.has("action")) +	{ +		std::string str_action = info["action"]; +		if(str_action == "store_state") +		{ +			storeOpenCloseState(); +			return true; +		} +		if(str_action == "restore_state") +		{ +			restoreOpenCloseState(); +			return true; +		} +	}	 +	return LLUICtrl::notifyChildren(info); +} + +S32	LLAccordionCtrlTab::notifyParent(const LLSD& info) +{ +	if(info.has("action")) +	{ +		std::string str_action = info["action"]; +		if(str_action == "size_changes") +		{ +			// +			S32 height = info["height"]; +			height = llmax(height,10) + HEADER_HEIGHT + getPaddingTop() + getPaddingBottom(); +			 +			mExpandedHeight = height; +			 +			if(isExpanded()) +			{ +				LLRect panel_rect = getRect(); +				panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth(), height); +				reshape(getRect().getWidth(),height); +				setRect(panel_rect); +			} +			 +			//LLAccordionCtrl should rearrange accodion tab if one of accordion change its size +			getParent()->notifyParent(info); +			return 1; +		} +		else if(str_action == "select_prev")  +		{ +			showAndFocusHeader(); +			return 1; +		} +	} +	return LLUICtrl::notifyParent(info); +} + +S32 LLAccordionCtrlTab::notify(const LLSD& info) +{ +	if(info.has("action")) +	{ +		std::string str_action = info["action"]; +		if(str_action == "select_first") +		{ +			showAndFocusHeader(); +			return 1; +		} +		else if( str_action == "select_last" ) +		{ +			if(getDisplayChildren() == false) +			{ +				showAndFocusHeader(); +			} +			else +			{ +				LLView* view = getAccordionView(); +				if(view) +					view->notify(LLSD().with("action","select_last")); +			} +		} +	} +	return 0; +} + +BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ +	LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);	 +	if( !header->hasFocus() ) +		return LLUICtrl::handleKey(key, mask, called_from_parent); + +	if ( (key == KEY_ADD || key == KEY_RIGHT)&& mask == MASK_NONE) +	{ +		if(getDisplayChildren() == false) +		{ +			changeOpenClose(getDisplayChildren()); +			return TRUE; +		} +	} +	if ( (key == KEY_SUBTRACT || key == KEY_LEFT)&& mask == MASK_NONE) +	{ +		if(getDisplayChildren() == true) +		{ +			changeOpenClose(getDisplayChildren()); +			return TRUE; +		} +	} + +	if ( key == KEY_DOWN && mask == MASK_NONE) +	{ +		//if collapsed go to the next accordion +		if(getDisplayChildren() == false) +			//we processing notifyParent so let call parent directly +			getParent()->notifyParent(LLSD().with("action","select_next")); +		else +		{ +			getAccordionView()->notify(LLSD().with("action","select_first")); +		} +		return TRUE; +	} + +	if ( key == KEY_UP && mask == MASK_NONE) +	{ +		//go to the previous accordion + +		//we processing notifyParent so let call parent directly +		getParent()->notifyParent(LLSD().with("action","select_prev")); +		return TRUE; +	} + +	return LLUICtrl::handleKey(key, mask, called_from_parent); +} + +void LLAccordionCtrlTab::showAndFocusHeader() +{ +	LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);	 +	header->setFocus(true); + +	LLRect screen_rc; +	LLRect selected_rc = header->getRect(); +	localRectToScreen(selected_rc, &screen_rc); +	notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue())); + +} +void    LLAccordionCtrlTab::storeOpenCloseState() +{ +	if(mWasStateStored) +		return; +	mStoredOpenCloseState = getDisplayChildren(); +	mWasStateStored = true; +} +void   LLAccordionCtrlTab::restoreOpenCloseState() +{ +	if(!mWasStateStored) +		return; +	if(getDisplayChildren() != mStoredOpenCloseState) +	{ +		changeOpenClose(getDisplayChildren()); +	} +	mWasStateStored = false; +} diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h new file mode 100644 index 0000000000..b200d43438 --- /dev/null +++ b/indra/llui/llaccordionctrltab.h @@ -0,0 +1,191 @@ +/**  + * @file LLAccordionCtrlTab.h + * @brief Collapsible box control implementation + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + *  + * Copyright (c) 2004-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_ACCORDIONCTRLTAB_H_ +#define LL_ACCORDIONCTRLTAB_H_ + +#include <string> +#include "llrect.h" + +class LLUICtrl; +class LLUICtrlFactory; +class LLUIImage; +class LLButton; +class LLTextBox; + + + +// LLAccordionCtrlTab is a container for other controls.  +// It has a Header, by clicking on which hosted controls are shown or hidden. +// When hosted controls are show - LLAccordionCtrlTab is expanded. +// When hosted controls are hidden - LLAccordionCtrlTab is collapsed. + +class LLAccordionCtrlTab : public LLUICtrl +{ +// Interface +public: + +	struct Params  +	 : public LLInitParam::Block<Params, LLUICtrl::Params> +	{ +		Optional<bool>			display_children, //expanded or collapsed after initialization +								collapsible; + +		Optional<std::string>	title; + +		Optional<S32>			header_height, +								min_width, +								min_height; + +		// Overlay images (arrows on the left) +		Mandatory<LLUIImage*>	header_expand_img, +								header_expand_img_pressed, +								header_collapse_img, +								header_collapse_img_pressed; + +		// Background images for the accordion tabs +		Mandatory<LLUIImage*>	header_image, +								header_image_over, +								header_image_pressed, +								header_image_focused; + +		Optional<LLUIColor>		header_bg_color, +								header_text_color, +								dropdown_bg_color; + +		Optional<bool>			header_visible; + +		Optional<S32>			padding_left; +		Optional<S32>			padding_right; +		Optional<S32>			padding_top; +		Optional<S32>			padding_bottom; + +		Params(); +	}; + +	typedef LLDefaultChildRegistry child_registry_t; + +	virtual ~LLAccordionCtrlTab(); +	 +	// Registers callback for expand/collapse events. +	boost::signals2::connection setDropDownStateChangedCallback(commit_callback_t cb); + +	// Changes expand/collapse state +	virtual void setDisplayChildren(bool display); + +	// Returns expand/collapse state +	virtual bool getDisplayChildren() const {return mDisplayChildren;}; + +	//set LLAccordionCtrlTab panel +	void		setAccordionView(LLView* panel); +	LLView*		getAccordionView(); + +	bool getCollapsible() {return mCollapsible;}; + +	void setCollapsible(bool collapsible) {mCollapsible = collapsible;}; +	void changeOpenClose(bool is_open); + +	void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close;}; + +	virtual BOOL postBuild(); + +	S32	notifyParent(const LLSD& info); +	S32 notify(const LLSD& info); +	bool notifyChildren(const LLSD& info); + +	void    storeOpenCloseState		(); +	void    restoreOpenCloseState	(); + +protected: +	LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&); +	friend class LLUICtrlFactory; + +// Overrides +public: + +	// Call reshape after changing size +	virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + +	// Changes expand/collapse state and triggers expand/collapse callbacks +	virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + +	virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); +	virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + +	virtual bool addChild(LLView* child, S32 tab_group); + +	bool isExpanded() { return mDisplayChildren; } + +	S32 getHeaderHeight(); + +	// Min size functions + +	void setHeaderVisible(bool value); + +	bool getHeaderVisible() { return mHeaderVisible;} + +	S32 mExpandedHeight; // Height of expanded ctrl. +						 // Used to restore height after expand. + +	S32	getPaddingLeft() const { return mPaddingLeft;} +	S32	getPaddingRight() const { return mPaddingRight;} +	S32	getPaddingTop() const { return mPaddingTop;} +	S32	getPaddingBottom() const { return mPaddingBottom;} + +	void showAndFocusHeader(); + +private: + +	 + +	class LLAccordionCtrlTabHeader; +	LLAccordionCtrlTabHeader* mHeader; //Header + +	bool mDisplayChildren; //Expanded/collapsed +	bool mCollapsible; +	bool mHeaderVisible; + +	bool mCanOpenClose; + +	S32	mPaddingLeft; +	S32	mPaddingRight; +	S32	mPaddingTop; +	S32	mPaddingBottom; + +	bool mStoredOpenCloseState; +	bool mWasStateStored; + + +	LLUIColor mDropdownBGColor; +}; + +#endif diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 527c0a1b87..bd67949c2a 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -46,6 +46,7 @@  #include "llmenugl.h" +#include "llgl.h"  #include "llmath.h"  #include "llrender.h"  #include "llfocusmgr.h" @@ -477,6 +478,7 @@ void LLMenuItemGL::draw( void )  		if (dynamic_cast<LLMenuItemCallGL*>(this))  			debug_count++;  		gGL.color4fv( mHighlightBackground.get().mV ); +  		gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 );  	} diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index db32882438..143f19eea6 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -43,6 +43,7 @@  #include "llerror.h"  #include "lltimer.h" +#include "llaccordionctrltab.h"  #include "llbutton.h"  #include "llmenugl.h"  //#include "llstatusbar.h" @@ -851,14 +852,26 @@ static LLPanel *childGetVisibleTabWithHelp(LLView *parent)  	// look through immediate children first for an active tab with help  	for (child = parent->getFirstChild(); child; child = parent->findNextSibling(child))  	{ +		LLPanel *curTabPanel = NULL; + +		// do we have a tab container?  		LLTabContainer *tab = dynamic_cast<LLTabContainer *>(child);  		if (tab && tab->getVisible())  		{ -			LLPanel *curTabPanel = tab->getCurrentPanel(); -			if (curTabPanel && !curTabPanel->getHelpTopic().empty()) -			{ -				return curTabPanel; -			} +			curTabPanel = tab->getCurrentPanel(); +		} + +		// do we have an accordion tab? +		LLAccordionCtrlTab* accordion = dynamic_cast<LLAccordionCtrlTab *>(child); +		if (accordion && accordion->getDisplayChildren()) +		{ +			curTabPanel = dynamic_cast<LLPanel *>(accordion->getAccordionView()); +		} + +		// if we found a valid tab, does it have a help topic? +		if (curTabPanel && !curTabPanel->getHelpTopic().empty()) +		{ +			return curTabPanel;  		}  	} diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index f7528bc62a..1b6dd1b264 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -101,7 +101,7 @@ std::string LLUrlEntryBase::getLabelFromWikiLink(const std::string &url)  	{  		start++;  	} -	return url.substr(start, url.size()-start-1); +	return unescapeUrl(url.substr(start, url.size()-start-1));  }  std::string LLUrlEntryBase::getUrlFromWikiLink(const std::string &string) diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index 128cd134c1..38cf7124ce 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -545,4 +545,50 @@ namespace tut  				  "XXX [secondlife:///app/teleport/Ahern/50/50/50/ Teleport to Ahern] YYY",  				  "[secondlife:///app/teleport/Ahern/50/50/50/ Teleport to Ahern]");  	} + +	template<> template<> +	void object::test<11>() +	{ +		// +		// test LLUrlEntryHTTPNoProtocol - general URLs without a protocol +		// +		LLUrlEntryHTTPNoProtocol url; +		boost::regex r = url.getPattern(); + +		testRegex("naked .com URL", r, +				  "see google.com", +				  "google.com"); + +		testRegex("naked .org URL", r, +				  "see en.wikipedia.org for details", +				  "en.wikipedia.org"); + +		testRegex("naked .net URL", r, +				  "example.net", +				  "example.net"); + +		testRegex("naked .edu URL (2 instances)", r, +				  "MIT web site is at web.mit.edu and also www.mit.edu", +				  "web.mit.edu"); + +		testRegex("invalid .com URL [1]", r, +				  "..com", +				  ""); + +		testRegex("invalid .com URL [2]", r, +				  "you.come", +				  ""); + +		testRegex("invalid .com URL [3]", r, +				  "recommended", +				  ""); + +		testRegex("invalid .edu URL", r, +				  "hi there scheduled maitenance has begun", +				  ""); + +		testRegex("invalid .net URL", r, +				  "foo.netty", +				  ""); +	}  } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 8918fc3018..62cb8380c0 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -63,8 +63,6 @@ include_directories(      )  set(viewer_SOURCE_FILES -    llaccordionctrl.cpp -    llaccordionctrltab.cpp      llagent.cpp      llagentaccess.cpp      llagentdata.cpp @@ -569,8 +567,6 @@ endif (LINUX)  set(viewer_HEADER_FILES      CMakeLists.txt      ViewerInstall.cmake -    llaccordionctrl.h -    llaccordionctrltab.h      llagent.h      llagentaccess.h      llagentdata.h diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index f49f862045..10a2dd132a 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -95,19 +95,38 @@ public:  	enum ELibraryOutfitFetchStep {  		LOFS_FOLDER = 0,  		LOFS_OUTFITS, +		LOFS_LIBRARY, +		LOFS_IMPORTED,  		LOFS_CONTENTS  	}; -	LLLibraryOutfitsFetch() : mCurrFetchStep(LOFS_FOLDER), mOutfitsPopulated(false) {} +	LLLibraryOutfitsFetch() : mCurrFetchStep(LOFS_FOLDER), mOutfitsPopulated(false)  +	{ +		mMyOutfitsID = LLUUID::null; +		mClothingID = LLUUID::null; +		mLibraryClothingID = LLUUID::null; +		mImportedClothingID = LLUUID::null; +		mImportedClothingName = "Imported Library Clothing"; +	}  	~LLLibraryOutfitsFetch() {} -	virtual void done();	 +	virtual void done();  	void doneIdle(); +	LLUUID mMyOutfitsID; +	void importedFolderFetch();  protected:  	void folderDone(void);  	void outfitsDone(void); +	void libraryDone(void); +	void importedFolderDone(void);  	void contentsDone(void);  	enum ELibraryOutfitFetchStep mCurrFetchStep; -	std::vector< std::pair< LLUUID, std::string > > mOutfits; +	typedef std::vector< std::pair< LLUUID, std::string > > cloth_folder_vec_t; +	cloth_folder_vec_t mLibraryClothingFolders; +	cloth_folder_vec_t mImportedClothingFolders;  	bool mOutfitsPopulated; +	LLUUID mClothingID; +	LLUUID mLibraryClothingID; +	LLUUID mImportedClothingID; +	std::string mImportedClothingName;  };  LLAgentWearables gAgentWearables; @@ -2126,11 +2145,15 @@ void LLAgentWearables::populateMyOutfitsFolder(void)  	// Get the complete information on the items in the inventory and   	// setup an observer that will wait for that to happen.  	LLInventoryFetchDescendentsObserver::folder_ref_t folders; -	const LLUUID my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); +	outfits->mMyOutfitsID = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -	folders.push_back(my_outfits_id); +	folders.push_back(outfits->mMyOutfitsID);  	gInventory.addObserver(outfits);  	outfits->fetchDescendents(folders); +	if (outfits->isEverythingComplete()) +	{ +		outfits->done(); +	}  }  void LLLibraryOutfitsFetch::done() @@ -2144,13 +2167,24 @@ void LLLibraryOutfitsFetch::done()  void LLLibraryOutfitsFetch::doneIdle()  {  	gInventory.addObserver(this); // Add this back in since it was taken out during ::done() +	  	switch (mCurrFetchStep)  	{  		case LOFS_FOLDER:  			folderDone(); +			mCurrFetchStep = LOFS_OUTFITS;  			break;  		case LOFS_OUTFITS:  			outfitsDone(); +			mCurrFetchStep = LOFS_LIBRARY; +			break; +		case LOFS_LIBRARY: +			libraryDone(); +			mCurrFetchStep = LOFS_IMPORTED; +			break; +		case LOFS_IMPORTED: +			importedFolderDone(); +			mCurrFetchStep = LOFS_CONTENTS;  			break;  		case LOFS_CONTENTS:  			contentsDone(); @@ -2172,67 +2206,217 @@ void LLLibraryOutfitsFetch::doneIdle()  void LLLibraryOutfitsFetch::folderDone(void)  { -	// Early out if we already have items in My Outfits.  	LLInventoryModel::cat_array_t cat_array;  	LLInventoryModel::item_array_t wearable_array; -	gInventory.collectDescendents(mCompleteFolders.front(), cat_array, wearable_array,  +	gInventory.collectDescendents(mMyOutfitsID, cat_array, wearable_array,   								  LLInventoryModel::EXCLUDE_TRASH); +	 +	// Early out if we already have items in My Outfits.  	if (cat_array.count() > 0 || wearable_array.count() > 0)  	{  		mOutfitsPopulated = true;  		return;  	} -	// Get the UUID of the library's clothing folder -	const LLUUID library_clothing_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING, false, true); +	mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); +	mLibraryClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING, false, true);  	mCompleteFolders.clear();  	// Get the complete information on the items in the inventory.  	LLInventoryFetchDescendentsObserver::folder_ref_t folders; -	folders.push_back(library_clothing_id); -	mCurrFetchStep = LOFS_OUTFITS; +	folders.push_back(mClothingID); +	folders.push_back(mLibraryClothingID);  	fetchDescendents(folders); +	if (isEverythingComplete()) +	{ +		done(); +	}  }  void LLLibraryOutfitsFetch::outfitsDone(void)  {  	LLInventoryModel::cat_array_t cat_array;  	LLInventoryModel::item_array_t wearable_array; -	gInventory.collectDescendents(mCompleteFolders.front(), cat_array, wearable_array,  -								  LLInventoryModel::EXCLUDE_TRASH); -	  	LLInventoryFetchDescendentsObserver::folder_ref_t folders; +	// Collect the contents of the Library's Clothing folder +	gInventory.collectDescendents(mLibraryClothingID, cat_array, wearable_array,  +								  LLInventoryModel::EXCLUDE_TRASH); +	  	llassert(cat_array.count() > 0);  	for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin();  		 iter != cat_array.end();  		 ++iter)  	{  		const LLViewerInventoryCategory *cat = iter->get(); +		 +		// Get the names and id's of every outfit in the library, except for ruth and other "misc" outfits.  		if (cat->getName() != "More Outfits" && cat->getName() != "Ruth")  		{ +			// Get the name of every outfit in the library   			folders.push_back(cat->getUUID()); -			mOutfits.push_back(std::make_pair(cat->getUUID(), cat->getName())); +			mLibraryClothingFolders.push_back(std::make_pair(cat->getUUID(), cat->getName())); +		} +	} +	 +	// Collect the contents of your Inventory Clothing folder +	cat_array.clear(); +	wearable_array.clear(); +	gInventory.collectDescendents(mClothingID, cat_array, wearable_array,  +								  LLInventoryModel::EXCLUDE_TRASH); + +	// Check if you already have an "Imported Library Clothing" folder +	for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); +		 iter != cat_array.end(); +		 ++iter) +	{ +		const LLViewerInventoryCategory *cat = iter->get(); +		if (cat->getName() == mImportedClothingName) +		{ +			mImportedClothingID = cat->getUUID();  		}  	} +	  	mCompleteFolders.clear(); +	 +	fetchDescendents(folders); +	if (isEverythingComplete()) +	{ +		done(); +	} +} + +class LLLibraryOutfitsCopyDone: public LLInventoryCallback +{ +public: +	LLLibraryOutfitsCopyDone(LLLibraryOutfitsFetch * fetcher): +	mFireCount(0), mLibraryOutfitsFetcher(fetcher) +	{ +	} +	 +	virtual ~LLLibraryOutfitsCopyDone() +	{ +		if (mLibraryOutfitsFetcher) +		{ +			gInventory.addObserver(mLibraryOutfitsFetcher); +			mLibraryOutfitsFetcher->done(); +		} +	} +	 +	/* virtual */ void fire(const LLUUID& inv_item) +	{ +		mFireCount++; +	} +private: +	U32 mFireCount; +	LLLibraryOutfitsFetch * mLibraryOutfitsFetcher; +}; -	mCurrFetchStep = LOFS_CONTENTS; +void LLLibraryOutfitsFetch::libraryDone(void) +{ +	// Copy the clothing folders from the library into the imported clothing folder if necessary. +	if (mImportedClothingID == LLUUID::null) +	{ +		gInventory.removeObserver(this); +		LLPointer<LLInventoryCallback> copy_waiter = new LLLibraryOutfitsCopyDone(this); +		mImportedClothingID = gInventory.createNewCategory(mClothingID, +														   LLFolderType::FT_NONE, +														   mImportedClothingName); +		 +		for (cloth_folder_vec_t::const_iterator iter = mLibraryClothingFolders.begin(); +			 iter != mLibraryClothingFolders.end(); +			 ++iter) +		{ +			LLUUID folder_id = gInventory.createNewCategory(mImportedClothingID, +															LLFolderType::FT_NONE, +															iter->second); +			LLAppearanceManager::getInstance()->shallowCopyCategory(iter->first, folder_id, copy_waiter); +		} +	} +	else +	{ +		// Skip straight to fetching the contents of the imported folder +		importedFolderFetch(); +	} +} + +void LLLibraryOutfitsFetch::importedFolderFetch(void) +{ +	// Fetch the contents of the Imported Clothing Folder +	LLInventoryFetchDescendentsObserver::folder_ref_t folders; +	folders.push_back(mImportedClothingID); +	 +	mCompleteFolders.clear(); +	  	fetchDescendents(folders); +	if (isEverythingComplete()) +	{ +		done(); +	}  } -void LLLibraryOutfitsFetch::contentsDone(void) +void LLLibraryOutfitsFetch::importedFolderDone(void)  { -	for(S32 i = 0; i < (S32)mOutfits.size(); ++i) +	LLInventoryModel::cat_array_t cat_array; +	LLInventoryModel::item_array_t wearable_array; +	LLInventoryFetchDescendentsObserver::folder_ref_t folders; +	 +	// Collect the contents of the Imported Clothing folder +	gInventory.collectDescendents(mImportedClothingID, cat_array, wearable_array,  +								  LLInventoryModel::EXCLUDE_TRASH); +	 +	for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); +		 iter != cat_array.end(); +		 ++iter) +	{ +		const LLViewerInventoryCategory *cat = iter->get(); +		 +		// Get the name of every imported outfit +		folders.push_back(cat->getUUID()); +		mImportedClothingFolders.push_back(std::make_pair(cat->getUUID(), cat->getName())); +	} +	 +	mCompleteFolders.clear(); +	fetchDescendents(folders); +	if (isEverythingComplete()) +	{ +		done(); +	} +} + +void LLLibraryOutfitsFetch::contentsDone(void) +{		 +	LLInventoryModel::cat_array_t cat_array; +	LLInventoryModel::item_array_t wearable_array; +	 +	for (cloth_folder_vec_t::const_iterator folder_iter = mImportedClothingFolders.begin(); +		 folder_iter != mImportedClothingFolders.end(); +		 ++folder_iter)  	{  		// First, make a folder in the My Outfits directory. -		const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -		LLUUID folder_id = gInventory.createNewCategory(parent_id, -														LLFolderType::FT_OUTFIT, -														mOutfits[i].second); -		LLAppearanceManager::getInstance()->shallowCopyCategory(mOutfits[i].first, folder_id, NULL); +		LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, folder_iter->second); +		 +		cat_array.clear(); +		wearable_array.clear(); +		// Collect the contents of each imported clothing folder, so we can create new outfit links for it +		gInventory.collectDescendents(folder_iter->first, cat_array, wearable_array,  +									  LLInventoryModel::EXCLUDE_TRASH); +		 +		for (LLInventoryModel::item_array_t::const_iterator wearable_iter = wearable_array.begin(); +			 wearable_iter != wearable_array.end(); +			 ++wearable_iter) +		{ +			const LLViewerInventoryItem *item = wearable_iter->get(); +			link_inventory_item(gAgent.getID(), +								item->getLinkedUUID(), +								new_outfit_folder_id, +								item->getName(), +								LLAssetType::AT_LINK, +								NULL); +		}  	} +  	mOutfitsPopulated = true;  } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e0356bc091..fb1bded795 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -313,6 +313,7 @@ void init_default_trans_args()  {  	default_trans_args.insert("SECOND_LIFE"); // World  	default_trans_args.insert("APP_NAME"); +	default_trans_args.insert("CAPITALIZED_APP_NAME");  	default_trans_args.insert("SECOND_LIFE_GRID");  	default_trans_args.insert("SUPPORT_SITE");  } diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index dac3280575..cda3e3a419 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -576,10 +576,10 @@ void LLChatHistory::appendMessage(const LLChat& chat, const bool use_plain_text_  		style_params.font.style = "ITALIC";  		if (chat.mFromName.size() > 0) -			mEditor->appendText(chat.mFromName + " ", TRUE, style_params); +			mEditor->appendText(chat.mFromName, TRUE, style_params);  		// Ensure that message ends with NewLine, to avoid losing of new lines  		// while copy/paste from text chat. See EXT-3263. -		mEditor->appendText(chat.mText.substr(4) + NEW_LINE, FALSE, style_params); +		mEditor->appendText(chat.mText.substr(3) + NEW_LINE, FALSE, style_params);  	}  	else  	{ diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index 60a37ac4af..9ce3f29853 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -170,10 +170,7 @@ void LLNearbyChatToastPanel::init(LLSD& notification)  	std::string str_sender; -	if(gAgentID != mFromID) -		str_sender = fromName; -	else -		str_sender = LLTrans::getString("You"); +	str_sender = fromName;  	str_sender+=" "; diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 3042fbc6ec..0964ad7f91 100644 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -64,6 +64,8 @@  // summary which only shows available & correct information  #define USE_SIMPLE_SUMMARY +const S32 SIZE_OF_ONE_KB = 1024; +  LLFloaterScriptLimits::LLFloaterScriptLimits(const LLSD& seed)  	: LLFloater(seed)  { @@ -130,7 +132,6 @@ void LLFloaterScriptLimits::refresh()  	}  } -  ///----------------------------------------------------------------------------  // Base class for panels  ///---------------------------------------------------------------------------- @@ -331,6 +332,57 @@ void LLPanelScriptLimitsRegionMemory::setErrorStatus(U32 status, const std::stri  	llerrs << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl;  } +// callback from the name cache with an owner name to add to the list +void LLPanelScriptLimitsRegionMemory::onNameCache( +						 const LLUUID& id, +						 const std::string& first_name, +						 const std::string& last_name) +{ +	std::string name = first_name + " " + last_name; + +	LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list");	 +	std::vector<LLSD>::iterator id_itor; +	for (id_itor = mObjectListItems.begin(); id_itor != mObjectListItems.end(); ++id_itor) +	{ +		LLSD element = *id_itor; +		if(element["owner_id"].asUUID() == id) +		{ +			LLScrollListItem* item = list->getItem(element["id"].asUUID()); + +			if(item) +			{ +				item->getColumn(2)->setValue(LLSD(name)); +				element["columns"][2]["value"] = name; +			} +		} +	} + +	// fill in the url's tab if needed, all urls must have memory so we can do it all here +	LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); +	if(instance) +	{ +		LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); +		LLPanelScriptLimitsRegionMemory* panel = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_urls_panel"); + +		LLScrollListCtrl *list = panel->getChild<LLScrollListCtrl>("scripts_list");	 +		std::vector<LLSD>::iterator id_itor; +		for (id_itor = mObjectListItems.begin(); id_itor != mObjectListItems.end(); ++id_itor) +		{ +			LLSD element = *id_itor; +			if(element["owner_id"].asUUID() == id) +			{ +				LLScrollListItem* item = list->getItem(element["id"].asUUID()); + +				if(item) +				{ +					item->getColumn(2)->setValue(LLSD(name)); +					element["columns"][2]["value"] = name; +				} +			} +		} +	} +} +  void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content)  {  	LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list"); @@ -345,22 +397,40 @@ void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content)  	S32 total_objects = 0;  	S32 total_size = 0; +	std::vector<LLUUID> names_requested; +  	for(S32 i = 0; i < number_parcels; i++)  	{  		std::string parcel_name = content["parcels"][i]["name"].asString(); -		 +		LLUUID parcel_id = content["parcels"][i]["id"].asUUID();  		S32 number_objects = content["parcels"][i]["objects"].size();  		for(S32 j = 0; j < number_objects; j++)  		{ -			S32 size = content["parcels"][i]["objects"][j]["resources"]["memory"].asInteger() / 1024; +			S32 size = content["parcels"][i]["objects"][j]["resources"]["memory"].asInteger() / SIZE_OF_ONE_KB;  			total_size += size;  			std::string name_buf = content["parcels"][i]["objects"][j]["name"].asString();  			LLUUID task_id = content["parcels"][i]["objects"][j]["id"].asUUID(); +			LLUUID owner_id = content["parcels"][i]["objects"][j]["owner_id"].asUUID(); +			 +			std::string owner_buf; +			 +			BOOL name_is_cached = gCacheName->getFullName(owner_id, owner_buf); +			if(!name_is_cached) +			{ +				if(std::find(names_requested.begin(), names_requested.end(), owner_id) == names_requested.end()) +				{ +					names_requested.push_back(owner_id); +					gCacheName->get(owner_id, TRUE, +					boost::bind(&LLPanelScriptLimitsRegionMemory::onNameCache, +						this, _1, _2, _3)); +				} +			}  			LLSD element;  			element["id"] = task_id; +			element["owner_id"] = owner_id;  			element["columns"][0]["column"] = "size";  			element["columns"][0]["value"] = llformat("%d", size);  			element["columns"][0]["font"] = "SANSSERIF"; @@ -368,18 +438,18 @@ void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content)  			element["columns"][1]["value"] = name_buf;  			element["columns"][1]["font"] = "SANSSERIF";  			element["columns"][2]["column"] = "owner"; -			element["columns"][2]["value"] = ""; +			element["columns"][2]["value"] = owner_buf;  			element["columns"][2]["font"] = "SANSSERIF";  			element["columns"][3]["column"] = "location";  			element["columns"][3]["value"] = parcel_name;  			element["columns"][3]["font"] = "SANSSERIF"; -			list->addElement(element); -			mObjectListIDs.push_back(task_id); +			list->addElement(element, ADD_SORTED); +			mObjectListItems.push_back(element);  			total_objects++;  		}  	} -	 +  	mParcelMemoryUsed =total_size;  	mGotParcelMemoryUsed = TRUE;  	populateParcelMemoryText(); @@ -556,7 +626,7 @@ void LLPanelScriptLimitsRegionMemory::clearList()  	childSetValue("memory_used", LLSD(msg_empty_string));  	childSetValue("parcels_listed", LLSD(msg_empty_string)); -	mObjectListIDs.clear(); +	mObjectListItems.clear();  }  // static @@ -728,7 +798,7 @@ void LLPanelScriptLimitsRegionURLs::setRegionDetails(LLSD content)  	S32 total_objects = 0;  	S32 total_size = 0; - +	  	for(S32 i = 0; i < number_parcels; i++)  	{  		std::string parcel_name = content["parcels"][i]["name"].asString(); @@ -744,6 +814,10 @@ void LLPanelScriptLimitsRegionURLs::setRegionDetails(LLSD content)  				std::string name_buf = content["parcels"][i]["objects"][j]["name"].asString();  				LLUUID task_id = content["parcels"][i]["objects"][j]["id"].asUUID(); +				LLUUID owner_id = content["parcels"][i]["objects"][j]["owner_id"].asUUID(); + +				std::string owner_buf; +				gCacheName->getFullName(owner_id, owner_buf); //dont care if this fails as the memory tab will request and fill the field  				LLSD element; @@ -755,14 +829,14 @@ void LLPanelScriptLimitsRegionURLs::setRegionDetails(LLSD content)  				element["columns"][1]["value"] = name_buf;  				element["columns"][1]["font"] = "SANSSERIF";  				element["columns"][2]["column"] = "owner"; -				element["columns"][2]["value"] = ""; +				element["columns"][2]["value"] = owner_buf;  				element["columns"][2]["font"] = "SANSSERIF";  				element["columns"][3]["column"] = "location";  				element["columns"][3]["value"] = parcel_name;  				element["columns"][3]["font"] = "SANSSERIF";  				list->addElement(element); -				mObjectListIDs.push_back(task_id); +				mObjectListItems.push_back(element);  				total_objects++;  			}  		} @@ -868,7 +942,7 @@ void LLPanelScriptLimitsRegionURLs::clearList()  	childSetValue("urls_used", LLSD(msg_empty_string));  	childSetValue("parcels_listed", LLSD(msg_empty_string)); -	mObjectListIDs.clear(); +	mObjectListItems.clear();  }  // static @@ -982,7 +1056,7 @@ void LLPanelScriptLimitsAttachment::setAttachmentDetails(LLSD content)  			S32 size = 0;  			if(content["attachments"][i]["objects"][j]["resources"].has("memory"))  			{ -				size = content["attachments"][i]["objects"][j]["resources"]["memory"].asInteger(); +				size = content["attachments"][i]["objects"][j]["resources"]["memory"].asInteger() / SIZE_OF_ONE_KB;  			}  			S32 urls = 0;  			if(content["attachments"][i]["objects"][j]["resources"].has("urls")) @@ -1059,3 +1133,4 @@ void LLPanelScriptLimitsAttachment::onClickRefresh(void* userdata)  		return;  	}  } + diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h index 88239136e3..7e2b536eb6 100644 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -54,12 +54,12 @@ public:  	// from LLPanel  	virtual void refresh(); -	 +  private: -	 +  	LLFloaterScriptLimits(const LLSD& seed);  	~LLFloaterScriptLimits(); -	 +  protected:  	LLTabContainer* mTab; @@ -167,13 +167,17 @@ public:  private: +	void onNameCache(	 const LLUUID& id, +						 const std::string& first_name, +						 const std::string& last_name); +  	LLUUID mParcelId;  	BOOL mGotParcelMemoryUsed;  	BOOL mGotParcelMemoryMax;  	S32 mParcelMemoryMax;  	S32 mParcelMemoryUsed; -	std::vector<LLUUID> mObjectListIDs; +	std::vector<LLSD> mObjectListItems;  protected: @@ -218,7 +222,7 @@ private:  	S32 mParcelURLsMax;  	S32 mParcelURLsUsed; -	std::vector<LLUUID> mObjectListIDs; +	std::vector<LLSD> mObjectListItems;  protected: diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index c6d9fee630..a7401fdb6f 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -32,6 +32,9 @@   */  #include "llviewerprecompiledheaders.h" + +#include "llcommandhandler.h" +#include "llfloaterreg.h"  #include "llfloatersearch.h"  #include "llmediactrl.h"  #include "lllogininstance.h" @@ -41,6 +44,42 @@  #include "llviewercontrol.h"  #include "llweb.h" +// support secondlife:///app/search/{CATEGORY}/{QUERY} SLapps +class LLSearchHandler : public LLCommandHandler +{ +public: +	// requires trusted browser to trigger +	LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_THROTTLE) { } +	bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) +	{ +		const size_t parts = tokens.size(); + +		// get the (optional) category for the search +		std::string category; +		if (parts > 0) +		{ +			category = tokens[0].asString(); +		} + +		// get the (optional) search string +		std::string search_text; +		if (parts > 1) +		{ +			search_text = tokens[1].asString(); +		} + +		// create the LLSD arguments for the search floater +		LLSD args; +		args["category"] = category; +		args["id"] = LLURI::unescape(search_text); + +		// open the search floater and perform the requested search +		LLFloaterReg::showInstance("search", args); +		return true; +	} +}; +LLSearchHandler gSearchHandler; +  LLFloaterSearch::LLFloaterSearch(const LLSD& key) :  	LLFloater(key),  	LLViewerMediaObserver(), diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 1ab111a41d..9aed403991 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -822,10 +822,11 @@ void LLFolderView::clearSelection()  	mSelectThisID.setNull();  } -BOOL LLFolderView::getSelectionList(std::set<LLUUID> &selection) +BOOL LLFolderView::getSelectionList(std::set<LLUUID> &selection) const  { -	selected_items_t::iterator item_it; -	for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) +	for (selected_items_t::const_iterator item_it = mSelectedItems.begin();  +		 item_it != mSelectedItems.end();  +		 ++item_it)  	{  		selection.insert((*item_it)->getListener()->getUUID());  	} diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 2598af4df4..89e1865e35 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -162,7 +162,7 @@ public:  	virtual S32 extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray<LLFolderViewItem*>& items); -	virtual BOOL getSelectionList(std::set<LLUUID> &selection); +	virtual BOOL getSelectionList(std::set<LLUUID> &selection) const;  	// make sure if ancestor is selected, descendents are not  	void sanitizeSelection(); diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h index 14fac5bdf9..be8e73a5a9 100644 --- a/indra/newview/llfolderviewitem.h +++ b/indra/newview/llfolderviewitem.h @@ -235,7 +235,7 @@ public:  	virtual void recursiveDeselect(BOOL deselect_self);  	// gets multiple-element selection -	virtual BOOL getSelectionList(std::set<LLUUID> &selection){return TRUE;} +	virtual BOOL getSelectionList(std::set<LLUUID> &selection) const {return TRUE;}  	// Returns true is this object and all of its children can be removed (deleted by user)  	virtual BOOL isRemovable(); @@ -302,7 +302,7 @@ public:  	// Show children (unfortunate that this is called "open")  	virtual void setOpen(BOOL open = TRUE) {}; -	virtual BOOL isOpen() { return FALSE; } +	virtual BOOL isOpen() const { return FALSE; }  	virtual LLFolderView*	getRoot();  	BOOL			isDescendantOf( const LLFolderViewFolder* potential_ancestor ); @@ -497,7 +497,7 @@ public:  	virtual void setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse = RECURSE_NO);  	// Get the current state of the folder. -	virtual BOOL isOpen() { return mIsOpen; } +	virtual BOOL isOpen() const { return mIsOpen; }  	// special case if an object is dropped on the child.  	BOOL handleDragAndDropFromChild(MASK mask, diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index fdc5d14d97..b05568f353 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -595,7 +595,7 @@ void LLIMFloater::updateMessages()  			std::string time = msg["time"].asString();  			LLUUID from_id = msg["from_id"].asUUID(); -			std::string from = from_id != gAgentID ? msg["from"].asString() : LLTrans::getString("You"); +			std::string from = msg["from"].asString();  			std::string message = msg["message"].asString();  			LLChat chat; diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 5f9d479b3e..22451998c6 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -278,7 +278,7 @@ void LLInspectAvatar::onOpen(const LLSD& data)  	getChild<LLUICtrl>("gear_self_btn")->setVisible(self);  	getChild<LLUICtrl>("gear_btn")->setVisible(!self); -	 +  	// Position the inspector relative to the mouse cursor  	// Similar to how tooltips are positioned  	// See LLToolTipMgr::createToolTip @@ -534,6 +534,7 @@ void LLInspectAvatar::updateVolumeSlider()  		// By convention, we only display and toggle voice mutes, not all mutes  		bool is_muted = LLMuteList::getInstance()->  							isMuted(mAvatarID, LLMute::flagVoiceChat); +	bool is_self = (mAvatarID == gAgent.getID());  		LLUICtrl* mute_btn = getChild<LLUICtrl>("mute_btn"); @@ -541,9 +542,12 @@ void LLInspectAvatar::updateVolumeSlider()  		mute_btn->setEnabled( !is_linden);  		mute_btn->setValue( is_muted ); +	mute_btn->setVisible( voice_enabled && !is_self );  		LLUICtrl* volume_slider = getChild<LLUICtrl>("volume_slider");  		volume_slider->setEnabled( !is_muted ); +	volume_slider->setVisible( voice_enabled && !is_self ); +  		const F32 DEFAULT_VOLUME = 0.5f;  		F32 volume;  		if (is_muted) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 2a395d79dc..20d7f5214b 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2074,7 +2074,12 @@ void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model  {  	if ("open" == action)  	{ -		openItem(); +		LLFolderViewFolder *f = dynamic_cast<LLFolderViewFolder *>(folder->getItemByID(mUUID)); +		if (f) +		{ +			f->setOpen(TRUE); +		} +		  		return;  	}  	else if ("paste" == action) diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index fc9654e9ad..92f19c9232 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -59,9 +59,6 @@ const static std::string NEW_LINE_SPACE_PREFIX("\n ");  const static std::string TWO_SPACES("  ");  const static std::string MULTI_LINE_PREFIX(" "); -//viewer 1.23 may have used "You" for Agent's entries -const static std::string YOU("You"); -  /**   *  Chat log lines - timestamp and name are optional but message text is mandatory.   * diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index e7043b2d00..fc0e51b76d 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -178,7 +178,7 @@ void	LLNearbyChat::addMessage(const LLChat& chat,bool archive)  	if (!chat.mMuted)  	{ -		tmp_chat.mFromName = chat.mFromID != gAgentID ? chat.mFromName : LLTrans::getString("You"); +		tmp_chat.mFromName = chat.mFromName;  		if (chat.mChatStyle == CHAT_STYLE_IRC)  		{ diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index f3d6dbbb46..fb898f7cdf 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -594,8 +594,8 @@ void LLPanelAvatarProfile::processGroupProperties(const LLAvatarGroups* avatar_g  		if (it != mGroups.begin())  			groups += ", "; -		 -		std::string group_url="[secondlife:///app/group/" + it->second.asString() + "/about " + it->first + "]"; +		std::string group_name = LLURI::escape(it->first); +		std::string group_url="[secondlife:///app/group/" + it->second.asString() + "/about " + group_name + "]";  		groups += group_url;  	} diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index a1c12412b5..550fee71bf 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -181,6 +181,10 @@ void LLPanelOutfitsInventory::onNew()  {  	const std::string& outfit_name = LLViewerFolderType::lookupNewCategoryName(LLFolderType::FT_OUTFIT);  	LLUUID outfit_folder = gAgentWearables.makeNewOutfitLinks(outfit_name); +	if (mAppearanceTabs) +	{ +		mAppearanceTabs->selectTabByName("outfitslist_tab"); +	}  }  void LLPanelOutfitsInventory::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action) @@ -412,8 +416,7 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)  		return (getCorrectListenerForAction() != NULL) && hasItemsSelected();  	} -	if (command_name == "wear" || -		command_name == "make_outfit") +	if (command_name == "wear")  	{  		const BOOL is_my_outfits = (mActivePanel->getName() == "outfitslist_tab");  		if (!is_my_outfits) @@ -421,6 +424,10 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)  			return FALSE;  		}  	} +	if (command_name == "make_outfit") +	{ +		return TRUE; +	}  	if (command_name == "edit" ||   		command_name == "add" diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 0ae62843ac..77a370cc3f 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -62,6 +62,7 @@ public:  	{  		mPanel->inventoryFetched();  		gInventory.removeObserver(this); +		delete this;  	}  private:  	LLSidepanelAppearance *mPanel; @@ -94,14 +95,12 @@ LLSidepanelAppearance::LLSidepanelAppearance() :  	mLookInfo(NULL),  	mCurrOutfitPanel(NULL)  { -	//LLUICtrlFactory::getInstance()->buildPanel(this, "panel_appearance.xml"); // Called from LLRegisterPanelClass::defaultPanelClassBuilder() -	mFetchWorn = new LLCurrentlyWornFetchObserver(this); -	 -	mOutfitRenameWatcher = new LLWatchForOutfitRenameObserver(this);  }  LLSidepanelAppearance::~LLSidepanelAppearance()  { +	gInventory.removeObserver(mOutfitRenameWatcher); +	delete mOutfitRenameWatcher;  }  // virtual @@ -156,6 +155,7 @@ BOOL LLSidepanelAppearance::postBuild()  	mCurrOutfitPanel = getChild<LLPanel>("panel_currentlook"); +	mOutfitRenameWatcher = new LLWatchForOutfitRenameObserver(this);  	gInventory.addObserver(mOutfitRenameWatcher);  	return TRUE; @@ -389,16 +389,17 @@ void LLSidepanelAppearance::fetchInventory()  		}  	} -	mFetchWorn->fetchItems(ids); +	LLCurrentlyWornFetchObserver *fetch_worn = new LLCurrentlyWornFetchObserver(this); +	fetch_worn->fetchItems(ids);  	// If no items to be fetched, done will never be triggered.  	// TODO: Change LLInventoryFetchObserver::fetchItems to trigger done() on this condition. -	if (mFetchWorn->isEverythingComplete()) +	if (fetch_worn->isEverythingComplete())  	{ -		mFetchWorn->done(); +		fetch_worn->done();  	}  	else  	{ -		gInventory.addObserver(mFetchWorn); +		gInventory.addObserver(fetch_worn);  	}  } diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 6ca6734598..514d8facb4 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -2460,7 +2460,6 @@ void renderOctree(LLSpatialGroup* group)  	gGL.color4fv(col.mV);  	drawBox(group->mObjectBounds[0], group->mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f)); -	glDepthMask(GL_TRUE);  	gGL.setSceneBlendType(LLRender::BT_ALPHA);  	if (group->mBuilt <= 0.f) diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 7e8c8eb92e..9671b9e5dc 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -48,12 +48,15 @@  #include "llviewerwindow.h"  #include "llfocusmgr.h"  #include "llcallbacklist.h" +#include "llparcel.h" +#include "llaudioengine.h"  // for gAudiop  #include "llevent.h"		// LLSimpleListener  #include "llnotificationsutil.h"  #include "lluuid.h"  #include "llkeyboard.h"  #include "llmutelist.h" +#include "llfirstuse.h"  #include <boost/bind.hpp>	// for SkinFolder listener  #include <boost/signals2.hpp> @@ -708,6 +711,8 @@ void LLViewerMedia::updateMedia(void *dummy_arg)  	std::vector<LLViewerMediaImpl*> proximity_order; +	bool inworld_media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); +	bool needs_first_run = LLViewerMedia::needsMediaFirstRun();  	U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal");  	U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal");  	U32 max_low = gSavedSettings.getU32("PluginInstancesLow"); @@ -822,6 +827,21 @@ void LLViewerMedia::updateMedia(void *dummy_arg)  			new_priority = LLPluginClassMedia::PRIORITY_LOW;  		} +		if(!inworld_media_enabled) +		{ +			// If inworld media is locked out, force all inworld media to stay unloaded. +			if(!pimpl->getUsedInUI()) +			{ +				new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; +				if(needs_first_run) +				{ +					// Don't do this more than once in this loop. +					needs_first_run = false; +					LLViewerMedia::displayMediaFirstRun(); +				} +			} +		} +		  		pimpl->setPriority(new_priority);  		if(pimpl->getUsedInUI()) @@ -888,6 +908,61 @@ void LLViewerMedia::cleanupClass()  	gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, NULL);  } + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::needsMediaFirstRun() +{ +	return gWarningSettings.getBOOL("FirstStreamingMedia"); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::displayMediaFirstRun() +{ +	gWarningSettings.setBOOL("FirstStreamingMedia", FALSE); + +	LLNotificationsUtil::add("ParcelCanPlayMedia", LLSD(), LLSD(), +		boost::bind(firstRunCallback, _1, _2)); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::firstRunCallback(const LLSD& notification, const LLSD& response) +{ +	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +	if (option == 0) +	{ +		// user has elected to automatically play media. +		gSavedSettings.setBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING, TRUE); +		gSavedSettings.setBOOL("AudioStreamingVideo", TRUE); +		gSavedSettings.setBOOL("AudioStreamingMusic", TRUE); +		gSavedSettings.setBOOL("AudioStreamingMedia", TRUE); + +		LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); +				 +		if (parcel) +		{ +			// play media right now, if available +			LLViewerParcelMedia::play(parcel); +		 +			// play music right now, if available +			std::string music_url = parcel->getMusicURL(); +			if (gAudiop && !music_url.empty()) +				gAudiop->startInternetStream(music_url); +		} +	} +	else +	{ +		gSavedSettings.setBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING, FALSE); +		gSavedSettings.setBOOL("AudioStreamingMedia", FALSE); +		gSavedSettings.setBOOL("AudioStreamingVideo", FALSE); +		gSavedSettings.setBOOL("AudioStreamingMusic", FALSE); +	} +	return false; +} + +  //////////////////////////////////////////////////////////////////////////////////////////  // LLViewerMediaImpl  ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 5e4dd8ff30..3ce9f1887c 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -115,6 +115,12 @@ class LLViewerMedia  		// This is the comparitor used to sort the list.  		static bool priorityComparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2); +		 +		// For displaying the media first-run dialog. +		static bool needsMediaFirstRun(); +		static void displayMediaFirstRun(); +		static bool firstRunCallback(const LLSD& notification, const LLSD& response); +  };  // Implementation functions not exported into header file @@ -123,7 +129,10 @@ class LLViewerMediaImpl  {  	LOG_CLASS(LLViewerMediaImpl);  public: - +	 +	friend class LLViewerMedia; +	friend class LLMimeDiscoveryResponder; +	  	LLViewerMediaImpl(  		const LLUUID& texture_id,  		S32 media_width,  @@ -202,11 +211,15 @@ public:  	bool isMediaPaused();  	bool hasMedia() const;  	bool isMediaFailed() const { return mMediaSourceFailed; }; +	void setMediaFailed(bool val) { mMediaSourceFailed = val; }  	void resetPreviousMediaState();  	void setDisabled(bool disabled);  	bool isMediaDisabled() const { return mIsDisabled; }; - +	 +	void setInNearbyMediaList(bool in_list) { mInNearbyMediaList = in_list; } +	bool getInNearbyMediaList() { return mInNearbyMediaList; } +	  	// returns true if this instance should not be loaded (disabled, muted object, crashed, etc.)  	bool isForcedUnloaded() const; @@ -311,7 +324,7 @@ public:  	void setNavState(EMediaNavState state);  	void cancelMimeTypeProbe(); -public: +private:  	// a single media url with some data and an impl.  	LLPluginClassMedia* mMediaSource;  	LLUUID mTextureId; diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 0f7903a7a5..56dee6b34c 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -56,10 +56,6 @@ LLUUID LLViewerParcelMedia::sMediaRegionID;  viewer_media_t LLViewerParcelMedia::sMediaImpl; -// Local functions -bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel); - -  // static  void LLViewerParcelMedia::initClass()  { @@ -112,12 +108,10 @@ void LLViewerParcelMedia::update(LLParcel* parcel)  			// First use warning  			if( (!mediaUrl.empty() ||  			     !parcel->getMusicURL().empty()) -			    && gWarningSettings.getBOOL("FirstStreamingMedia") ) +			    && LLViewerMedia::needsMediaFirstRun())  			{ -				LLNotificationsUtil::add("ParcelCanPlayMedia", LLSD(), LLSD(), -					boost::bind(callback_play_media, _1, _2, parcel)); +				LLViewerMedia::displayMediaFirstRun();  				return; -  			}  			// if we have a current (link sharing) url, use it instead @@ -591,36 +585,6 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent  	};  } -bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel) -{ -	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); -	if (option == 0) -	{ -		// user has elected to automatically play media. -		gSavedSettings.setBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING, TRUE); -		gSavedSettings.setBOOL("AudioStreamingVideo", TRUE); -		gSavedSettings.setBOOL("AudioStreamingMusic", TRUE); -		if(!gSavedSettings.getBOOL("AudioStreamingMedia"))  -			gSavedSettings.setBOOL("AudioStreamingMedia", TRUE); -		// play media right now, if available -		LLViewerParcelMedia::play(parcel); -		// play music right now, if available -		if (parcel) -		{ -			std::string music_url = parcel->getMusicURL(); -			if (gAudiop && !music_url.empty()) -				gAudiop->startInternetStream(music_url); -		} -	} -	else -	{ -		gSavedSettings.setBOOL("AudioStreamingVideo", FALSE); -		gSavedSettings.setBOOL("AudioStreamingMusic", FALSE); -	} -	gWarningSettings.setBOOL("FirstStreamingMedia", FALSE); -	return false; -} -  // TODO: observer  /*  void LLViewerParcelMediaNavigationObserver::onNavigateComplete( const EventType& event_in ) diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp index 1b79b47905..ad2723b66b 100644 --- a/indra/newview/llviewerparcelmediaautoplay.cpp +++ b/indra/newview/llviewerparcelmediaautoplay.cpp @@ -35,6 +35,7 @@  #include "llviewerparcelmedia.h"  #include "llviewercontrol.h"  #include "llviewermedia.h" +#include "llviewerregion.h"  #include "llparcel.h"  #include "llviewerparcelmgr.h"  #include "lluuid.h" @@ -48,6 +49,8 @@ const F32 AUTOPLAY_SPEED = 0.1f;        // how slow should the agent be moving t  LLViewerParcelMediaAutoPlay::LLViewerParcelMediaAutoPlay() :  	LLEventTimer(1), +	 +	mLastParcelID(-1),  	mPlayed(FALSE),  	mTimeInParcel(0)  { @@ -81,9 +84,18 @@ void LLViewerParcelMediaAutoPlay::playStarted()  BOOL LLViewerParcelMediaAutoPlay::tick()  {  	LLParcel *this_parcel = NULL; +	LLViewerRegion *this_region = NULL;  	std::string this_media_url;  	LLUUID this_media_texture_id;  	S32 this_parcel_id = 0; +	LLUUID this_region_id; + +	this_region = gAgent.getRegion(); +	 +	if (this_region) +	{ +		this_region_id = this_region->getRegionID(); +	}  	this_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); @@ -96,12 +108,14 @@ BOOL LLViewerParcelMediaAutoPlay::tick()  		this_parcel_id = this_parcel->getLocalID();  	} -	if (this_parcel_id != mLastParcelID) +	if (this_parcel_id != mLastParcelID || +	    this_region_id != mLastRegionID)  	{  		// we've entered a new parcel  		mPlayed    = FALSE;                   // we haven't autoplayed yet  		mTimeInParcel = 0;                    // reset our timer  		mLastParcelID = this_parcel_id; +		mLastRegionID = this_region_id;  	}  	mTimeInParcel += mPeriod;                 // increase mTimeInParcel by the amount of time between ticks diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h index 16279e7f1f..1d80b4756c 100644 --- a/indra/newview/llviewerparcelmediaautoplay.h +++ b/indra/newview/llviewerparcelmediaautoplay.h @@ -34,6 +34,7 @@  #define LLVIEWERPARCELMEDIAAUTOPLAY_H  #include "lltimer.h" +#include "lluuid.h"  // timer to automatically play media  class LLViewerParcelMediaAutoPlay : LLEventTimer @@ -47,6 +48,7 @@ class LLViewerParcelMediaAutoPlay : LLEventTimer   private:  	S32 mLastParcelID; +	LLUUID mLastRegionID;  	BOOL mPlayed;  	F32 mTimeInParcel;  }; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index f825eaa8ab..1edaeec848 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -3007,7 +3007,7 @@ void LLViewerMediaTexture::addFace(LLFace* facep)  	LLViewerTexture::addFace(facep) ;  	const LLTextureEntry* te = facep->getTextureEntry() ; -	if(te) +	if(te && te->getID().notNull())  	{  		LLViewerTexture* tex = gTextureList.findImage(te->getID()) ;  		if(tex) @@ -3024,7 +3024,10 @@ void LLViewerMediaTexture::addFace(LLFace* facep)  		return ;  	} -	llerrs << "The face does not have a valid texture before media texture." << llendl ; +	if(te && te->getID().notNull()) //should have a texture +	{ +		llerrs << "The face does not have a valid texture before media texture." << llendl ; +	}  }  //virtual  @@ -3033,7 +3036,7 @@ void LLViewerMediaTexture::removeFace(LLFace* facep)  	LLViewerTexture::removeFace(facep) ;  	const LLTextureEntry* te = facep->getTextureEntry() ; -	if(te) +	if(te && te->getID().notNull())  	{  		LLViewerTexture* tex = gTextureList.findImage(te->getID()) ;  		if(tex) @@ -3094,7 +3097,10 @@ void LLViewerMediaTexture::removeFace(LLFace* facep)  		}  	} -	llerrs << "mTextureList texture reference number is corrupted." << llendl ; +	if(te && te->getID().notNull()) //should have a texture +	{ +		llerrs << "mTextureList texture reference number is corrupted." << llendl ; +	}  }  void LLViewerMediaTexture::stopPlaying() @@ -3130,11 +3136,15 @@ void LLViewerMediaTexture::switchTexture(LLFace* facep)  			const LLTextureEntry* te = facep->getTextureEntry() ;  			if(te)  			{ -				LLViewerTexture* tex = gTextureList.findImage(te->getID()) ; +				LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID()) : NULL ;  				if(!tex && te->getID() != mID)//try parcel media.  				{  					tex = gTextureList.findImage(mID) ;  				} +				if(!tex) +				{ +					tex = LLViewerFetchedTexture::sDefaultImagep ; +				}  				facep->switchTexture(tex) ;  			}  		} diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 55609621b3..d23bcf9006 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1852,12 +1852,22 @@ void LLVOVolume::mediaNavigateBounceBack(U8 texture_index)  	if (mep && impl)  	{          std::string url = mep->getCurrentURL(); -        if (url.empty()) +		// If the url we're trying to "bounce back" to is either empty or not +		// allowed by the whitelist, try the home url.  If *that* doesn't work, +		// set the media as failed and unload it +        if (url.empty() || !mep->checkCandidateUrl(url))          {              url = mep->getHomeURL();          } -        if (! url.empty()) -        { +        if (url.empty() || !mep->checkCandidateUrl(url)) +		{ +			// The url to navigate back to is not good, and we have nowhere else +			// to go. +			LL_WARNS("MediaOnAPrim") << "FAILED to bounce back URL \"" << url << "\" -- unloading impl" << LL_ENDL; +			impl->setMediaFailed(true); +		} +		else { +			// Okay, navigate now              LL_INFOS("MediaOnAPrim") << "bouncing back to URL: " << url << LL_ENDL;              impl->navigateTo(url, "", false, true);          } diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 2ff99dcf5a..fac7aef690 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -6,7 +6,7 @@   name="floater_about"   help_topic="floater_about"   save_rect="true" - title="ABOUT [APP_NAME]" + title="ABOUT [CAPITALIZED_APP_NAME]"   width="470">    <floater.string       name="AboutHeader"> diff --git a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml index 953bd08dd4..f59badfcb4 100644 --- a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml +++ b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml @@ -47,7 +47,7 @@           label="Search"           layout="topleft"           left="6" -         help_topic="avatarpicker_search_tab" +         help_topic="avatarpicker"           name="SearchPanel"           top="150"           width="132"> @@ -98,7 +98,7 @@           label="Friends"           layout="topleft"           left="6" -         help_topic="avatarpicker_friends_tab" +         help_topic="avatarpicker"           name="FriendsPanel"           top="150"           width="132"> @@ -144,7 +144,7 @@           label="Near Me"           layout="topleft"           left="6" -         help_topic="avatarpicker_near_me_tab" +         help_topic="avatarpicker"           name="NearMePanel"           top="150"           width="132"> diff --git a/indra/newview/skins/default/xui/en/floater_voice_controls.xml b/indra/newview/skins/default/xui/en/floater_voice_controls.xml index a4ef807f06..b9649e9c57 100644 --- a/indra/newview/skins/default/xui/en/floater_voice_controls.xml +++ b/indra/newview/skins/default/xui/en/floater_voice_controls.xml @@ -8,6 +8,7 @@   min_height="122"   min_width="190"   name="floater_voice_controls" + help_topic="floater_voice_controls"   title="Voice Controls"   save_visibility="true"   single_instance="true" diff --git a/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml b/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml index 4ece0fa3ba..897d959b98 100644 --- a/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml +++ b/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml @@ -5,6 +5,9 @@   height="108"   layout="topleft"   name="whitelist_entry" + single_instance="true" + help_topic="whitelist_entry" + title="WHITELIST ENTRY"   width="390">    <text type="string" length="1" bottom="20" follows="top|left" height="15" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index 690167bc33..a0dec346a4 100644 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -223,6 +223,7 @@             parameter="test_inspectors" />          </menu_item_call>        </menu> +<!--        <menu_item_check           label="Reg In Client Test (restart)"           name="Reg In Client Test (restart)"> @@ -232,6 +233,7 @@                 function="ToggleControl"                 parameter="RegInClient" />        </menu_item_check> +-->        <menu_item_separator />        <menu_item_call         label="Set Window Size..." diff --git a/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml index 970a2e6a8a..003e1baa7e 100644 --- a/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml +++ b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml @@ -5,6 +5,7 @@   height="305"   layout="topleft"   name="block_list_panel" + help_topic="blocked_list"   min_height="350"   min_width="240"   width="280"> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 447901f984..f2f23a3847 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -8,6 +8,7 @@  	<!-- Default Args - these arguments will be replaced in all strings -->  	<string name="SECOND_LIFE">Second Life</string>  	<string name="APP_NAME">Second Life</string> +	<string name="CAPITALIZED_APP_NAME">SECOND LIFE</string>  	<string name="SECOND_LIFE_GRID">Second Life Grid</string>  	<string name="SUPPORT_SITE">Second Life Support Portal</string> | 
