diff options
103 files changed, 5802 insertions, 2003 deletions
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 26802bbd1c..457c074ef1 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -552,6 +552,23 @@ void LLPluginClassMedia::loadURI(const std::string &uri)  	sendMessage(message);  } +const char* LLPluginClassMedia::priorityToString(EPriority priority) +{ +	const char* result = "UNKNOWN"; +	switch(priority) +	{ +		case PRIORITY_UNLOADED:		result = "unloaded";	break; +		case PRIORITY_STOPPED:		result = "stopped";		break; +		case PRIORITY_HIDDEN:		result = "hidden";		break; +		case PRIORITY_SLIDESHOW:	result = "slideshow";	break; +		case PRIORITY_LOW:			result = "low";			break; +		case PRIORITY_NORMAL:		result = "normal";		break; +		case PRIORITY_HIGH:			result = "high";		break; +	} +	 +	return result; +} +  void LLPluginClassMedia::setPriority(EPriority priority)  {  	if(mPriority != priority) @@ -560,35 +577,28 @@ void LLPluginClassMedia::setPriority(EPriority priority)  		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); -		std::string priority_string; +		std::string priority_string = priorityToString(priority);  		switch(priority)  		{  			case PRIORITY_UNLOADED:	 -				priority_string = "unloaded";	  				mSleepTime = 1.0f;  			break;  			case PRIORITY_STOPPED:	 -				priority_string = "stopped";	  				mSleepTime = 1.0f;  			break;  			case PRIORITY_HIDDEN:	 -				priority_string = "hidden";	  				mSleepTime = 1.0f;  			break;  			case PRIORITY_SLIDESHOW: -				priority_string = "slideshow";		  				mSleepTime = 1.0f;  			break;  			case PRIORITY_LOW:		 -				priority_string = "low";		  				mSleepTime = 1.0f / 50.0f;  			break;  			case PRIORITY_NORMAL:	 -				priority_string = "normal";	  				mSleepTime = 1.0f / 100.0f;  			break;  			case PRIORITY_HIGH:		 -				priority_string = "high";		  				mSleepTime = 1.0f / 100.0f;  			break;  		} @@ -794,6 +804,10 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)  			{  				mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED;  			} +			else if(status == "done") +			{ +				mStatus = LLPluginClassMediaOwner::MEDIA_DONE; +			}  			else  			{  				// empty string or any unknown string diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 4f9763474e..90ecd1e073 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -150,6 +150,7 @@ public:  		PRIORITY_HIGH		// media has user focus and/or is taking up most of the screen  	}EPriority; +	static const char* priorityToString(EPriority priority);  	void setPriority(EPriority priority);  	void setLowPrioritySizeLimit(int size); diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h index 4690f09172..c798af29ca 100644 --- a/indra/llplugin/llpluginclassmediaowner.h +++ b/indra/llplugin/llpluginclassmediaowner.h @@ -70,7 +70,8 @@ public:  		MEDIA_ERROR,		// navigation/preroll failed  		MEDIA_PLAYING,		// playing (only for time-based media)  		MEDIA_PAUSED,		// paused (only for time-based media) -		 +		MEDIA_DONE			// finished playing (only for time-based media) +	  	} EMediaStatus;  	virtual ~LLPluginClassMediaOwner() {}; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index e053477d58..75905d0927 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1544,18 +1544,24 @@ void LLLineEditor::drawBackground()  		image = mBgImage;  	} +	F32 alpha = getDrawContext().mAlpha;  	// optionally draw programmatic border  	if (has_focus)  	{ +		LLColor4 tmp_color = gFocusMgr.getFocusColor(); +		tmp_color.setAlpha(alpha);  		image->drawBorder(0, 0, getRect().getWidth(), getRect().getHeight(), -						  gFocusMgr.getFocusColor(), +						  tmp_color,  						  gFocusMgr.getFocusFlashWidth());  	} -	image->draw(getLocalRect()); +	LLColor4 tmp_color = UI_VERTEX_COLOR; +	tmp_color.setAlpha(alpha); +	image->draw(getLocalRect(), tmp_color);  }  void LLLineEditor::draw()  { +	F32 alpha = getDrawContext().mAlpha;  	S32 text_len = mText.length();  	static LLUICachedControl<S32> lineeditor_cursor_thickness ("UILineEditorCursorThickness", 0);  	static LLUICachedControl<S32> lineeditor_v_pad ("UILineEditorVPad", 0); @@ -1608,8 +1614,10 @@ void LLLineEditor::draw()  	{  		text_color = mReadOnlyFgColor.get();  	} +	text_color.setAlpha(alpha);  	LLColor4 label_color = mTentativeFgColor.get(); - +	label_color.setAlpha(alpha); +	  	if (hasPreeditString())  	{  		// Draw preedit markers.  This needs to be before drawing letters. @@ -1632,7 +1640,7 @@ void LLLineEditor::draw()  						preedit_pixels_right - preedit_standout_gap - 1,  						background.mBottom + preedit_standout_position - preedit_standout_thickness,  						(text_color * preedit_standout_brightness  -						 + mPreeditBgColor * (1 - preedit_standout_brightness)).setAlpha(1.0f)); +						 + mPreeditBgColor * (1 - preedit_standout_brightness)).setAlpha(alpha/*1.0f*/));  				}  				else  				{ @@ -1641,7 +1649,7 @@ void LLLineEditor::draw()  						preedit_pixels_right - preedit_marker_gap - 1,  						background.mBottom + preedit_marker_position - preedit_marker_thickness,  						(text_color * preedit_marker_brightness -						 + mPreeditBgColor * (1 - preedit_marker_brightness)).setAlpha(1.0f)); +						 + mPreeditBgColor * (1 - preedit_marker_brightness)).setAlpha(alpha/*1.0f*/));  				}  			}  		} @@ -1684,15 +1692,17 @@ void LLLineEditor::draw()  		if( (rendered_pixels_right < (F32)mMaxHPixels) && (rendered_text < text_len) )  		{  			LLColor4 color = mHighlightColor; +			color.setAlpha(alpha);  			// selected middle  			S32 width = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos + rendered_text, select_right - mScrollHPos - rendered_text);  			width = llmin(width, mMaxHPixels - llround(rendered_pixels_right));  			gl_rect_2d(llround(rendered_pixels_right), cursor_top, llround(rendered_pixels_right)+width, cursor_bottom, color); +			LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha );  			rendered_text += mGLFont->render(   				mText, mScrollHPos + rendered_text,  				rendered_pixels_right, text_bottom, -				LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], 1 ), +				tmp_color,  				LLFontGL::LEFT, LLFontGL::BOTTOM,  				0,  				LLFontGL::NO_SHADOW, @@ -1758,8 +1768,9 @@ void LLLineEditor::draw()  					cursor_right, cursor_bottom, text_color);  				if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection())  				{ +					LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha );  					mGLFont->render(mText, getCursor(), (F32)(cursor_left + lineeditor_cursor_thickness / 2), text_bottom,  -						LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], 1 ), +						tmp_color,  						LLFontGL::LEFT, LLFontGL::BOTTOM,  						0,  						LLFontGL::NO_SHADOW, diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 732c01614b..cde4c75518 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -44,6 +44,7 @@  #include "lluictrlfactory.h"  #include "llrender.h"  #include "llfloater.h" +#include "lltrans.h"  //---------------------------------------------------------------------------- @@ -153,6 +154,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)  	mRightTabBtnOffset(p.tab_padding_right),  	mTotalTabWidth(0),  	mTabPosition(p.tab_position), +	mFontHalign(p.font_halign), +	mFont(p.font.isProvided() ? p.font() : (mIsVertical ? LLFontGL::getFontSansSerif() : LLFontGL::getFontSansSerifSmall())),  	mFirstTabParams(p.first_tab),  	mMiddleTabParams(p.middle_tab),  	mLastTabParams(p.last_tab) @@ -401,12 +404,6 @@ void LLTabContainer::draw()  					}  				}  			} -			LLUI::pushMatrix(); -			{ -				LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f); -				tuple->mButton->draw(); -			} -			LLUI::popMatrix();  			idx++;  		} @@ -641,12 +638,6 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, MASK mask)  				}  			}  		} - -		for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) -		{ -			LLTabTuple* tuple = *iter; -			tuple->mButton->setVisible( FALSE ); -		}  	}  	return handled;  } @@ -836,8 +827,6 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  		// already a child of mine  		return;  	} -	const LLFontGL* font = -		(mIsVertical ? LLFontGL::getFontSansSerif() : LLFontGL::getFontSansSerifSmall());  	// Store the original label for possible xml export.  	child->setLabel(label); @@ -847,7 +836,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  	S32 button_width = mMinTabWidth;  	if (!mIsVertical)  	{ -		button_width = llclamp(font->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth); +		button_width = llclamp(mFont->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth);  	}  	// Tab panel @@ -934,7 +923,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  		params.name(trimmed_label);  		params.rect(btn_rect);  		params.initial_value(trimmed_label); -		params.font(font); +		params.font(mFont);  		textbox = LLUICtrlFactory::create<LLTextBox> (params);  		LLButton::Params p; @@ -950,12 +939,12 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  			p.rect(btn_rect);  			p.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT);  			p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); -			p.font(font); +			p.font(mFont);  			p.label(trimmed_label);  			p.image_unselected(mMiddleTabParams.tab_left_image_unselected);  			p.image_selected(mMiddleTabParams.tab_left_image_selected);  			p.scale_image(true); -			p.font_halign = LLFontGL::LEFT; +			p.font_halign = mFontHalign;  			p.tab_stop(false);  			if (indent)  			{ @@ -965,18 +954,13 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  		}  		else  		{ -			std::string tooltip = trimmed_label; -			tooltip += "\nAlt-Left arrow for previous tab"; -			tooltip += "\nAlt-Right arrow for next tab"; -  			LLButton::Params p;  			p.name(std::string(child->getName()) + " tab");  			p.rect(btn_rect);  			p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); -			p.font(font); +			p.font(mFont);  			p.label(trimmed_label);  			p.visible(false); -			p.tool_tip(tooltip);  			p.scale_image(true);  			p.image_unselected(tab_img);  			p.image_selected(tab_selected_img); @@ -984,7 +968,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  			// Try to squeeze in a bit more text  			p.pad_left(4);  			p.pad_right(2); -			p.font_halign = LLFontGL::LEFT; +			p.font_halign = mFontHalign;  			p.follows.flags = FOLLOWS_LEFT;  			p.follows.flags = FOLLOWS_LEFT; @@ -1505,7 +1489,6 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L  		if (!mIsVertical)  		{ -			const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall();  			// remove current width from total tab strip width  			mTotalTabWidth -= tuple->mButton->getRect().getWidth(); @@ -1516,7 +1499,7 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L  			tuple->mPadding = image_overlay_width;  			tuple->mButton->setRightHPad(6); -			tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth),  +			tuple->mButton->reshape(llclamp(mFont->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth),   									tuple->mButton->getRect().getHeight());  			// add back in button width to total tab strip width  			mTotalTabWidth += tuple->mButton->getRect().getWidth(); diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index a81974cd42..be9c6c7d06 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -262,6 +262,9 @@ private:  	S32								mTabHeight;  	LLFrameTimer					mDragAndDropDelayTimer; +	 +	LLFontGL::HAlign                mFontHalign; +	const LLFontGL*					mFont;  	TabParams						mFirstTabParams;  	TabParams						mMiddleTabParams; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 0add3fb500..2b1d677ffb 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -419,9 +419,6 @@ void LLTextBase::drawCursor()  			return;  		} -		if (!mTextRect.contains(cursor_rect)) -			return; -  		// Draw the cursor  		// (Flash the cursor every half second starting a fixed time after the last keystroke)  		F32 elapsed = mCursorBlinkTimer.getElapsedTimeF32(); @@ -973,7 +970,7 @@ void LLTextBase::draw()  							: hasFocus()   								? mFocusBgColor.get()   								: mWriteableBgColor.get(); -		gl_rect_2d(mDocumentView->getRect(), bg_color, TRUE); +		gl_rect_2d(mTextRect, bg_color, TRUE);  	}  	// draw document view @@ -1034,13 +1031,13 @@ S32 LLTextBase::getLeftOffset(S32 width)  	switch (mHAlign)  	{  	case LLFontGL::LEFT: -		return 0; +		return mHPad;  	case LLFontGL::HCENTER: -		return (mTextRect.getWidth() - width) / 2; +		return mHPad + (mTextRect.getWidth() - width - mHPad) / 2;  	case LLFontGL::RIGHT:  		return mTextRect.getWidth() - width;  	default: -		return 0; +		return mHPad;  	}  } @@ -1048,8 +1045,6 @@ S32 LLTextBase::getLeftOffset(S32 width)  static LLFastTimer::DeclareTimer FTM_TEXT_REFLOW ("Text Reflow");  void LLTextBase::reflow(S32 start_index)  { -	if (!mReflowNeeded) return; -  	LLFastTimer ft(FTM_TEXT_REFLOW);  	updateSegments(); @@ -1078,7 +1073,7 @@ void LLTextBase::reflow(S32 start_index)  		segment_set_t::iterator seg_iter = mSegments.begin();  		S32 seg_offset = 0;  		S32 line_start_index = 0; -		const S32 text_width = mTextRect.getWidth();  // optionally reserve room for margin +		const S32 text_width = mTextRect.getWidth() - mHPad;  // reserve room for margin  		S32 remaining_pixels = text_width;  		LLWString text(getWText());  		S32 line_count = 0; @@ -2037,7 +2032,6 @@ void LLTextBase::updateRects()  	}  	else  	{ -  		mContentsRect = mLineInfoList.begin()->mRect;  		for (line_list_t::const_iterator line_iter = ++mLineInfoList.begin();  			line_iter != mLineInfoList.end(); @@ -2046,13 +2040,28 @@ void LLTextBase::updateRects()  			mContentsRect.unionWith(line_iter->mRect);  		} -		mContentsRect.mRight += mHPad; +		mContentsRect.mLeft = 0;  		mContentsRect.mTop += mVPad; -		// get around rounding errors when clipping text against rectangle -		mContentsRect.stretch(1); + +		S32 delta_pos = -mContentsRect.mBottom; +		// move line segments to fit new document rect +		for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it) +		{ +			it->mRect.translate(0, delta_pos); +		} +		mContentsRect.translate(0, delta_pos);  	} +	// update document container dimensions according to text contents +	LLRect doc_rect = mContentsRect; +	// use old mTextRect constraint document to width of viewable region +	doc_rect.mRight = doc_rect.mLeft + mTextRect.getWidth(); + +	mDocumentView->setShape(doc_rect); +	//update mTextRect *after* mDocumentView has been resized +	// so that scrollbars are added if document needs to scroll +	// since mTextRect does not include scrollbars  	LLRect old_text_rect = mTextRect;  	mTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect();  	//FIXME: replace border with image? @@ -2060,43 +2069,14 @@ void LLTextBase::updateRects()  	{  		mTextRect.stretch(-1);  	} -	mTextRect.mLeft += mHPad; -	mTextRect.mTop -= mVPad;  	if (mTextRect != old_text_rect)  	{  		needsReflow();  	} -	// change document rect size too -	LLRect document_rect; -	if (mScroller) -	{ -		// document is size of scroller or size of text contents, whichever is larger -		document_rect.setOriginAndSize(0, 0,  -									mScroller->getContentWindowRect().getWidth(),  -									llmax(mScroller->getContentWindowRect().getHeight(), mContentsRect.getHeight())); -	} -	else -	{ -		// document size is just extents of reflowed text, reset to origin 0,0 -		document_rect.set(0,  -						getLocalRect().getHeight(),  -						getLocalRect().getWidth(),  -						llmin(0, getLocalRect().getHeight() - mContentsRect.getHeight())); -	} -	mDocumentView->setShape(document_rect); - -	// after making document big enough to hold all the text, move the text to fit in the document -	if (!mLineInfoList.empty()) -	{ -		S32 delta_pos = mDocumentView->getRect().getHeight() - mLineInfoList.begin()->mRect.mTop - mVPad; -		// move line segments to fit new document rect -		for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it) -		{ -			it->mRect.translate(0, delta_pos); -		} -		mContentsRect.translate(0, delta_pos); -	} +	// update document container again, using new mTextRect +	doc_rect.mRight = doc_rect.mLeft + mTextRect.getWidth(); +	mDocumentView->setShape(doc_rect);  } @@ -2398,7 +2378,6 @@ S32	LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin  	{  		if (text[last_char] == '\n')   		{ -			last_char++;  			break;  		}  	} @@ -2418,9 +2397,14 @@ S32	LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin  		// If at the beginning of a line, and a single character won't fit, draw it anyway  		num_chars = 1;  	} -	if (mStart + segment_offset + num_chars == mEditor.getLength()) + +	// include *either* the EOF or newline character in this run of text +	// but not both +	S32 last_char_in_run = mStart + segment_offset + num_chars; +	// check length first to avoid indexing off end of string +	if (last_char_in_run >= mEditor.getLength()  +		|| text[last_char_in_run] == '\n')  	{ -		// include terminating NULL  		num_chars++;  	}  	return num_chars; @@ -2442,12 +2426,14 @@ void LLNormalTextSegment::dump() const  // LLInlineViewSegment  // -LLInlineViewSegment::LLInlineViewSegment(LLView* view, S32 start, S32 end, bool force_new_line, S32 hpad, S32 vpad) +LLInlineViewSegment::LLInlineViewSegment(const Params& p, S32 start, S32 end)  :	LLTextSegment(start, end), -	mView(view), -	mForceNewLine(force_new_line), -	mHPad(hpad), // one sided padding (applied to left and right) -	mVPad(vpad) +	mView(p.view), +	mForceNewLine(p.force_newline), +	mLeftPad(p.left_pad), +	mRightPad(p.right_pad), +	mTopPad(p.top_pad), +	mBottomPad(p.bottom_pad)  {  }  @@ -2467,8 +2453,8 @@ void	LLInlineViewSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt  	}  	else  	{ -		width = mHPad * 2 + mView->getRect().getWidth(); -		height = mVPad * 2 + mView->getRect().getHeight(); +		width = mLeftPad + mRightPad + mView->getRect().getWidth(); +		height = mBottomPad + mTopPad + mView->getRect().getHeight();  	}  } @@ -2491,14 +2477,14 @@ S32	LLInlineViewSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin  void LLInlineViewSegment::updateLayout(const LLTextBase& editor)  {  	LLRect start_rect = editor.getDocRectFromDocIndex(mStart); -	mView->setOrigin(start_rect.mLeft + mHPad, start_rect.mBottom + mVPad); +	mView->setOrigin(start_rect.mLeft + mLeftPad, start_rect.mBottom + mBottomPad);  }  F32	LLInlineViewSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)  {  	// return padded width of widget  	// widget is actually drawn during mDocumentView's draw() -	return (F32)(draw_rect.mLeft + mView->getRect().getWidth() + mHPad * 2); +	return (F32)(draw_rect.mLeft + mView->getRect().getWidth() + mLeftPad + mRightPad);  }  void LLInlineViewSegment::unlinkFromDocument(LLTextBase* editor) diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index d0787f001e..14fd786127 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -459,7 +459,17 @@ public:  class LLInlineViewSegment : public LLTextSegment  {  public: -	LLInlineViewSegment(LLView* widget, S32 start, S32 end, bool force_new_line, S32 hpad = 0, S32 vpad = 0); +	struct Params : public LLInitParam::Block<Params> +	{ +		Mandatory<LLView*>		view; +		Optional<bool>			force_newline; +		Optional<S32>			left_pad, +								right_pad, +								bottom_pad, +								top_pad; +	}; + +	LLInlineViewSegment(const Params& p, S32 start, S32 end);  	~LLInlineViewSegment();  	/*virtual*/ void		getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;  	/*virtual*/ S32			getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; @@ -470,8 +480,10 @@ public:  	/*virtual*/ void		linkToDocument(class LLTextBase* editor);  private: -	S32 mHPad; -	S32 mVPad; +	S32 mLeftPad; +	S32 mRightPad; +	S32 mTopPad; +	S32 mBottomPad;  	LLView* mView;  	bool	mForceNewLine;  }; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 570ca4b998..f0238dba49 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -2307,7 +2307,7 @@ void LLTextEditor::insertText(const std::string &new_text)  	setEnabled( enabled );  } -void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool force_new_line, S32 hpad, S32 vpad) +void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo)  {  	// Save old state  	S32 selection_start = mSelectionStart; @@ -2321,12 +2321,9 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text,  	setCursorPos(old_length); -	LLWString widget_wide_text; +	LLWString widget_wide_text = utf8str_to_wstring(text); -	// Add carriage return if not first line -	widget_wide_text = utf8str_to_wstring(widget_text); - -	LLTextSegmentPtr segment = new LLInlineViewSegment(widget, old_length, old_length + widget_text.size(), force_new_line, hpad, vpad); +	LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size());  	insert(getLength(), widget_wide_text, FALSE, segment);  	needsReflow(); @@ -2349,7 +2346,7 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text,  		setCursorPos(cursor_pos);  	} -	if( !allow_undo ) +	if (!allow_undo)  	{  		blockUndo();  	} diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 4847f4d117..10fc94dedc 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -166,7 +166,7 @@ public:  	// inserts text at cursor  	void			insertText(const std::string &text); -	void			appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool force_newline, S32 hpad, S32 vpad); +	void			appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo);  	// Non-undoable  	void			setText(const LLStringExplicit &utf8str); diff --git a/indra/media_plugins/base/media_plugin_base.cpp b/indra/media_plugins/base/media_plugin_base.cpp index 0b7092fad6..6acac07423 100644 --- a/indra/media_plugins/base/media_plugin_base.cpp +++ b/indra/media_plugins/base/media_plugin_base.cpp @@ -64,6 +64,7 @@ std::string MediaPluginBase::statusString()  		case STATUS_ERROR:		result = "error";		break;  		case STATUS_PLAYING:	result = "playing";		break;  		case STATUS_PAUSED:		result = "paused";		break; +		case STATUS_DONE:		result = "done";		break;  		default:  			// keep the empty string  		break; diff --git a/indra/media_plugins/base/media_plugin_base.h b/indra/media_plugins/base/media_plugin_base.h index 8f600cb8d6..f1e96335f9 100644 --- a/indra/media_plugins/base/media_plugin_base.h +++ b/indra/media_plugins/base/media_plugin_base.h @@ -56,6 +56,7 @@ protected:  		STATUS_ERROR,  		STATUS_PLAYING,  		STATUS_PAUSED, +		STATUS_DONE  	} EStatus;  	class SharedSegmentInfo diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp index c9ee1c8ac7..fb6d5b2905 100644 --- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp +++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp @@ -420,7 +420,7 @@ private:  	{
  		if ( mCommand == COMMAND_PLAY )
  		{
 -			if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING )
 +			if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING || mStatus == STATUS_DONE )
  			{
  				long state = GetMovieLoadState( mMovieHandle );
 @@ -446,7 +446,7 @@ private:  		else
  		if ( mCommand == COMMAND_STOP )
  		{
 -			if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED )
 +			if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED || mStatus == STATUS_DONE )
  			{
  				if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
  				{
 @@ -547,12 +547,12 @@ private:  		// see if title arrived and if so, update member variable with contents
  		checkTitle();
 -
 -		// special code for looping - need to rewind at the end of the movie
 -		if ( mIsLooping )
 +		
 +		// QT call to see if we are at the end - can't do with controller
 +		if ( IsMovieDone( mMovieHandle ) )
  		{
 -			// QT call to see if we are at the end - can't do with controller
 -			if ( IsMovieDone( mMovieHandle ) )
 +			// special code for looping - need to rewind at the end of the movie
 +			if ( mIsLooping )
  			{
  				// go back to start
  				rewind();
 @@ -565,8 +565,16 @@ private:  					// set the volume
  					MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
  				};
 -			};
 -		};
 +			}
 +			else
 +			{
 +				if(mStatus == STATUS_PLAYING)
 +				{
 +					setStatus(STATUS_DONE);
 +				}
 +			}
 +		}
 +
  	};
  	int getDataWidth() const
 diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index dd3937a6ef..a7681e4a1d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -63,13 +63,13 @@ include_directories(      )  set(viewer_SOURCE_FILES -    llaccordionctrltab.cpp      llaccordionctrl.cpp +    llaccordionctrltab.cpp      llagent.cpp -    llagentlistener.cpp      llagentaccess.cpp      llagentdata.cpp      llagentlanguage.cpp +    llagentlistener.cpp      llagentpicksinfo.cpp      llagentpilot.cpp      llagentui.cpp @@ -78,8 +78,8 @@ set(viewer_SOURCE_FILES      llappearancemgr.cpp      llappviewer.cpp      llappviewerlistener.cpp -    llassetuploadresponders.cpp      llassetuploadqueue.cpp +    llassetuploadresponders.cpp      llaudiosourcevo.cpp      llavataractions.cpp      llavatariconctrl.cpp @@ -95,8 +95,8 @@ set(viewer_SOURCE_FILES      llcaphttpsender.cpp      llchannelmanager.cpp      llchatbar.cpp -    llchatitemscontainerctrl.cpp      llchathistory.cpp +    llchatitemscontainerctrl.cpp      llchatmsgbox.cpp      llchiclet.cpp      llclassifiedinfo.cpp @@ -116,10 +116,10 @@ set(viewer_SOURCE_FILES      lldirpicker.cpp      lldndbutton.cpp      lldrawable.cpp +    lldrawpool.cpp      lldrawpoolalpha.cpp      lldrawpoolavatar.cpp      lldrawpoolbump.cpp -    lldrawpool.cpp      lldrawpoolground.cpp      lldrawpoolsimple.cpp      lldrawpoolsky.cpp @@ -151,8 +151,8 @@ set(viewer_SOURCE_FILES      llfloaterbuildoptions.cpp      llfloaterbulkpermission.cpp      llfloaterbump.cpp -    llfloaterbuycontents.cpp      llfloaterbuy.cpp +    llfloaterbuycontents.cpp      llfloaterbuycurrency.cpp      llfloaterbuyland.cpp      llfloatercall.cpp @@ -163,8 +163,8 @@ set(viewer_SOURCE_FILES      llfloatercustomize.cpp      llfloaterdaycycle.cpp      llfloaterenvsettings.cpp -    llfloaterfriends.cpp      llfloaterfonttest.cpp +    llfloaterfriends.cpp      llfloatergesture.cpp      llfloatergodtools.cpp      llfloatergroupinvite.cpp @@ -172,8 +172,6 @@ set(viewer_SOURCE_FILES      llfloaterhandler.cpp      llfloaterhardwaresettings.cpp      llfloaterhelpbrowser.cpp -    llfloatermediabrowser.cpp -    llfloatermediasettings.cpp      llfloaterhud.cpp      llfloaterimagepreview.cpp      llfloaterinspect.cpp @@ -183,6 +181,8 @@ set(viewer_SOURCE_FILES      llfloaterland.cpp      llfloaterlandholdings.cpp      llfloatermap.cpp +    llfloatermediabrowser.cpp +    llfloatermediasettings.cpp      llfloatermemleak.cpp      llfloaternamedesc.cpp      llfloaternotificationsconsole.cpp @@ -227,8 +227,8 @@ set(viewer_SOURCE_FILES      llgroupmgr.cpp      llgroupnotify.cpp      llhomelocationresponder.cpp -    llhudeffectbeam.cpp      llhudeffect.cpp +    llhudeffectbeam.cpp      llhudeffectlookat.cpp      llhudeffectpointat.cpp      llhudeffecttrail.cpp @@ -238,11 +238,11 @@ set(viewer_SOURCE_FILES      llhudrender.cpp      llhudtext.cpp      llhudview.cpp +    llimcontrolpanel.cpp      llimfloater.cpp      llimhandler.cpp      llimpanel.cpp      llimview.cpp -    llimcontrolpanel.cpp      llinspect.cpp      llinspectavatar.cpp      llinspectgroup.cpp @@ -260,7 +260,6 @@ set(viewer_SOURCE_FILES      lllocaltextureobject.cpp      lllocationhistory.cpp      lllocationinputctrl.cpp -    llurllineeditorctrl.cpp      lllogchat.cpp      llloginhandler.cpp      lllogininstance.cpp @@ -312,8 +311,8 @@ set(viewer_SOURCE_FILES      llpanelgrouplandmoney.cpp      llpanelgroupnotices.cpp      llpanelgrouproles.cpp -    llpanelinventory.cpp      llpanelimcontrolpanel.cpp +    llpanelinventory.cpp      llpanelland.cpp      llpanellandaudio.cpp      llpanellandmarks.cpp @@ -322,11 +321,10 @@ set(viewer_SOURCE_FILES      llpanellookinfo.cpp      llpanellooks.cpp      llpanelmedia.cpp -    llpanelmediahud.cpp -    llpanelmeprofile.cpp      llpanelmediasettingsgeneral.cpp -    llpanelmediasettingssecurity.cpp      llpanelmediasettingspermissions.cpp +    llpanelmediasettingssecurity.cpp +    llpanelmeprofile.cpp      llpanelobject.cpp      llpanelpeople.cpp      llpanelpeoplemenus.cpp @@ -335,11 +333,12 @@ set(viewer_SOURCE_FILES      llpanelpicks.cpp      llpanelplace.cpp      llpanelplaceinfo.cpp -    llpanelshower.cpp      llpanelplaces.cpp      llpanelplacestab.cpp +    llpanelprimmediacontrols.cpp      llpanelprofile.cpp      llpanelprofileview.cpp +    llpanelshower.cpp      llpanelteleporthistory.cpp      llpanelvolume.cpp      llparcelselection.cpp @@ -348,8 +347,8 @@ set(viewer_SOURCE_FILES      llplacesinventorybridge.cpp      llpolymesh.cpp      llpolymorph.cpp -    llpreviewanim.cpp      llpreview.cpp +    llpreviewanim.cpp      llpreviewgesture.cpp      llpreviewnotecard.cpp      llpreviewscript.cpp @@ -371,6 +370,7 @@ set(viewer_SOURCE_FILES      llsky.cpp      llslurl.cpp      llspatialpartition.cpp +    llspeakers.cpp      llsplitbutton.cpp      llsprite.cpp      llstartup.cpp @@ -397,10 +397,10 @@ set(viewer_SOURCE_FILES      lltoastimpanel.cpp      lltoastnotifypanel.cpp      lltoastpanel.cpp +    lltool.cpp      lltoolbar.cpp      lltoolbrush.cpp      lltoolcomp.cpp -    lltool.cpp      lltooldraganddrop.cpp      lltoolface.cpp      lltoolfocus.cpp @@ -424,6 +424,7 @@ set(viewer_SOURCE_FILES      llurl.cpp      llurldispatcher.cpp      llurlhistory.cpp +    llurllineeditorctrl.cpp      llurlsimstring.cpp      llurlwhitelist.cpp      llvectorperfoptions.cpp @@ -440,18 +441,18 @@ set(viewer_SOURCE_FILES      llviewerhelp.cpp      llviewerhelputil.cpp      llviewerinventory.cpp -    llviewerjointattachment.cpp      llviewerjoint.cpp +    llviewerjointattachment.cpp      llviewerjointmesh.cpp -    llviewerjointmesh_sse2.cpp      llviewerjointmesh_sse.cpp +    llviewerjointmesh_sse2.cpp      llviewerjointmesh_vec.cpp      llviewerjoystick.cpp      llviewerkeyboard.cpp      llviewerlayer.cpp      llviewermedia.cpp -    llviewermediafocus.cpp      llviewermedia_streamingaudio.cpp +    llviewermediafocus.cpp      llviewermenu.cpp      llviewermenufile.cpp      llviewermessage.cpp @@ -484,10 +485,11 @@ set(viewer_SOURCE_FILES      llvoclouds.cpp      llvograss.cpp      llvoground.cpp +    llvoicechannel.cpp      llvoiceclient.cpp +    llvoicecontrolpanel.cpp      llvoiceremotectrl.cpp      llvoicevisualizer.cpp -    llvoicecontrolpanel.cpp      llvoinventorylistener.cpp      llvopartgroup.cpp      llvosky.cpp @@ -538,25 +540,25 @@ endif (LINUX)  set(viewer_HEADER_FILES      CMakeLists.txt      ViewerInstall.cmake -    llaccordionctrltab.h      llaccordionctrl.h +    llaccordionctrltab.h      llagent.h -    llagentlistener.h      llagentaccess.h      llagentdata.h      llagentlanguage.h +    llagentlistener.h      llagentpicksinfo.h      llagentpilot.h      llagentui.h      llagentwearables.h      llanimstatelabels.h      llappearance.h +    llappearancemgr.h      llappviewer.h      llappviewerlistener.h -    llassetuploadresponders.h      llassetuploadqueue.h +    llassetuploadresponders.h      llaudiosourcevo.h -    llappearancemgr.h      llavataractions.h      llavatariconctrl.h      llavatarlist.h @@ -572,8 +574,8 @@ set(viewer_HEADER_FILES      llcaphttpsender.h      llchannelmanager.h      llchatbar.h -    llchatitemscontainerctrl.h      llchathistory.h +    llchatitemscontainerctrl.h      llchatmsgbox.h      llchiclet.h      llclassifiedinfo.h @@ -650,8 +652,6 @@ set(viewer_HEADER_FILES      llfloaterhandler.h      llfloaterhardwaresettings.h      llfloaterhelpbrowser.h -    llfloatermediabrowser.h -    llfloatermediasettings.h      llfloaterhud.h      llfloaterimagepreview.h      llfloaterinspect.h @@ -661,16 +661,18 @@ set(viewer_HEADER_FILES      llfloaterland.h      llfloaterlandholdings.h      llfloatermap.h +    llfloatermediabrowser.h +    llfloatermediasettings.h      llfloatermemleak.h      llfloaternamedesc.h      llfloaternotificationsconsole.h      llfloateropenobject.h      llfloaterparcel.h      llfloaterpay.h +    llfloaterperms.h      llfloaterpostcard.h      llfloaterpostprocess.h      llfloaterpreference.h -    llfloaterperms.h      llfloaterproperties.h      llfloaterregioninfo.h      llfloaterreporter.h @@ -716,12 +718,12 @@ set(viewer_HEADER_FILES      llhudrender.h      llhudtext.h      llhudview.h +    llimcontrolpanel.h      llimfloater.h      llimpanel.h      llimview.h -    llimcontrolpanel.h -    llinspectavatar.h      llinspect.h +    llinspectavatar.h      llinspectgroup.h      llinspectobject.h      llinventorybridge.h @@ -738,7 +740,6 @@ set(viewer_HEADER_FILES      lllocaltextureobject.h      lllocationhistory.h      lllocationinputctrl.h -    llurllineeditorctrl.h      lllogchat.h      llloginhandler.h      lllogininstance.h @@ -747,6 +748,7 @@ set(viewer_HEADER_FILES      llmanipscale.h      llmaniptranslate.h      llmapresponders.h +    llmediactrl.h      llmediadataclient.h      llmediaremotectrl.h      llmemoryview.h @@ -786,8 +788,8 @@ set(viewer_HEADER_FILES      llpanelgrouplandmoney.h      llpanelgroupnotices.h      llpanelgrouproles.h -    llpanelinventory.h      llpanelimcontrolpanel.h +    llpanelinventory.h      llpanelland.h      llpanellandaudio.h      llpanellandmarks.h @@ -796,11 +798,10 @@ set(viewer_HEADER_FILES      llpanellookinfo.h      llpanellooks.h      llpanelmedia.h -    llpanelmediahud.h -    llpanelmeprofile.h      llpanelmediasettingsgeneral.h -    llpanelmediasettingssecurity.h      llpanelmediasettingspermissions.h +    llpanelmediasettingssecurity.h +    llpanelmeprofile.h      llpanelobject.h      llpanelpeople.h      llpanelpeoplemenus.h @@ -809,11 +810,12 @@ set(viewer_HEADER_FILES      llpanelpicks.h      llpanelplace.h      llpanelplaceinfo.h -    llpanelshower.h      llpanelplaces.h      llpanelplacestab.h +    llpanelprimmediacontrols.h      llpanelprofile.h      llpanelprofileview.h +    llpanelshower.h      llpanelteleporthistory.h      llpanelvolume.h      llparcelselection.h @@ -836,9 +838,9 @@ set(viewer_HEADER_FILES      llremoteparcelrequest.h      llresourcedata.h      llrootview.h +    llsavedsettingsglue.h      llscreenchannel.h      llscrollingpanelparam.h -    llsavedsettingsglue.h      llsearchcombobox.h      llsearchhistory.h      llselectmgr.h @@ -847,6 +849,7 @@ set(viewer_HEADER_FILES      llsky.h      llslurl.h      llspatialpartition.h +    llspeakers.h      llsplitbutton.h      llsprite.h      llstartup.h @@ -902,6 +905,7 @@ set(viewer_HEADER_FILES      llurl.h      llurldispatcher.h      llurlhistory.h +    llurllineeditorctrl.h      llurlsimstring.h      llurlwhitelist.h      llvectorperfoptions.h @@ -925,8 +929,8 @@ set(viewer_HEADER_FILES      llviewerkeyboard.h      llviewerlayer.h      llviewermedia.h -    llviewermediaobserver.h      llviewermediafocus.h +    llviewermediaobserver.h      llviewermenu.h      llviewermenufile.h      llviewermessage.h @@ -960,10 +964,11 @@ set(viewer_HEADER_FILES      llvoclouds.h      llvograss.h      llvoground.h +    llvoicechannel.h      llvoiceclient.h +    llvoicecontrolpanel.h      llvoiceremotectrl.h      llvoicevisualizer.h -    llvoicecontrolpanel.h      llvoinventorylistener.h      llvopartgroup.h      llvosky.h @@ -981,7 +986,6 @@ set(viewer_HEADER_FILES      llwearabledictionary.h      llwearablelist.h      llweb.h -    llmediactrl.h      llwind.h      llwindebug.h      llwlanimator.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 63a4435408..568e8deb59 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7753,6 +7753,39 @@        <key>Value</key>        <integer>1</integer>      </map> +    <key>FriendsListShowIcons</key> +    <map> +      <key>Comment</key> +      <string>Show/hide online and all friends icons in the friend list</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map> +    <key>NearbyListShowIcons</key> +    <map> +      <key>Comment</key> +      <string>Show/hide people icons in nearby list</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map> +    <key>RecentListShowIcons</key> +    <map> +      <key>Comment</key> +      <string>Show/hide people icons in recent list</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map>      <key>FriendsSortOrder</key>      <map>        <key>Comment</key> @@ -10471,6 +10504,17 @@        <key>Value</key>        <real>90.0</real>      </map> +    <key>YouAreHereDistance</key> +    <map> +      <key>Comment</key> +      <string>Radius of distance for banner that indicates if the resident is "on" the Place.(meters from avatar to requested place)</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>10.0</real> +    </map>      <key>YieldTime</key>      <map>        <key>Comment</key> diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index f3bfa37cea..c43ba27984 100644 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -5589,6 +5589,13 @@      </layer>      <layer +       name="hair texture alpha layer" +       visibility_mask="TRUE"> +      <texture +         local_texture="hair_grain" /> +    </layer> + +    <layer         name="hair alpha"         visibility_mask="TRUE">        <texture diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index f62606cc50..75a72e5b17 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -42,7 +42,7 @@  #include "lldrawable.h"  #include "llfirstuse.h"  #include "llfloaterreg.h" -#include "llfloateractivespeakers.h" +#include "llspeakers.h"  #include "llfloatercamera.h"  #include "llfloatercustomize.h" @@ -5391,12 +5391,6 @@ void update_group_floaters(const LLUUID& group_id)  	//*TODO Implement group update for Profile View   	// still actual as of July 31, 2009 (DZ) -	if (gIMMgr) -	{ -		// update the talk view -		gIMMgr->refresh(); -	} -  	gAgent.fireEvent(new LLOldEvents::LLEvent(&gAgent, "new group"), "");  } diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp index 1a69f1d975..09f7c49f23 100644 --- a/indra/newview/llagentui.cpp +++ b/indra/newview/llagentui.cpp @@ -89,6 +89,11 @@ std::string LLAgentUI::buildSLURL(const bool escaped /*= true*/)  	return slurl;  } +//static +BOOL LLAgentUI::checkAgentDistance(const LLVector3& pole, F32 radius) +{ +	return  (gAgent.getPositionAgent() - pole).length() < radius; +}  BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const LLVector3& agent_pos_region)  {  	LLViewerRegion* region = gAgent.getRegion(); diff --git a/indra/newview/llagentui.h b/indra/newview/llagentui.h index 47ecb04547..c7aafb71e7 100644 --- a/indra/newview/llagentui.h +++ b/indra/newview/llagentui.h @@ -52,6 +52,11 @@ public:  	static BOOL buildLocationString(std::string& str, ELocationFormat fmt = LOCATION_FORMAT_LANDMARK);  	//build location string using a region position of the avatar.   	static BOOL buildLocationString(std::string& str, ELocationFormat fmt,const LLVector3& agent_pos_region); +	/** +	 * @brief Check whether  the agent is in neighborhood of the pole  Within same region +	 * @return true if the agent is in neighborhood. +	 */ +	static BOOL checkAgentDistance(const LLVector3& local_pole, F32 radius);  };  #endif //LLAGENTUI_H diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e184d99ffc..06c9171d67 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -49,7 +49,6 @@  #include "llviewerstats.h"  #include "llmd5.h"  #include "llpumpio.h" -#include "llimpanel.h"  #include "llmimetypes.h"  #include "llslurl.h"  #include "llstartup.h" @@ -76,6 +75,7 @@  #include "llteleporthistory.h"  #include "lllocationhistory.h"  #include "llfasttimerview.h" +#include "llvoicechannel.h"  #include "llweb.h"  #include "llsecondlifeurls.h" diff --git a/indra/newview/llavatariconctrl.h b/indra/newview/llavatariconctrl.h index 426fcec514..65b5c86ed5 100644 --- a/indra/newview/llavatariconctrl.h +++ b/indra/newview/llavatariconctrl.h @@ -103,6 +103,8 @@ public:  	const std::string&	getFirstName() const { return mFirstName; }  	const std::string&	getLastName() const { return mLastName; } +	void setDrawTooltip(bool value) { mDrawTooltip = value;} +  protected:  	LLUUID				mAvatarId;  	std::string			mFirstName; diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index 3a07c6e5ef..e93d0dfa50 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -38,6 +38,7 @@  #include "llcallingcard.h" // for LLAvatarTracker  #include "llcachename.h"  #include "llvoiceclient.h" +#include "llviewercontrol.h"	// for gSavedSettings  static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list"); @@ -45,6 +46,21 @@ static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list");  // Used to limit time spent for avatar list update per frame.  static const unsigned ADD_LIMIT = 50; +void LLAvatarList::toggleIcons() +{ +	// Save the new value for new items to use. +	mShowIcons = !mShowIcons; +	gSavedSettings.setBOOL(mIconParamName, mShowIcons); +	 +	// Show/hide icons for all existing items. +	std::vector<LLPanel*> items; +	getItems(items); +	for( std::vector<LLPanel*>::const_iterator it = items.begin(); it != items.end(); it++) +	{ +		static_cast<LLAvatarListItem*>(*it)->setAvatarIconVisible(mShowIcons); +	} +} +  static bool findInsensitive(std::string haystack, const std::string& needle_upper)  {      LLStringUtil::toUpper(haystack); @@ -73,13 +89,22 @@ LLAvatarList::LLAvatarList(const Params& p)  	setComparator(&NAME_COMPARATOR);  } +void LLAvatarList::setShowIcons(std::string param_name) +{ +	mIconParamName= param_name; +	mShowIcons = gSavedSettings.getBOOL(mIconParamName); +} +  // virtual  void LLAvatarList::draw()  { -	if (mDirty) -		refresh(); +	// *NOTE dzaporozhan +	// Call refresh() after draw() to avoid flickering of avatar list items.  	LLFlatListView::draw(); + +	if (mDirty) +		refresh();  }  void LLAvatarList::setNameFilter(const std::string& filter) @@ -202,6 +227,7 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is  	item->setContextMenu(mContextMenu);  	item->childSetVisible("info_btn", false); +	item->setAvatarIconVisible(mShowIcons);  	addItem(item, id, pos);  } diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index a83a72b26c..f60f1f00f3 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -70,7 +70,11 @@ public:  	void setContextMenu(LLAvatarListItem::ContextMenu* menu) { mContextMenu = menu; } +	void toggleIcons();  	void sortByName(); +	void setShowIcons(std::string param_name); +	bool getIconsVisible() const { return mShowIcons; } +	const std::string getIconParamName() const{return mIconParamName;}  	virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);  protected: @@ -86,7 +90,9 @@ private:  	bool mIgnoreOnlineStatus;  	bool mDirty; +	bool mShowIcons; +	std::string				mIconParamName;  	std::string				mNameFilter;  	uuid_vector_t			mIDs; diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp index ebc79aae48..4ecb9537ba 100644 --- a/indra/newview/llavatarlistitem.cpp +++ b/indra/newview/llavatarlistitem.cpp @@ -42,6 +42,7 @@  #include "llavatariconctrl.h"  #include "llbutton.h" +S32 LLAvatarListItem::sIconWidth = 0;  LLAvatarListItem::LLAvatarListItem()  :	LLPanel(), @@ -55,6 +56,12 @@ LLAvatarListItem::LLAvatarListItem()  	mOnlineStatus(E_UNKNOWN)  {  	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_avatar_list_item.xml"); +	// Remember avatar icon width including its padding from the name text box, +	// so that we can hide and show the icon again later. +	if (!sIconWidth) +	{ +		sIconWidth = mAvatarName->getRect().mLeft - mAvatarIcon->getRect().mLeft; +	}  }  LLAvatarListItem::~LLAvatarListItem() @@ -188,6 +195,21 @@ void LLAvatarListItem::setAvatarId(const LLUUID& id, bool ignore_status_changes)  	gCacheName->get(id, FALSE, boost::bind(&LLAvatarListItem::onNameCache, this, _2, _3));  } +void LLAvatarListItem::setAvatarIconVisible(bool visible) +{ +	// Already done? Then do nothing. +	if (mAvatarIcon->getVisible() == (BOOL)visible) +		return; + +	// Show/hide avatar icon. +	mAvatarIcon->setVisible(visible); + +	// Move the avatar name horizontally by icon size + its distance from the avatar name. +	LLRect name_rect = mAvatarName->getRect(); +	name_rect.mLeft += visible ? sIconWidth : -sIconWidth; +	mAvatarName->setRect(name_rect); +} +  void LLAvatarListItem::onInfoBtnClick()  {  	LLFloaterReg::showInstance("inspect_avatar", LLSD().insert("avatar_id", mAvatarId)); diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h index b9cfed4b7b..a8d3919217 100644 --- a/indra/newview/llavatarlistitem.h +++ b/indra/newview/llavatarlistitem.h @@ -64,6 +64,7 @@ public:  	void setOnline(bool online);  	void setName(const std::string& name);  	void setAvatarId(const LLUUID& id, bool ignore_status_changes = false); +	void setAvatarIconVisible(bool visible);  	const LLUUID& getAvatarId() const;  	const std::string getAvatarName() const; @@ -87,7 +88,7 @@ private:  	void onNameCache(const std::string& first_name, const std::string& last_name); -	LLAvatarIconCtrl*mAvatarIcon; +	LLAvatarIconCtrl* mAvatarIcon;  	LLTextBox* mAvatarName;  	LLTextBox* mStatus; @@ -98,6 +99,7 @@ private:  	LLUUID mAvatarId;  	EOnlineStatus mOnlineStatus; +	static S32	sIconWidth; // icon width + padding  };  #endif //LL_LLAVATARLISTITEM_H diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp index 77f941eef0..6427422572 100644 --- a/indra/newview/llchannelmanager.cpp +++ b/indra/newview/llchannelmanager.cpp @@ -40,6 +40,8 @@  #include "llbottomtray.h"  #include "llviewerwindow.h"  #include "llrootview.h" +#include "llsyswellwindow.h" +#include "llfloaterreg.h"  #include <algorithm> @@ -128,7 +130,7 @@ void LLChannelManager::onLoginCompleted()  	S32 channel_right_bound = gViewerWindow->getWorldViewRect().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");   	S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");  	mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound); -	mStartUpChannel->setShowToasts(true); +	mStartUpChannel->setMouseDownCallback(boost::bind(&LLSysWellWindow::onStartUpToastClick, LLFloaterReg::getTypedInstance<LLSysWellWindow>("syswell_window"), _2, _3, _4));  	mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this));  	mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime")); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 94058365be..aaca568320 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -38,9 +38,215 @@  #include "llscrollcontainer.h"  #include "llavatariconctrl.h" +#include "llimview.h" +#include "llcallingcard.h" //for LLAvatarTracker +#include "llagentdata.h" +#include "llavataractions.h" +#include "lltrans.h" +  static LLDefaultChildRegistry::Register<LLChatHistory> r("chat_history");  static const std::string MESSAGE_USERNAME_DATE_SEPARATOR(" ----- "); +std::string formatCurrentTime() +{ +	time_t utc_time; +	utc_time = time_corrected(); +	std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:[" +		+LLTrans::getString("TimeMin")+"] "; + +	LLSD substitution; + +	substitution["datetime"] = (S32) utc_time; +	LLStringUtil::format (timeStr, substitution); + +	return timeStr; +} + +class LLChatHistoryHeader: public LLPanel +{ +public: +	static LLChatHistoryHeader* createInstance(const std::string& file_name) +	{ +		LLChatHistoryHeader* pInstance = new LLChatHistoryHeader; +		LLUICtrlFactory::getInstance()->buildPanel(pInstance, file_name);	 +		return pInstance; +	} + +	BOOL handleMouseUp(S32 x, S32 y, MASK mask) +	{ +		return LLPanel::handleMouseUp(x,y,mask); +	} + +	void onAvatarIconContextMenuItemClicked(const LLSD& userdata) +	{ +		std::string level = userdata.asString(); + +		if (level == "profile") +		{ +			LLAvatarActions::showProfile(getAvatarId()); +		} +		else if (level == "im") +		{ +			LLAvatarActions::startIM(getAvatarId()); +		} +		else if (level == "add") +		{ +			std::string name; +			name.assign(getFirstName()); +			name.append(" "); +			name.append(getLastName()); + +			LLAvatarActions::requestFriendshipDialog(getAvatarId(), name); +		} +		else if (level == "remove") +		{ +			LLAvatarActions::removeFriendDialog(getAvatarId()); +		} +	} + +	BOOL postBuild() +	{ +		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + +		registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2)); + +		LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_avatar_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + +		mPopupMenuHandleAvatar = menu->getHandle(); + +		return LLPanel::postBuild(); +	} + +	bool pointInChild(const std::string& name,S32 x,S32 y) +	{ +		LLUICtrl* child = findChild<LLUICtrl>(name); +		if(!child) +			return false; +		 +		LLView* parent = child->getParent(); +		if(parent!=this) +		{ +			x-=parent->getRect().mLeft; +			y-=parent->getRect().mBottom; +		} + +		S32 local_x = x - child->getRect().mLeft ; +		S32 local_y = y - child->getRect().mBottom ; +		return 	child->pointInView(local_x, local_y); +	} + +	BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) +	{ +		if(pointInChild("avatar_icon",x,y) || pointInChild("user_name",x,y)) +		{ +			showContextMenu(x,y); +			return TRUE; +		} + +		return LLPanel::handleRightMouseDown(x,y,mask); +	} +	const LLUUID&		getAvatarId () const { return mAvatarID;} +	const std::string&	getFirstName() const { return mFirstName; } +	const std::string&	getLastName	() const { return mLastName; } + +	void setup(const LLChat& chat)  +	{ +		mAvatarID = chat.mFromID; +		mSourceType = chat.mSourceType; +		gCacheName->get(mAvatarID, FALSE, boost::bind(&LLChatHistoryHeader::nameUpdatedCallback, this, _1, _2, _3, _4)); +		if(chat.mFromID.isNull()) +		{ +			mSourceType = CHAT_SOURCE_SYSTEM; +		} + + +		LLTextBox* userName = getChild<LLTextBox>("user_name"); +		 +		if(!chat.mFromName.empty()) +			userName->setValue(chat.mFromName); +		else +		{ +			std::string SL = LLTrans::getString("SECOND_LIFE"); +			userName->setValue(SL); +		} +		 +		LLTextBox* timeBox = getChild<LLTextBox>("time_box"); +		timeBox->setValue(formatCurrentTime()); + +		LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon"); + +		if(mSourceType != CHAT_SOURCE_AGENT) +			icon->setDrawTooltip(false); + +		if(!chat.mFromID.isNull()) +		{ +			icon->setValue(chat.mFromID); +		} + +	}  + +	void nameUpdatedCallback(const LLUUID& id,const std::string& first,const std::string& last,BOOL is_group) +	{ +		if (id != mAvatarID) +			return; +		mFirstName = first; +		mLastName = last; +	} +protected: +	void showContextMenu(S32 x,S32 y) +	{ +		if(mSourceType == CHAT_SOURCE_SYSTEM) +			showSystemContextMenu(x,y); +		if(mSourceType == CHAT_SOURCE_AGENT) +			showAvatarContextMenu(x,y); +		if(mSourceType == CHAT_SOURCE_OBJECT) +			showObjectContextMenu(x,y); +	} + +	void showSystemContextMenu(S32 x,S32 y) +	{ +	} +	void showObjectContextMenu(S32 x,S32 y) +	{ +	} +	 +	void showAvatarContextMenu(S32 x,S32 y) +	{ +		LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleAvatar.get(); + +		if(menu) +		{ +			bool is_friend = LLAvatarTracker::instance().getBuddyInfo(mAvatarID) != NULL; +			 +			menu->setItemEnabled("Add Friend", !is_friend); +			menu->setItemEnabled("Remove Friend", is_friend); + +			if(gAgentID == mAvatarID) +			{ +				menu->setItemEnabled("Add Friend", false); +				menu->setItemEnabled("Send IM", false); +				menu->setItemEnabled("Remove Friend", false); +			} + +			menu->buildDrawLabels(); +			menu->updateParent(LLMenuGL::sMenuContainer); +			LLMenuGL::showPopup(this, menu, x, y); +		} +	} + +	 + +protected: +	LLHandle<LLView>	mPopupMenuHandleAvatar; + +	LLUUID			    mAvatarID; +	EChatSourceType		mSourceType; +	std::string			mFirstName; +	std::string			mLastName; + +}; + +  LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)  : LLTextEditor(p),  mMessageHeaderFilename(p.message_header), @@ -48,7 +254,7 @@ mMessageSeparatorFilename(p.message_separator),  mLeftTextPad(p.left_text_pad),  mRightTextPad(p.right_text_pad),  mLeftWidgetPad(p.left_widget_pad), -mRightWidgetPad(p.rigth_widget_pad) +mRightWidgetPad(p.right_widget_pad)  {  } @@ -78,50 +284,49 @@ LLView* LLChatHistory::getSeparator()  	return separator;  } -LLView* LLChatHistory::getHeader(const LLUUID& avatar_id, std::string& from, std::string& time) +LLView* LLChatHistory::getHeader(const LLChat& chat)  { -	LLPanel* header = LLUICtrlFactory::getInstance()->createFromFile<LLPanel>(mMessageHeaderFilename, NULL, LLPanel::child_registry_t::instance()); -	LLTextBox* userName = header->getChild<LLTextBox>("user_name"); -	userName->setValue(from); -	LLTextBox* timeBox = header->getChild<LLTextBox>("time_box"); -	timeBox->setValue(time); -	if(!avatar_id.isNull()) -	{ -		LLAvatarIconCtrl* icon = header->getChild<LLAvatarIconCtrl>("avatar_icon"); -		icon->setValue(avatar_id); -	} +	LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename); +	header->setup(chat);  	return header;  } -void LLChatHistory::appendWidgetMessage(const LLUUID& avatar_id, std::string& from, std::string& time, std::string& message, LLStyle::Params& style_params) +void LLChatHistory::appendWidgetMessage(const LLChat& chat, LLStyle::Params& style_params)  {  	LLView* view = NULL;  	std::string view_text; -	if (mLastFromName == from) +	if (mLastFromName == chat.mFromName)  	{  		view = getSeparator();  		view_text = "\n";  	}  	else  	{ -		view = getHeader(avatar_id, from, time); -		view_text = from + MESSAGE_USERNAME_DATE_SEPARATOR + time + '\n'; +		view = getHeader(chat); +		view_text = chat.mFromName + MESSAGE_USERNAME_DATE_SEPARATOR + formatCurrentTime() + '\n';  	}  	//Prepare the rect for the view  	LLRect target_rect = getDocumentView()->getRect(); -	target_rect.mLeft += mLeftWidgetPad; +	// squeeze down the widget by subtracting padding off left and right +	target_rect.mLeft += mLeftWidgetPad + mHPad;  	target_rect.mRight -= mRightWidgetPad;  	view->reshape(target_rect.getWidth(), view->getRect().getHeight());  	view->setOrigin(target_rect.mLeft, view->getRect().mBottom); -	appendWidget(view, view_text, FALSE, TRUE, mLeftWidgetPad, 0); +	LLInlineViewSegment::Params p; +	p.view = view; +	p.force_newline = true; +	p.left_pad = mLeftWidgetPad; +	p.right_pad = mRightWidgetPad; + +	appendWidget(p, view_text, false);  	//Append the text message -	message += '\n'; +	std::string message = chat.mText + '\n';  	appendText(message, FALSE, style_params); -	mLastFromName = from; +	mLastFromName = chat.mFromName;  	blockUndo();  	setCursorAndScrollToEnd();  } diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h index d6eccf896a..92dcfdd958 100644 --- a/indra/newview/llchathistory.h +++ b/indra/newview/llchathistory.h @@ -34,6 +34,7 @@  #define LLCHATHISTORY_H_  #include "lltexteditor.h" +#include "llchat.h"  //Chat log widget allowing addition of a message as a widget   class LLChatHistory : public LLTextEditor @@ -52,7 +53,7 @@ class LLChatHistory : public LLTextEditor  			//Widget left padding from the scroll rect  			Optional<S32>			left_widget_pad;  			//Widget right padding from the scroll rect -			Optional<S32>			rigth_widget_pad; +			Optional<S32>			right_widget_pad;  			Params()  			:	message_header("message_header"), @@ -60,7 +61,7 @@ class LLChatHistory : public LLTextEditor  				left_text_pad("left_text_pad"),  				right_text_pad("right_text_pad"),  				left_widget_pad("left_widget_pad"), -				rigth_widget_pad("rigth_widget_pad") +				right_widget_pad("right_widget_pad")  				{  				} @@ -85,7 +86,7 @@ class LLChatHistory : public LLTextEditor  		 * @param time time of a message.  		 * @return pointer to LLView header object.  		 */ -		LLView* getHeader(const LLUUID& avatar_id, std::string& from, std::string& time); +		LLView* getHeader(const LLChat& chat);  	public:  		~LLChatHistory(); @@ -94,11 +95,11 @@ class LLChatHistory : public LLTextEditor  		 * Appends a widget message.  		 * If last user appended message, concurs with current user,  		 * separator is added before the message, otherwise header is added. -		 * @param from owner of a message. +		 * @param chat - base chat message.  		 * @param time time of a message.  		 * @param message message itself.  		 */ -		void appendWidgetMessage(const LLUUID& avatar_id, std::string& from, std::string& time, std::string& message, LLStyle::Params& style_params); +		void appendWidgetMessage(const LLChat& chat, LLStyle::Params& style_params);  	private:  		std::string mLastFromName; diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 3b5b7f570e..a6afbc05be 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -503,13 +503,15 @@ void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, con  		return;  	} +	LLPointer<LLViewerInventoryItem> viewer_item = new LLViewerInventoryItem(item); +  	if (dest)  	{ -		insertBeforeItem(mItems, dest->getLandmarkId(), item->getUUID()); +		insertBeforeItem(mItems, dest->getLandmarkId(), viewer_item);  	}  	else  	{ -		mItems.push_back(gInventory.getItem(item->getUUID())); +		mItems.push_back(viewer_item);  	}  	int sortField = 0; @@ -534,13 +536,22 @@ void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, con  		}  	} -	copy_inventory_item( -			gAgent.getID(), -			item->getPermissions().getOwner(), -			item->getUUID(), -			favorites_id, -			std::string(), -			cb); +	LLToolDragAndDrop* tool_dad = LLToolDragAndDrop::getInstance(); +	if (tool_dad->getSource() == LLToolDragAndDrop::SOURCE_NOTECARD) +	{ +		viewer_item->setType(LLAssetType::AT_FAVORITE); +		copy_inventory_from_notecard(tool_dad->getObjectID(), tool_dad->getSourceID(), viewer_item.get(), gInventoryCallbacks.registerCB(cb)); +	} +	else +	{ +		copy_inventory_item( +				gAgent.getID(), +				item->getPermissions().getOwner(), +				item->getUUID(), +				favorites_id, +				std::string(), +				cb); +	}  	llinfos << "Copied inventory item #" << item->getUUID() << " to favorites." << llendl;  } @@ -1263,10 +1274,9 @@ void LLFavoritesBarCtrl::updateItemsOrder(LLInventoryModel::item_array_t& items,  	items.insert(findItemByUUID(items, destItem->getUUID()), srcItem);  } -void LLFavoritesBarCtrl::insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, const LLUUID& insertedItemId) +void LLFavoritesBarCtrl::insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, LLViewerInventoryItem* insertedItem)  {  	LLViewerInventoryItem* beforeItem = gInventory.getItem(beforeItemId); -	LLViewerInventoryItem* insertedItem = gInventory.getItem(insertedItemId);  	items.insert(findItemByUUID(items, beforeItem->getUUID()), insertedItem);  } diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index ea2a3d08e2..e90d13f9d5 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -141,7 +141,7 @@ private:  	 * inserts an item identified by insertedItemId BEFORE an item identified by beforeItemId.  	 * this function assumes that an item identified by insertedItemId doesn't exist in items array.  	 */ -	void insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, const LLUUID& insertedItemId); +	void insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, LLViewerInventoryItem* insertedItem);  	// finds an item by it's UUID in the items array  	LLInventoryModel::item_array_t::iterator findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id); diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 92ad28a105..63ea990d14 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -61,6 +61,9 @@  #include "lluri.h"
  #include "v3dmath.h"
  #include "llwindow.h"
 +#include "stringize.h"
 +#include "llsdutil_math.h"
 +#include "lleventdispatcher.h"
  #if LL_WINDOWS
  #include "lldxhardware.h"
 @@ -85,6 +88,10 @@ private:  public:
  	/*virtual*/ BOOL postBuild();
 +
 +	/// Obtain the data used to fill out the contents string. This is
 +	/// separated so that we can programmatically access the same info.
 +	static LLSD getInfo();
  	void onClickCopyToClipboard();
  };
 @@ -114,25 +121,117 @@ BOOL LLFloaterAbout::postBuild()  	getChild<LLUICtrl>("copy_btn")->setCommitCallback(
  		boost::bind(&LLFloaterAbout::onClickCopyToClipboard, this));
 -	// Version string
 -	std::string version = LLTrans::getString("APP_NAME")
 -		+ llformat(" %d.%d.%d (%d) %s %s (%s)\n",
 -				   LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VIEWER_BUILD,
 -				   __DATE__, __TIME__,
 -				   gSavedSettings.getString("VersionChannelName").c_str());
 +#if LL_WINDOWS
 +	getWindow()->incBusyCount();
 +	getWindow()->setCursor(UI_CURSOR_ARROW);
 +#endif
 +	LLSD info(getInfo());
 +#if LL_WINDOWS
 +	getWindow()->decBusyCount();
 +	getWindow()->setCursor(UI_CURSOR_ARROW);
 +#endif
 -	std::string support;
 -	support.append(version);
 -	support.append("[" + get_viewer_release_notes_url() + " " +
 -				   LLTrans::getString("ReleaseNotes") + "]");
 -	support.append("\n\n");
 +	std::ostringstream support;
 -#if LL_MSVC
 -    support.append(llformat("Built with MSVC version %d\n\n", _MSC_VER));
 -#endif
 +	// Render the LLSD from getInfo() as a format_map_t
 +	LLStringUtil::format_map_t args;
 +	// For reasons I don't yet understand, [ReleaseNotes] is not part of the
 +	// default substitution strings whereas [APP_NAME] is. But it works to
 +	// simply copy it into these specific args.
 +	args["ReleaseNotes"] = LLTrans::getString("ReleaseNotes");
 +	for (LLSD::map_const_iterator ii(info.beginMap()), iend(info.endMap());
 +		 ii != iend; ++ii)
 +	{
 +		if (! ii->second.isArray())
 +		{
 +			// Scalar value
 +			if (ii->second.isUndefined())
 +			{
 +				args[ii->first] = getString("none");
 +			}
 +			else
 +			{
 +				// don't forget to render value asString()
 +				args[ii->first] = ii->second.asString();
 +			}
 +		}
 +		else
 +		{
 +			// array value: build KEY_0, KEY_1 etc. entries
 +			for (LLSD::Integer n(0), size(ii->second.size()); n < size; ++n)
 +			{
 +				args[STRINGIZE(ii->first << '_' << n)] = ii->second[n].asString();
 +			}
 +		}
 +	}
 +
 +	// Now build the various pieces
 +	support << getString("AboutHeader", args);
 +	if (info.has("COMPILER"))
 +	{
 +		support << "\n\n" << getString("AboutCompiler", args);
 +	}
 +	if (info.has("REGION"))
 +	{
 +		support << "\n\n" << getString("AboutPosition", args);
 +	}
 +	support << "\n\n" << getString("AboutSystem", args);
 +	if (info.has("GRAPHICS_DRIVER_VERSION"))
 +	{
 +		support << "\n\n" << getString("AboutDriver", args);
 +	}
 +	support << "\n\n" << getString("AboutLibs", args);
 +	if (info.has("PACKETS_IN"))
 +	{
 +		support << '\n' << getString("AboutTraffic", args);
 +	}
 -#if LL_GNUC
 -    support.append(llformat("Built with GCC version %d\n\n", GCC_VERSION));
 +	support_widget->appendText(support.str(), 
 +								FALSE, 
 +								LLStyle::Params()
 +									.color(LLUIColorTable::instance().getColor("TextFgReadOnlyColor")));
 +	support_widget->blockUndo();
 +
 +	// Fix views
 +	support_widget->setCursorPos(0);
 +	support_widget->setEnabled(FALSE);
 +
 +	credits_widget->setCursorPos(0);
 +	credits_widget->setEnabled(FALSE);
 +
 +	return TRUE;
 +}
 +
 +// static
 +LLSD LLFloaterAbout::getInfo()
 +{
 +	// The point of having one method build an LLSD info block and the other
 +	// construct the user-visible About string is to ensure that the same info
 +	// is available to a getInfo() caller as to the user opening
 +	// LLFloaterAbout.
 +	LLSD info;
 +	LLSD version;
 +	version.append(LL_VERSION_MAJOR);
 +	version.append(LL_VERSION_MINOR);
 +	version.append(LL_VERSION_PATCH);
 +	version.append(LL_VERSION_BUILD);
 +	info["VIEWER_VERSION"] = version;
 +	info["VIEWER_VERSION_STR"] = STRINGIZE(version[0].asInteger() << '.' <<
 +										   version[1].asInteger() << '.' <<
 +										   version[2].asInteger() << '.' <<
 +										   version[3].asInteger());
 +	info["BUILD_DATE"] = __DATE__;
 +	info["BUILD_TIME"] = __TIME__;
 +	info["CHANNEL"] = gSavedSettings.getString("VersionChannelName");
 +
 +	info["VIEWER_RELEASE_NOTES_URL"] = get_viewer_release_notes_url();
 +
 +#if LL_MSVC
 +	info["COMPILER"] = "MSVC";
 +	info["COMPILER_VERSION"] = _MSC_VER;
 +#elif LL_GNUC
 +	info["COMPILER"] = "GCC";
 +	info["COMPILER_VERSION"] = GCC_VERSION;
  #endif
  	// Position
 @@ -140,120 +239,49 @@ BOOL LLFloaterAbout::postBuild()  	if (region)
  	{
  		const LLVector3d &pos = gAgent.getPositionGlobal();
 -		LLUIString pos_text = getString("you_are_at");
 -		pos_text.setArg("[POSITION]",
 -						llformat("%.1f, %.1f, %.1f ", pos.mdV[VX], pos.mdV[VY], pos.mdV[VZ]));
 -		support.append(pos_text);
 -
 -		LLUIString region_text = getString ("in_region") + " ";
 -		region_text.setArg("[REGION]", llformat ("%s", gAgent.getRegion()->getName().c_str()));
 -		support.append(region_text);
 -
 -		std::string buffer;
 -		buffer = gAgent.getRegion()->getHost().getHostName();
 -		support.append(buffer);
 -		support.append(" (");
 -		buffer = gAgent.getRegion()->getHost().getString();
 -		support.append(buffer);
 -		support.append(")\n");
 -		support.append(gLastVersionChannel);
 -		support.append("\n");
 -		support.append("[" + LLWeb::escapeURL(region->getCapability("ServerReleaseNotes")) +
 -					   " " + LLTrans::getString("ReleaseNotes") + "]");
 -		support.append("\n\n");
 +		info["POSITION"] = ll_sd_from_vector3d(pos);
 +		info["REGION"] = gAgent.getRegion()->getName();
 +		info["HOSTNAME"] = gAgent.getRegion()->getHost().getHostName();
 +		info["HOSTIP"] = gAgent.getRegion()->getHost().getString();
 +		info["SERVER_VERSION"] = gLastVersionChannel;
 +		info["SERVER_RELEASE_NOTES_URL"] = LLWeb::escapeURL(region->getCapability("ServerReleaseNotes"));
  	}
 -	// *NOTE: Do not translate text like GPU, Graphics Card, etc -
 -	//  Most PC users that know what these mean will be used to the english versions,
 -	//  and this info sometimes gets sent to support
 -	
  	// CPU
 -	support.append(getString("CPU") + " ");
 -	support.append( gSysCPU.getCPUString() );
 -	support.append("\n");
 -
 -	U32 memory = gSysMemory.getPhysicalMemoryKB() / 1024;
 +	info["CPU"] = gSysCPU.getCPUString();
 +	info["MEMORY_MB"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB() / 1024);
  	// Moved hack adjustment to Windows memory size into llsys.cpp
 -
 -	LLStringUtil::format_map_t args;
 -	args["[MEM]"] = llformat ("%u", memory);
 -	support.append(getString("Memory", args) + "\n");
 -
 -	support.append(getString("OSVersion") + " ");
 -	support.append( LLAppViewer::instance()->getOSInfo().getOSString() );
 -	support.append("\n");
 -
 -	support.append(getString("GraphicsCardVendor") + " ");
 -	support.append( (const char*) glGetString(GL_VENDOR) );
 -	support.append("\n");
 -
 -	support.append(getString("GraphicsCard") + " ");
 -	support.append( (const char*) glGetString(GL_RENDERER) );
 -	support.append("\n");
 +	info["OS_VERSION"] = LLAppViewer::instance()->getOSInfo().getOSString();
 +	info["GRAPHICS_CARD_VENDOR"] = (const char*)(glGetString(GL_VENDOR));
 +	info["GRAPHICS_CARD"] = (const char*)(glGetString(GL_RENDERER));
  #if LL_WINDOWS
 -    getWindow()->incBusyCount();
 -    getWindow()->setCursor(UI_CURSOR_ARROW);
 -    support.append("Windows Graphics Driver Version: ");
      LLSD driver_info = gDXHardware.getDisplayInfo();
      if (driver_info.has("DriverVersion"))
      {
 -        support.append(driver_info["DriverVersion"]);
 +        info["GRAPHICS_DRIVER_VERSION"] = driver_info["DriverVersion"];
      }
 -    support.append("\n");
 -    getWindow()->decBusyCount();
 -    getWindow()->setCursor(UI_CURSOR_ARROW);
  #endif
 -	support.append(getString("OpenGLVersion") + " ");
 -	support.append( (const char*) glGetString(GL_VERSION) );
 -	support.append("\n");
 -
 -	support.append("\n");
 -
 -	support.append(getString("LibCurlVersion") + " ");
 -	support.append( LLCurl::getVersionString() );
 -	support.append("\n");
 -
 -	support.append(getString("J2CDecoderVersion") + " ");
 -	support.append( LLImageJ2C::getEngineInfo() );
 -	support.append("\n");
 -
 -	support.append(getString("AudioDriverVersion") + " ");
 +	info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION));
 +	info["LIBCURL_VERSION"] = LLCurl::getVersionString();
 +	info["J2C_VERSION"] = LLImageJ2C::getEngineInfo();
  	bool want_fullname = true;
 -	support.append( gAudiop ? gAudiop->getDriverName(want_fullname) : getString("none") );
 -	support.append("\n");
 +	info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : LLSD();
  	// TODO: Implement media plugin version query
 -
 -	support.append(getString("LLQtWebkitVersion") + " ");
 -	support.append("\n");
 +	info["QT_WEBKIT_VERSION"] = "4.5.2";
  	if (gPacketsIn > 0)
  	{
 -		args["[LOST]"] = llformat ("%.0f", LLViewerStats::getInstance()->mPacketsLostStat.getCurrent());
 -		args["[IN]"] = llformat ("%.0f", F32(gPacketsIn));
 -		args["[PCT]"] = llformat ("%.1f", 100.f*LLViewerStats::getInstance()->mPacketsLostStat.getCurrent() / F32(gPacketsIn) );
 -		support.append(getString ("PacketsLost", args) + "\n");
 +		info["PACKETS_LOST"] = LLViewerStats::getInstance()->mPacketsLostStat.getCurrent();
 +		info["PACKETS_IN"] = F32(gPacketsIn);
 +		info["PACKETS_PCT"] = 100.f*info["PACKETS_LOST"].asReal() / info["PACKETS_IN"].asReal();
  	}
 -	support_widget->appendText(support, 
 -								FALSE, 
 -								LLStyle::Params()
 -									.color(LLUIColorTable::instance().getColor("TextFgReadOnlyColor")));
 -	support_widget->blockUndo();
 -
 -	// Fix views
 -	support_widget->setCursorPos(0);
 -	support_widget->setEnabled(FALSE);
 -
 -	credits_widget->setCursorPos(0);
 -	credits_widget->setEnabled(FALSE);
 -
 -	return TRUE;
 +    return info;
  }
 -
  static std::string get_viewer_release_notes_url()
  {
  	std::ostringstream version;
 @@ -272,6 +300,27 @@ static std::string get_viewer_release_notes_url()  	return LLWeb::escapeURL(url.str());
  }
 +class LLFloaterAboutListener: public LLDispatchListener
 +{
 +public:
 +	LLFloaterAboutListener():
 +		LLDispatchListener("LLFloaterAbout", "op")
 +	{
 +		add("getInfo", &LLFloaterAboutListener::getInfo, LLSD().insert("reply", LLSD()));
 +	}
 +
 +private:
 +	void getInfo(const LLSD& request) const
 +	{
 +		LLReqID reqid(request);
 +		LLSD reply(LLFloaterAbout::getInfo());
 +		reqid.stamp(reply);
 +		LLEventPumps::instance().obtain(request["reply"]).post(reply);
 +	}
 +};
 +
 +static LLFloaterAboutListener floaterAboutListener;
 +
  void LLFloaterAbout::onClickCopyToClipboard()
  {
  	LLViewerTextEditor *support_widget = 
 diff --git a/indra/newview/llfloaterchatterbox.cpp b/indra/newview/llfloaterchatterbox.cpp index dea656b0e4..fbf09207fe 100644 --- a/indra/newview/llfloaterchatterbox.cpp +++ b/indra/newview/llfloaterchatterbox.cpp @@ -42,7 +42,7 @@  #include "llfloaterfriends.h"  #include "llfloatergroups.h"  #include "llviewercontrol.h" -#include "llimview.h" +#include "llvoicechannel.h"  #include "llimpanel.h"  // diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp index c890f9f122..a47916b7d7 100644 --- a/indra/newview/llfloaterinventory.cpp +++ b/indra/newview/llfloaterinventory.cpp @@ -1438,7 +1438,11 @@ void LLInventoryPanel::modelChanged(U32 mask)  						}  						LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolders->getItemByID(model_item->getParentUUID()); -						if (view_item->getParentFolder() != new_parent) + +						// added check against NULL for cases when Inventory panel contains startFolder. +						// in this case parent is LLFolderView (LLInventoryPanel::mFolders) itself. +						// this check is a fix for bug EXT-1859. +						if (NULL != new_parent && view_item->getParentFolder() != new_parent)  						{  							view_item->getParentFolder()->extractItem(view_item);  							view_item->addToFolder(new_parent, mFolders); diff --git a/indra/newview/llfloatervoicedevicesettings.cpp b/indra/newview/llfloatervoicedevicesettings.cpp index b64257b11d..aca9198f59 100644 --- a/indra/newview/llfloatervoicedevicesettings.cpp +++ b/indra/newview/llfloatervoicedevicesettings.cpp @@ -43,7 +43,7 @@  #include "llsliderctrl.h"  #include "llviewercontrol.h"  #include "llvoiceclient.h" -#include "llimpanel.h" +#include "llvoicechannel.h"  // Library includes (after viewer)  #include "lluictrlfactory.h" diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index a20b5ea66c..b86795f696 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -42,7 +42,6 @@  #include "llchiclet.h"  #include "llfloaterchat.h"  #include "llfloaterreg.h" -#include "llimview.h"  #include "lllineeditor.h"  #include "lllogchat.h"  #include "llpanelimcontrolpanel.h" @@ -50,6 +49,7 @@  #include "lltrans.h"  #include "llchathistory.h"  #include "llviewerwindow.h" +#include "llvoicechannel.h"  #include "lltransientfloatermgr.h" @@ -61,7 +61,14 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id)  	mLastMessageIndex(-1),  	mDialog(IM_NOTHING_SPECIAL),  	mChatHistory(NULL), -	mInputEditor(NULL),  +	mInputEditor(NULL), +	mSavedTitle(), +	mTypingStart(), +	mShouldSendTypingState(false), +	mMeTyping(false), +	mOtherTyping(false), +	mTypingTimer(), +	mTypingTimeoutTimer(),  	mPositioned(false),  	mSessionInitialized(false)  { @@ -71,12 +78,15 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id)  		mSessionInitialized = im_session->mSessionInitialized;  		mDialog = im_session->mType; -		if (IM_NOTHING_SPECIAL == mDialog || IM_SESSION_P2P_INVITE == mDialog) -		{ +		switch(mDialog){ +		case IM_NOTHING_SPECIAL: +		case IM_SESSION_P2P_INVITE:  			mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelIMControl, this); -		} -		else -		{ +			break; +		case IM_SESSION_CONFERENCE_START: +			mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelAdHocControl, this); +			break; +		default:  			mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelGroupControl, this);  		}  	} @@ -95,6 +105,7 @@ void LLIMFloater::onFocusReceived()  // virtual  void LLIMFloater::onClose(bool app_quitting)  { +	setTyping(false);  	gIMMgr->leaveSession(mSessionID);  } @@ -141,6 +152,7 @@ void LLIMFloater::onSendMsg( LLUICtrl* ctrl, void* userdata )  {  	LLIMFloater* self = (LLIMFloater*) userdata;  	self->sendMsg(); +	self->setTyping(false);  }  void LLIMFloater::sendMsg() @@ -193,9 +205,10 @@ BOOL LLIMFloater::postBuild()  	if (other_party_id.notNull())  	{  		mOtherParticipantUUID = other_party_id; -		mControlPanel->setID(mOtherParticipantUUID);  	} +	mControlPanel->setSessionId(mSessionID); +  	LLButton* slide_left = getChild<LLButton>("slide_left_btn");  	slide_left->setVisible(mControlPanel->getVisible());  	slide_left->setClickedCallback(boost::bind(&LLIMFloater::onSlide, this)); @@ -228,12 +241,37 @@ BOOL LLIMFloater::postBuild()  		LLLogChat::loadHistory(getTitle(), &chatFromLogFile, (void *)this);  	} +	mTypingStart = LLTrans::getString("IM_typing_start_string"); + +	// Disable input editor if session cannot accept text +	LLIMModel::LLIMSession* im_session = +		LLIMModel::instance().findIMSession(mSessionID); +	if( im_session && !im_session->mTextIMPossible ) +	{ +		mInputEditor->setEnabled(FALSE); +		mInputEditor->setLabel(LLTrans::getString("IM_unavailable_text_label")); +	} +  	//*TODO if session is not initialized yet, add some sort of a warning message like "starting session...blablabla"  	//see LLFloaterIMPanel for how it is done (IB)  	return LLDockableFloater::postBuild();  } +// virtual +void LLIMFloater::draw() +{ +	if ( mMeTyping ) +	{ +		// Time out if user hasn't typed for a while. +		if ( mTypingTimeoutTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS ) +		{ +			setTyping(false); +		} +	} + +	LLFloater::draw(); +}  // static @@ -255,6 +293,15 @@ void* LLIMFloater::createPanelGroupControl(void* userdata)  	return self->mControlPanel;  } +// static +void* LLIMFloater::createPanelAdHocControl(void* userdata) +{ +	LLIMFloater *self = (LLIMFloater*)userdata; +	self->mControlPanel = new LLPanelAdHocControlPanel(self->mSessionID); +	self->mControlPanel->setXMLFilename("panel_adhoc_control_panel.xml"); +	return self->mControlPanel; +} +  void LLIMFloater::onSlide()  {  	LLPanel* im_control_panel = getChild<LLPanel>("panel_im_control_panel"); @@ -379,10 +426,12 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)  {  	mSessionInitialized = true; +	//will be different only for an ad-hoc im session  	if (mSessionID != im_session_id)  	{  		mSessionID = im_session_id;  		setKey(im_session_id); +		mControlPanel->setSessionId(im_session_id);  	}  	//*TODO here we should remove "starting session..." warning message if we added it in postBuild() (IB) @@ -402,7 +451,8 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)  void LLIMFloater::updateMessages()  { -	std::list<LLSD> messages = LLIMModel::instance().getMessages(mSessionID, mLastMessageIndex+1); +	std::list<LLSD> messages; +	LLIMModel::instance().getMessages(mSessionID, messages, mLastMessageIndex+1);  	std::string agent_name;  	gCacheName->getFullName(gAgentID, agent_name); @@ -428,7 +478,11 @@ void LLIMFloater::updateMessages()  			if (from == agent_name)  				from = LLTrans::getString("You"); -			mChatHistory->appendWidgetMessage(from_id, from, time, message, style_params); +			LLChat chat(message); +			chat.mFromID = from_id; +			chat.mFromName = from; + +			mChatHistory->appendWidgetMessage(chat, style_params);  			mLastMessageIndex = msg["index"].asInteger();  		} @@ -440,9 +494,14 @@ void LLIMFloater::onInputEditorFocusReceived( LLFocusableElement* caller, void*  {  	LLIMFloater* self= (LLIMFloater*) userdata; -	//in disconnected state IM input editor should be disabled -	self->mInputEditor->setEnabled(!gDisconnected); - +	// Allow enabling the LLIMFloater input editor only if session can accept text +	LLIMModel::LLIMSession* im_session = +		LLIMModel::instance().findIMSession(self->mSessionID); +	if( im_session && im_session->mTextIMPossible ) +	{ +		//in disconnected state IM input editor should be disabled +		self->mInputEditor->setEnabled(!gDisconnected); +	}  	self->mChatHistory->setCursorAndScrollToEnd();  } @@ -450,7 +509,7 @@ void LLIMFloater::onInputEditorFocusReceived( LLFocusableElement* caller, void*  void LLIMFloater::onInputEditorFocusLost(LLFocusableElement* caller, void* userdata)  {  	LLIMFloater* self = (LLIMFloater*) userdata; -	self->setTyping(FALSE); +	self->setTyping(false);  }  // static @@ -460,19 +519,142 @@ void LLIMFloater::onInputEditorKeystroke(LLLineEditor* caller, void* userdata)  	std::string text = self->mInputEditor->getText();  	if (!text.empty())  	{ -		self->setTyping(TRUE); +		self->setTyping(true);  	}  	else  	{  		// Deleting all text counts as stopping typing. -		self->setTyping(FALSE); +		self->setTyping(false);  	}  } +void LLIMFloater::setTyping(bool typing) +{ +	if ( typing ) +	{ +		// Started or proceeded typing, reset the typing timeout timer +		mTypingTimeoutTimer.reset(); +	} + +	if ( mMeTyping != typing ) +	{ +		// Typing state is changed +		mMeTyping = typing; +		// So, should send current state +		mShouldSendTypingState = true; +		// In case typing is started, send state after some delay +		mTypingTimer.reset(); +	} + +	// Don't want to send typing indicators to multiple people, potentially too +	// much network traffic. Only send in person-to-person IMs. +	if ( mShouldSendTypingState && mDialog == IM_NOTHING_SPECIAL ) +	{ +		if ( mMeTyping ) +		{ +			if ( mTypingTimer.getElapsedTimeF32() > 1.f ) +			{ +				// Still typing, send 'start typing' notification +				LLIMModel::instance().sendTypingState(mSessionID, mOtherParticipantUUID, TRUE); +				mShouldSendTypingState = false; +			} +		} +		else +		{ +			// Send 'stop typing' notification immediately +			LLIMModel::instance().sendTypingState(mSessionID, mOtherParticipantUUID, FALSE); +			mShouldSendTypingState = false; +		} +	} -//just a stub for now -void LLIMFloater::setTyping(BOOL typing) +	LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); +	if (speaker_mgr) +		speaker_mgr->setSpeakerTyping(gAgent.getID(), FALSE); + +} + +void LLIMFloater::processIMTyping(const LLIMInfo* im_info, BOOL typing) +{ +	if ( typing ) +	{ +		// other user started typing +		addTypingIndicator(im_info); +	} +	else +	{ +		// other user stopped typing +		removeTypingIndicator(im_info); +	} +} + +void LLIMFloater::processSessionUpdate(const LLSD& session_update) +{ +	// *TODO : verify following code when moderated mode will be implemented +	if ( false && session_update.has("moderated_mode") && +		 session_update["moderated_mode"].has("voice") ) +	{ +		BOOL voice_moderated = session_update["moderated_mode"]["voice"]; +		const std::string session_label = LLIMModel::instance().getName(mSessionID); + +		if (voice_moderated) +		{ +			setTitle(session_label + std::string(" ") + LLTrans::getString("IM_moderated_chat_label")); +		} +		else +		{ +			setTitle(session_label); +		} + +		// *TODO : uncomment this when/if LLPanelActiveSpeakers panel will be added +		//update the speakers dropdown too +		//mSpeakerPanel->setVoiceModerationCtrlMode(voice_moderated); +	} +} + +void LLIMFloater::addTypingIndicator(const LLIMInfo* im_info)  { +	// We may have lost a "stop-typing" packet, don't add it twice +	if ( im_info && !mOtherTyping ) +	{ +		mOtherTyping = true; + +		// Create typing is started title string +		LLUIString typing_start(mTypingStart); +		typing_start.setArg("[NAME]", im_info->mName); + +		// Save and set new title +		mSavedTitle = getTitle(); +		setTitle (typing_start); + +		// Update speaker +		LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); +		if ( speaker_mgr ) +		{ +			speaker_mgr->setSpeakerTyping(im_info->mFromID, TRUE); +		} +	} +} + +void LLIMFloater::removeTypingIndicator(const LLIMInfo* im_info) +{ +	if ( mOtherTyping ) +	{ +		mOtherTyping = false; + +		// Revert the title to saved one +		setTitle(mSavedTitle); + +		if ( im_info ) +		{ +			// Update speaker +			LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); +			if ( speaker_mgr ) +			{ +				speaker_mgr->setSpeakerTyping(im_info->mFromID, FALSE); +			} +		} + +	}  }  void LLIMFloater::chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata) diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index 99810b6d6d..3da27ac941 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -55,6 +55,8 @@ public:  	// LLView overrides  	/*virtual*/ BOOL postBuild();  	/*virtual*/ void setVisible(BOOL visible); +	// Check typing timeout timer. +	/*virtual*/ void draw();  	// LLFloater overrides  	/*virtual*/ void onClose(bool app_quitting); @@ -85,6 +87,8 @@ public:  	void setPositioned(bool b) { mPositioned = b; };  	void onVisibilityChange(const LLSD& new_visibility); +	void processIMTyping(const LLIMInfo* im_info, BOOL typing); +	void processSessionUpdate(const LLSD& session_update);  private:  	// process focus events to set a currently active session @@ -94,15 +98,21 @@ private:  	static void		onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata );  	static void		onInputEditorFocusLost(LLFocusableElement* caller, void* userdata);  	static void		onInputEditorKeystroke(LLLineEditor* caller, void* userdata); -	void			setTyping(BOOL typing); +	void			setTyping(bool typing);  	void			onSlide();  	static void*	createPanelIMControl(void* userdata);  	static void*	createPanelGroupControl(void* userdata); +	static void* 	createPanelAdHocControl(void* userdata);  	// gets a rect that bounds possible positions for the LLIMFloater on a screen (EXT-1111)  	void getAllowedRect(LLRect& rect);  	static void chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata); +	// Add the "User is typing..." indicator. +	void addTypingIndicator(const LLIMInfo* im_info); + +	// Remove the "User is typing..." indicator. +	void removeTypingIndicator(const LLIMInfo* im_info = NULL);  	LLPanelChatControlPanel* mControlPanel;  	LLUUID mSessionID; @@ -114,6 +124,14 @@ private:  	LLLineEditor* mInputEditor;  	bool mPositioned; +	std::string mSavedTitle; +	LLUIString mTypingStart; +	bool mMeTyping; +	bool mOtherTyping; +	bool mShouldSendTypingState; +	LLFrameTimer mTypingTimer; +	LLFrameTimer mTypingTimeoutTimer; +  	bool mSessionInitialized;  	LLSD mQueuedMsgsForInit;  }; diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 163984f740..77ee90f681 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -54,6 +54,7 @@  #include "llconsole.h"  #include "llgroupactions.h"  #include "llfloater.h" +#include "llfloateractivespeakers.h"  #include "llfloatercall.h"  #include "llavataractions.h"  #include "llimview.h" @@ -77,6 +78,7 @@  #include "llviewercontrol.h"  #include "lluictrlfactory.h"  #include "llviewerwindow.h" +#include "llvoicechannel.h"  #include "lllogchat.h"  #include "llweb.h"  #include "llhttpclient.h" @@ -90,7 +92,6 @@  const S32 LINE_HEIGHT = 16;  const S32 MIN_WIDTH = 200;  const S32 MIN_HEIGHT = 130; -const U32 DEFAULT_RETRIES_COUNT = 3;  //  // Statics @@ -100,831 +101,6 @@ static std::string sTitleString = "Instant Message with [NAME]";  static std::string sTypingStartString = "[NAME]: ...";  static std::string sSessionStartString = "Starting session with [NAME] please wait."; -LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap; -LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap; -LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL; -LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL; - -BOOL LLVoiceChannel::sSuspended = FALSE; - - - -class LLVoiceCallCapResponder : public LLHTTPClient::Responder -{ -public: -	LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; - -	virtual void error(U32 status, const std::string& reason);	// called with bad status codes -	virtual void result(const LLSD& content); - -private: -	LLUUID mSessionID; -}; - - -void LLVoiceCallCapResponder::error(U32 status, const std::string& reason) -{ -	llwarns << "LLVoiceCallCapResponder::error(" -		<< status << ": " << reason << ")" -		<< llendl; -	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); -	if ( channelp ) -	{ -		if ( 403 == status ) -		{ -			//403 == no ability -			LLNotifications::instance().add( -				"VoiceNotAllowed", -				channelp->getNotifyArgs()); -		} -		else -		{ -			LLNotifications::instance().add( -				"VoiceCallGenericError", -				channelp->getNotifyArgs()); -		} -		channelp->deactivate(); -	} -} - -void LLVoiceCallCapResponder::result(const LLSD& content) -{ -	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); -	if (channelp) -	{ -		//*TODO: DEBUG SPAM -		LLSD::map_const_iterator iter; -		for(iter = content.beginMap(); iter != content.endMap(); ++iter) -		{ -			llinfos << "LLVoiceCallCapResponder::result got "  -				<< iter->first << llendl; -		} - -		channelp->setChannelInfo( -			content["voice_credentials"]["channel_uri"].asString(), -			content["voice_credentials"]["channel_credentials"].asString()); -	} -} - -// -// LLVoiceChannel -// -LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) :  -	mSessionID(session_id),  -	mState(STATE_NO_CHANNEL_INFO),  -	mSessionName(session_name), -	mIgnoreNextSessionLeave(FALSE) -{ -	mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName; - -	if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second) -	{ -		// a voice channel already exists for this session id, so this instance will be orphaned -		// the end result should simply be the failure to make voice calls -		llwarns << "Duplicate voice channels registered for session_id " << session_id << llendl; -	} - -	LLVoiceClient::getInstance()->addObserver(this); -} - -LLVoiceChannel::~LLVoiceChannel() -{ -	// Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed. -	if(gVoiceClient) -	{ -		gVoiceClient->removeObserver(this); -	} -	 -	sVoiceChannelMap.erase(mSessionID); -	sVoiceChannelURIMap.erase(mURI); -} - -void LLVoiceChannel::setChannelInfo( -	const std::string& uri, -	const std::string& credentials) -{ -	setURI(uri); - -	mCredentials = credentials; - -	if (mState == STATE_NO_CHANNEL_INFO) -	{ -		if (mURI.empty()) -		{ -			LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); -			llwarns << "Received empty URI for channel " << mSessionName << llendl; -			deactivate(); -		} -		else if (mCredentials.empty()) -		{ -			LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); -			llwarns << "Received empty credentials for channel " << mSessionName << llendl; -			deactivate(); -		} -		else -		{ -			setState(STATE_READY); - -			// if we are supposed to be active, reconnect -			// this will happen on initial connect, as we request credentials on first use -			if (sCurrentVoiceChannel == this) -			{ -				// just in case we got new channel info while active -				// should move over to new channel -				activate(); -			} -		} -	} -} - -void LLVoiceChannel::onChange(EStatusType type, const std::string &channelURI, bool proximal) -{ -	if (channelURI != mURI) -	{ -		return; -	} - -	if (type < BEGIN_ERROR_STATUS) -	{ -		handleStatusChange(type); -	} -	else -	{ -		handleError(type); -	} -} - -void LLVoiceChannel::handleStatusChange(EStatusType type) -{ -	// status updates -	switch(type) -	{ -	case STATUS_LOGIN_RETRY: -		//mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle(); -		LLNotifications::instance().add("VoiceLoginRetry"); -		break; -	case STATUS_LOGGED_IN: -		//if (!mLoginNotificationHandle.isDead()) -		//{ -		//	LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get(); -		//	if (notifyp) -		//	{ -		//		notifyp->close(); -		//	} -		//	mLoginNotificationHandle.markDead(); -		//} -		break; -	case STATUS_LEFT_CHANNEL: -		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) -		{ -			// if forceably removed from channel -			// update the UI and revert to default channel -			LLNotifications::instance().add("VoiceChannelDisconnected", mNotifyArgs); -			deactivate(); -		} -		mIgnoreNextSessionLeave = FALSE; -		break; -	case STATUS_JOINING: -		if (callStarted()) -		{ -			setState(STATE_RINGING); -		} -		break; -	case STATUS_JOINED: -		if (callStarted()) -		{ -			setState(STATE_CONNECTED); -		} -	default: -		break; -	} -} - -// default behavior is to just deactivate channel -// derived classes provide specific error messages -void LLVoiceChannel::handleError(EStatusType type) -{ -	deactivate(); -	setState(STATE_ERROR); -} - -BOOL LLVoiceChannel::isActive() -{  -	// only considered active when currently bound channel matches what our channel -	return callStarted() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI;  -} - -BOOL LLVoiceChannel::callStarted() -{ -	return mState >= STATE_CALL_STARTED; -} - -void LLVoiceChannel::deactivate() -{ -	if (mState >= STATE_RINGING) -	{ -		// ignore session leave event -		mIgnoreNextSessionLeave = TRUE; -	} - -	if (callStarted()) -	{ -		setState(STATE_HUNG_UP); -		// mute the microphone if required when returning to the proximal channel -		if (gSavedSettings.getBOOL("AutoDisengageMic") && sCurrentVoiceChannel == this) -		{ -			gSavedSettings.setBOOL("PTTCurrentlyEnabled", true); -		} -	} - -	if (sCurrentVoiceChannel == this) -	{ -		// default channel is proximal channel -		sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); -		sCurrentVoiceChannel->activate(); -	} -} - -void LLVoiceChannel::activate() -{ -	if (callStarted()) -	{ -		return; -	} - -	// deactivate old channel and mark ourselves as the active one -	if (sCurrentVoiceChannel != this) -	{ -		// mark as current before deactivating the old channel to prevent -		// activating the proximal channel between IM calls -		LLVoiceChannel* old_channel = sCurrentVoiceChannel; -		sCurrentVoiceChannel = this; -		if (old_channel) -		{ -			old_channel->deactivate(); -		} -	} - -	if (mState == STATE_NO_CHANNEL_INFO) -	{ -		// responsible for setting status to active -		getChannelInfo(); -	} -	else -	{ -		setState(STATE_CALL_STARTED); -	} -} - -void LLVoiceChannel::getChannelInfo() -{ -	// pretend we have everything we need -	if (sCurrentVoiceChannel == this) -	{ -		setState(STATE_CALL_STARTED); -	} -} - -//static  -LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id) -{ -	voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id); -	if (found_it == sVoiceChannelMap.end()) -	{ -		return NULL; -	} -	else -	{ -		return found_it->second; -	} -} - -//static  -LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri) -{ -	voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri); -	if (found_it == sVoiceChannelURIMap.end()) -	{ -		return NULL; -	} -	else -	{ -		return found_it->second; -	} -} - -void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id) -{ -	sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID)); -	mSessionID = new_session_id; -	sVoiceChannelMap.insert(std::make_pair(mSessionID, this)); -} - -void LLVoiceChannel::setURI(std::string uri) -{ -	sVoiceChannelURIMap.erase(mURI); -	mURI = uri; -	sVoiceChannelURIMap.insert(std::make_pair(mURI, this)); -} - -void LLVoiceChannel::setState(EState state) -{ -	switch(state) -	{ -	case STATE_RINGING: -		gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs); -		break; -	case STATE_CONNECTED: -		gIMMgr->addSystemMessage(mSessionID, "connected", mNotifyArgs); -		break; -	case STATE_HUNG_UP: -		gIMMgr->addSystemMessage(mSessionID, "hang_up", mNotifyArgs); -		break; -	default: -		break; -	} - -	mState = state; -} - -void LLVoiceChannel::toggleCallWindowIfNeeded(EState state) -{ -	if (state == STATE_CONNECTED) -	{ -		LLFloaterReg::showInstance("voice_call", mSessionID); -	} -	// By checking that current state is CONNECTED we make sure that the call window -	// has been shown, hence there's something to hide. This helps when user presses -	// the "End call" button right after initiating the call. -	// *TODO: move this check to LLFloaterCall? -	else if (state == STATE_HUNG_UP && mState == STATE_CONNECTED) -	{ -		LLFloaterReg::hideInstance("voice_call", mSessionID); -	} -} - -//static -void LLVoiceChannel::initClass() -{ -	sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); -} - - -//static  -void LLVoiceChannel::suspend() -{ -	if (!sSuspended) -	{ -		sSuspendedVoiceChannel = sCurrentVoiceChannel; -		sSuspended = TRUE; -	} -} - -//static  -void LLVoiceChannel::resume() -{ -	if (sSuspended) -	{ -		if (gVoiceClient->voiceEnabled()) -		{ -			if (sSuspendedVoiceChannel) -			{ -				sSuspendedVoiceChannel->activate(); -			} -			else -			{ -				LLVoiceChannelProximal::getInstance()->activate(); -			} -		} -		sSuspended = FALSE; -	} -} - - -// -// LLVoiceChannelGroup -// - -LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) :  -	LLVoiceChannel(session_id, session_name) -{ -	mRetries = DEFAULT_RETRIES_COUNT; -	mIsRetrying = FALSE; -} - -void LLVoiceChannelGroup::deactivate() -{ -	if (callStarted()) -	{ -		LLVoiceClient::getInstance()->leaveNonSpatialChannel(); -	} -	LLVoiceChannel::deactivate(); -} - -void LLVoiceChannelGroup::activate() -{ -	if (callStarted()) return; - -	LLVoiceChannel::activate(); - -	if (callStarted()) -	{ -		// we have the channel info, just need to use it now -		LLVoiceClient::getInstance()->setNonSpatialChannel( -			mURI, -			mCredentials); - -#if 0 // *TODO -		if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel -		{ -			// Add the party to the list of people with which we've recently interacted. -			for (/*people in the chat*/) -				LLRecentPeople::instance().add(buddy_id); -		} -#endif -	} -} - -void LLVoiceChannelGroup::getChannelInfo() -{ -	LLViewerRegion* region = gAgent.getRegion(); -	if (region) -	{ -		std::string url = region->getCapability("ChatSessionRequest"); -		LLSD data; -		data["method"] = "call"; -		data["session-id"] = mSessionID; -		LLHTTPClient::post(url, -						   data, -						   new LLVoiceCallCapResponder(mSessionID)); -	} -} - -void LLVoiceChannelGroup::setChannelInfo( -	const std::string& uri, -	const std::string& credentials) -{ -	setURI(uri); - -	mCredentials = credentials; - -	if (mState == STATE_NO_CHANNEL_INFO) -	{ -		if(!mURI.empty() && !mCredentials.empty()) -		{ -			setState(STATE_READY); - -			// if we are supposed to be active, reconnect -			// this will happen on initial connect, as we request credentials on first use -			if (sCurrentVoiceChannel == this) -			{ -				// just in case we got new channel info while active -				// should move over to new channel -				activate(); -			} -		} -		else -		{ -			//*TODO: notify user -			llwarns << "Received invalid credentials for channel " << mSessionName << llendl; -			deactivate(); -		} -	} -	else if ( mIsRetrying ) -	{ -		// we have the channel info, just need to use it now -		LLVoiceClient::getInstance()->setNonSpatialChannel( -			mURI, -			mCredentials); -	} -} - -void LLVoiceChannelGroup::handleStatusChange(EStatusType type) -{ -	// status updates -	switch(type) -	{ -	case STATUS_JOINED: -		mRetries = 3; -		mIsRetrying = FALSE; -	default: -		break; -	} - -	LLVoiceChannel::handleStatusChange(type); -} - -void LLVoiceChannelGroup::handleError(EStatusType status) -{ -	std::string notify; -	switch(status) -	{ -	case ERROR_CHANNEL_LOCKED: -	case ERROR_CHANNEL_FULL: -		notify = "VoiceChannelFull"; -		break; -	case ERROR_NOT_AVAILABLE: -		//clear URI and credentials -		//set the state to be no info -		//and activate -		if ( mRetries > 0 ) -		{ -			mRetries--; -			mIsRetrying = TRUE; -			mIgnoreNextSessionLeave = TRUE; - -			getChannelInfo(); -			return; -		} -		else -		{ -			notify = "VoiceChannelJoinFailed"; -			mRetries = DEFAULT_RETRIES_COUNT; -			mIsRetrying = FALSE; -		} - -		break; - -	case ERROR_UNKNOWN: -	default: -		break; -	} - -	// notification -	if (!notify.empty()) -	{ -		LLNotificationPtr notification = LLNotifications::instance().add(notify, mNotifyArgs); -		// echo to im window -		gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage()); -	} - -	LLVoiceChannel::handleError(status); -} - -void LLVoiceChannelGroup::setState(EState state) -{ -	// HACK: Open/close the call window if needed. -	toggleCallWindowIfNeeded(state); - -	switch(state) -	{ -	case STATE_RINGING: -		if ( !mIsRetrying ) -		{ -			gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs); -		} - -		mState = state; -		break; -	default: -		LLVoiceChannel::setState(state); -	} -} - -// -// LLVoiceChannelProximal -// -LLVoiceChannelProximal::LLVoiceChannelProximal() :  -	LLVoiceChannel(LLUUID::null, LLStringUtil::null) -{ -	activate(); -} - -BOOL LLVoiceChannelProximal::isActive() -{ -	return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();  -} - -void LLVoiceChannelProximal::activate() -{ -	if (callStarted()) return; - -	LLVoiceChannel::activate(); - -	if (callStarted()) -	{ -		// this implicitly puts you back in the spatial channel -		LLVoiceClient::getInstance()->leaveNonSpatialChannel(); -	} -} - -void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal) -{ -	if (!proximal) -	{ -		return; -	} - -	if (type < BEGIN_ERROR_STATUS) -	{ -		handleStatusChange(type); -	} -	else -	{ -		handleError(type); -	} -} - -void LLVoiceChannelProximal::handleStatusChange(EStatusType status) -{ -	// status updates -	switch(status) -	{ -	case STATUS_LEFT_CHANNEL: -		// do not notify user when leaving proximal channel -		return; -	case STATUS_VOICE_DISABLED: -		 gIMMgr->addSystemMessage(LLUUID::null, "unavailable", mNotifyArgs); -		return; -	default: -		break; -	} -	LLVoiceChannel::handleStatusChange(status); -} - - -void LLVoiceChannelProximal::handleError(EStatusType status) -{ -	std::string notify; -	switch(status) -	{ -	  case ERROR_CHANNEL_LOCKED: -	  case ERROR_CHANNEL_FULL: -		notify = "ProximalVoiceChannelFull"; -		break; -	  default: -		 break; -	} - -	// notification -	if (!notify.empty()) -	{ -		LLNotifications::instance().add(notify, mNotifyArgs); -	} - -	LLVoiceChannel::handleError(status); -} - -void LLVoiceChannelProximal::deactivate() -{ -	if (callStarted()) -	{ -		setState(STATE_HUNG_UP); -	} -} - - -// -// LLVoiceChannelP2P -// -LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id) :  -		LLVoiceChannelGroup(session_id, session_name),  -		mOtherUserID(other_user_id), -		mReceivedCall(FALSE) -{ -	// make sure URI reflects encoded version of other user's agent id -	setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id)); -} - -void LLVoiceChannelP2P::handleStatusChange(EStatusType type) -{ -	// status updates -	switch(type) -	{ -	case STATUS_LEFT_CHANNEL: -		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) -		{ -			if (mState == STATE_RINGING) -			{ -				// other user declined call -				LLNotifications::instance().add("P2PCallDeclined", mNotifyArgs); -			} -			else -			{ -				// other user hung up -				LLNotifications::instance().add("VoiceChannelDisconnectedP2P", mNotifyArgs); -			} -			deactivate(); -		} -		mIgnoreNextSessionLeave = FALSE; -		return; -	default: -		break; -	} - -	LLVoiceChannel::handleStatusChange(type); -} - -void LLVoiceChannelP2P::handleError(EStatusType type) -{ -	switch(type) -	{ -	case ERROR_NOT_AVAILABLE: -		LLNotifications::instance().add("P2PCallNoAnswer", mNotifyArgs); -		break; -	default: -		break; -	} - -	LLVoiceChannel::handleError(type); -} - -void LLVoiceChannelP2P::activate() -{ -	if (callStarted()) return; - -	LLVoiceChannel::activate(); - -	if (callStarted()) -	{ -		// no session handle yet, we're starting the call -		if (mSessionHandle.empty()) -		{ -			mReceivedCall = FALSE; -			LLVoiceClient::getInstance()->callUser(mOtherUserID); -		} -		// otherwise answering the call -		else -		{ -			LLVoiceClient::getInstance()->answerInvite(mSessionHandle); -			 -			// using the session handle invalidates it.  Clear it out here so we can't reuse it by accident. -			mSessionHandle.clear(); -		} - -		// Add the party to the list of people with which we've recently interacted. -		LLRecentPeople::instance().add(mOtherUserID); -	} -} - -void LLVoiceChannelP2P::getChannelInfo() -{ -	// pretend we have everything we need, since P2P doesn't use channel info -	if (sCurrentVoiceChannel == this) -	{ -		setState(STATE_CALL_STARTED); -	} -} - -// receiving session from other user who initiated call -void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::string &inURI) -{  -	BOOL needs_activate = FALSE; -	if (callStarted()) -	{ -		// defer to lower agent id when already active -		if (mOtherUserID < gAgent.getID()) -		{ -			// pretend we haven't started the call yet, so we can connect to this session instead -			deactivate(); -			needs_activate = TRUE; -		} -		else -		{ -			// we are active and have priority, invite the other user again -			// under the assumption they will join this new session -			mSessionHandle.clear(); -			LLVoiceClient::getInstance()->callUser(mOtherUserID); -			return; -		} -	} - -	mSessionHandle = handle; - -	// The URI of a p2p session should always be the other end's SIP URI. -	if(!inURI.empty()) -	{ -		setURI(inURI); -	} -	else -	{ -		setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID)); -	} -	 -	mReceivedCall = TRUE; - -	if (needs_activate) -	{ -		activate(); -	} -} - -void LLVoiceChannelP2P::setState(EState state) -{ -	// HACK: Open/close the call window if needed. -	toggleCallWindowIfNeeded(state); - -	// you only "answer" voice invites in p2p mode -	// so provide a special purpose message here -	if (mReceivedCall && state == STATE_RINGING) -	{ -		gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs); -		mState = state; -		return; -	} -	LLVoiceChannel::setState(state); -} -  //  // LLFloaterIMPanel @@ -1836,75 +1012,8 @@ void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string  	self->mHistoryEditor->blockUndo();  } -void LLFloaterIMPanel::showSessionStartError( -	const std::string& error_string) -{ -	LLSD args; -	args["REASON"] = LLTrans::getString(error_string); -	args["RECIPIENT"] = getTitle(); - -	LLSD payload; -	payload["session_id"] = mSessionUUID; - -	LLNotifications::instance().add( -		"ChatterBoxSessionStartError", -		args, -		payload, -		onConfirmForceCloseError); -} - -void LLFloaterIMPanel::showSessionEventError( -	const std::string& event_string, -	const std::string& error_string) -{ -	LLSD args; -	args["REASON"] = -		LLTrans::getString(error_string); -	args["EVENT"] = -		LLTrans::getString(event_string); -	args["RECIPIENT"] = getTitle(); - -	LLNotifications::instance().add( -		"ChatterBoxSessionEventError", -		args); -} - -void LLFloaterIMPanel::showSessionForceClose( -	const std::string& reason_string) -{ -	LLSD args; - -	args["NAME"] = getTitle(); -	args["REASON"] = LLTrans::getString(reason_string); - -	LLSD payload; -	payload["session_id"] = mSessionUUID; - -	LLNotifications::instance().add( -		"ForceCloseChatterBoxSession", -		args, -		payload, -		LLFloaterIMPanel::onConfirmForceCloseError); - -} -  //static   void LLFloaterIMPanel::onKickSpeaker(void* user_data)  {  } - -bool LLFloaterIMPanel::onConfirmForceCloseError(const LLSD& notification, const LLSD& response) -{ -	//only 1 option really -	LLUUID session_id = notification["payload"]["session_id"]; - -	if ( gIMMgr ) -	{ -		LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession( -			session_id); - -		if ( floaterp ) floaterp->closeFloater(FALSE); -	} -	return false; -} diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index 4e306c7fab..39107d9a22 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -50,133 +50,6 @@ class LLIMSpeakerMgr;  class LLPanelActiveSpeakers;  class LLPanelChatControlPanel; -class LLVoiceChannel : public LLVoiceClientStatusObserver -{ -public: -	typedef enum e_voice_channel_state -	{ -		STATE_NO_CHANNEL_INFO, -		STATE_ERROR, -		STATE_HUNG_UP, -		STATE_READY, -		STATE_CALL_STARTED, -		STATE_RINGING, -		STATE_CONNECTED -	} EState; - -	LLVoiceChannel(const LLUUID& session_id, const std::string& session_name); -	virtual ~LLVoiceChannel(); - -	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); - -	virtual void handleStatusChange(EStatusType status); -	virtual void handleError(EStatusType status); -	virtual void deactivate(); -	virtual void activate(); -	virtual void setChannelInfo( -		const std::string& uri, -		const std::string& credentials); -	virtual void getChannelInfo(); -	virtual BOOL isActive(); -	virtual BOOL callStarted(); -	const std::string& getSessionName() const { return mSessionName; } - -	const LLUUID getSessionID() { return mSessionID; } -	EState getState() { return mState; } - -	void updateSessionID(const LLUUID& new_session_id); -	const LLSD& getNotifyArgs() { return mNotifyArgs; } - -	static LLVoiceChannel* getChannelByID(const LLUUID& session_id); -	static LLVoiceChannel* getChannelByURI(std::string uri); -	static LLVoiceChannel* getCurrentVoiceChannel() { return sCurrentVoiceChannel; } -	static void initClass(); -	 -	static void suspend(); -	static void resume(); - -protected: -	virtual void setState(EState state); -	void toggleCallWindowIfNeeded(EState state); -	void setURI(std::string uri); - -	std::string	mURI; -	std::string	mCredentials; -	LLUUID		mSessionID; -	EState		mState; -	std::string	mSessionName; -	LLSD mNotifyArgs; -	BOOL		mIgnoreNextSessionLeave; -	LLHandle<LLPanel> mLoginNotificationHandle; - -	typedef std::map<LLUUID, LLVoiceChannel*> voice_channel_map_t; -	static voice_channel_map_t sVoiceChannelMap; - -	typedef std::map<std::string, LLVoiceChannel*> voice_channel_map_uri_t; -	static voice_channel_map_uri_t sVoiceChannelURIMap; - -	static LLVoiceChannel* sCurrentVoiceChannel; -	static LLVoiceChannel* sSuspendedVoiceChannel; -	static BOOL sSuspended; -}; - -class LLVoiceChannelGroup : public LLVoiceChannel -{ -public: -	LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name); - -	/*virtual*/ void handleStatusChange(EStatusType status); -	/*virtual*/ void handleError(EStatusType status); -	/*virtual*/ void activate(); -	/*virtual*/ void deactivate(); -	/*vritual*/ void setChannelInfo( -		const std::string& uri, -		const std::string& credentials); -	/*virtual*/ void getChannelInfo(); - -protected: -	virtual void setState(EState state); - -private: -	U32 mRetries; -	BOOL mIsRetrying; -}; - -class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoiceChannelProximal> -{ -public: -	LLVoiceChannelProximal(); - -	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); -	/*virtual*/ void handleStatusChange(EStatusType status); -	/*virtual*/ void handleError(EStatusType status); -	/*virtual*/ BOOL isActive(); -	/*virtual*/ void activate(); -	/*virtual*/ void deactivate(); - -}; - -class LLVoiceChannelP2P : public LLVoiceChannelGroup -{ -public: -	LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id); - -	/*virtual*/ void handleStatusChange(EStatusType status); -	/*virtual*/ void handleError(EStatusType status); -    /*virtual*/ void activate(); -	/*virtual*/ void getChannelInfo(); - -	void setSessionHandle(const std::string& handle, const std::string &inURI); - -protected: -	virtual void setState(EState state); - -private: -	std::string	mSessionHandle; -	LLUUID		mOtherUserID; -	BOOL		mReceivedCall; -}; -  class LLFloaterIMPanel : public LLFloater  {  public: @@ -256,15 +129,6 @@ public:  	void processIMTyping(const LLIMInfo* im_info, BOOL typing);  	static void chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata); -	//show error statuses to the user -	void showSessionStartError(const std::string& error_string); -	void showSessionEventError( -		const std::string& event_string, -		const std::string& error_string); -	void showSessionForceClose(const std::string& reason); - -	static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response); -  private:  	// Called by UI methods.  	void sendMsg(); diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index b631c991ae..8a55ab41b9 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -70,6 +70,7 @@  #include "llviewerwindow.h"  #include "llnotify.h"  #include "llviewerregion.h" +#include "llvoicechannel.h"  #include "lltrans.h"  #include "llrecentpeople.h" @@ -144,7 +145,10 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&  	mInitialTargetIDs(ids),  	mVoiceChannel(NULL),  	mSpeakers(NULL), -	mSessionInitialized(false) +	mSessionInitialized(false), +	mCallBackEnabled(true), +	mTextIMPossible(true), +	mOtherParticipantIsAvatar(true)  {  	if (IM_NOTHING_SPECIAL == type || IM_SESSION_P2P_INVITE == type)  	{ @@ -168,6 +172,13 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&  		//so we're already initialized  		mSessionInitialized = true;  	} + +	if (IM_NOTHING_SPECIAL == type) +	{ +		mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID); +		mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID); +		mOtherParticipantIsAvatar = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionID); +	}  }  LLIMModel::LLIMSession::~LLIMSession() @@ -272,7 +283,8 @@ void LLIMModel::testMessages()  } -bool LLIMModel::newSession(LLUUID session_id, std::string name, EInstantMessage type, LLUUID other_participant_id, const std::vector<LLUUID>& ids) +bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type,  +						   const LLUUID& other_participant_id, const std::vector<LLUUID>& ids)  {  	if (is_in_map(sSessionsMap, session_id))  	{ @@ -289,7 +301,7 @@ bool LLIMModel::newSession(LLUUID session_id, std::string name, EInstantMessage  } -bool LLIMModel::clearSession(LLUUID session_id) +bool LLIMModel::clearSession(const LLUUID& session_id)  {  	if (sSessionsMap.find(session_id) == sSessionsMap.end()) return false;  	delete (sSessionsMap[session_id]); @@ -297,16 +309,13 @@ bool LLIMModel::clearSession(LLUUID session_id)  	return true;  } -//*TODO remake it, instead of returing the list pass it as as parameter (IB) -std::list<LLSD> LLIMModel::getMessages(LLUUID session_id, int start_index) +void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index)  { -	std::list<LLSD> return_list; -  	LLIMSession* session = findIMSession(session_id);  	if (!session)   	{  		llwarns << "session " << session_id << "does not exist " << llendl; -		return return_list; +		return;  	}  	int i = session->mMsgs.size() - start_index; @@ -317,7 +326,7 @@ std::list<LLSD> LLIMModel::getMessages(LLUUID session_id, int start_index)  	{  		LLSD msg;  		msg = *iter; -		return_list.push_back(*iter); +		messages.push_back(*iter);  		i--;  	} @@ -327,14 +336,9 @@ std::list<LLSD> LLIMModel::getMessages(LLUUID session_id, int start_index)  	arg["session_id"] = session_id;  	arg["num_unread"] = 0;  	mNoUnreadMsgsSignal(arg); - -    // TODO: in the future is there a more efficient way to return these -	//of course there is - return as parameter (IB) -	return return_list; -  } -bool LLIMModel::addToHistory(LLUUID session_id, std::string from, LLUUID from_id, std::string utf8_text) {  +bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) {  	LLIMSession* session = findIMSession(session_id); @@ -383,8 +387,8 @@ bool LLIMModel::logToFile(const LLUUID& session_id, const std::string& from, con  	return false;  } -//*TODO add const qualifier and pass by references (IB) -bool LLIMModel::addMessage(LLUUID session_id, std::string from, LLUUID from_id, std::string utf8_text, bool log2file /* = true */) {  +bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id,  +						   const std::string& utf8_text, bool log2file /* = true */) {   	LLIMSession* session = findIMSession(session_id);  	if (!session)  @@ -506,7 +510,7 @@ void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id,  	gAgent.sendReliableMessage();  } -void LLIMModel::sendLeaveSession(LLUUID session_id, LLUUID other_participant_id)  +void LLIMModel::sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id)  {  	if(session_id.notNull())  	{ @@ -890,20 +894,11 @@ public:  		{  			gIMMgr->clearPendingAgentListUpdates(mSessionID);  			gIMMgr->clearPendingInvitation(mSessionID); - -			LLFloaterIMPanel* floaterp = -				gIMMgr->findFloaterBySession(mSessionID); - -			if ( floaterp ) +			if ( 404 == statusNum )  			{ -				if ( 404 == statusNum ) -				{ -					std::string error_string; -					error_string = "does not exist"; - -					floaterp->showSessionStartError( -						error_string); -				} +				std::string error_string; +				error_string = "does not exist"; +				gIMMgr->showSessionStartError(error_string, mSessionID);  			}  		}  	} @@ -955,6 +950,106 @@ LLUUID LLIMMgr::computeSessionID(  	return session_id;  } +inline LLFloater* getFloaterBySessionID(const LLUUID session_id) +{ +	LLFloater* floater = NULL; +	if ( gIMMgr ) +	{ +		floater = dynamic_cast < LLFloater* > +			( gIMMgr->findFloaterBySession(session_id) ); +	} +	if ( !floater ) +	{ +		floater = dynamic_cast < LLFloater* > +			( LLIMFloater::findInstance(session_id) ); +	} +	return floater; +} + +void +LLIMMgr::showSessionStartError( +	const std::string& error_string, +	const LLUUID session_id) +{ +	const LLFloater* floater = getFloaterBySessionID (session_id); +	if (!floater) return; + +	LLSD args; +	args["REASON"] = LLTrans::getString(error_string); +	args["RECIPIENT"] = floater->getTitle(); + +	LLSD payload; +	payload["session_id"] = session_id; + +	LLNotifications::instance().add( +		"ChatterBoxSessionStartError", +		args, +		payload, +		LLIMMgr::onConfirmForceCloseError); +} + +void +LLIMMgr::showSessionEventError( +	const std::string& event_string, +	const std::string& error_string, +	const LLUUID session_id) +{ +	const LLFloater* floater = getFloaterBySessionID (session_id); +	if (!floater) return; + +	LLSD args; +	args["REASON"] = +		LLTrans::getString(error_string); +	args["EVENT"] = +		LLTrans::getString(event_string); +	args["RECIPIENT"] = floater->getTitle(); + +	LLNotifications::instance().add( +		"ChatterBoxSessionEventError", +		args); +} + +void +LLIMMgr::showSessionForceClose( +	const std::string& reason_string, +	const LLUUID session_id) +{ +	const LLFloater* floater = getFloaterBySessionID (session_id); +	if (!floater) return; + +	LLSD args; + +	args["NAME"] = floater->getTitle(); +	args["REASON"] = LLTrans::getString(reason_string); + +	LLSD payload; +	payload["session_id"] = session_id; + +	LLNotifications::instance().add( +		"ForceCloseChatterBoxSession", +		args, +		payload, +		LLIMMgr::onConfirmForceCloseError); +} + +//static +bool +LLIMMgr::onConfirmForceCloseError( +	const LLSD& notification, +	const LLSD& response) +{ +	//only 1 option really +	LLUUID session_id = notification["payload"]["session_id"]; + +	LLFloater* floater = getFloaterBySessionID (session_id); +	if ( floater ) +	{ +		floater->closeFloater(FALSE); +	} +	return false; +} + +  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // Class LLIncomingCallDialog  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1114,29 +1209,6 @@ void LLIncomingCallDialog::processCallResponse(S32 response)  	}  } -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLIMViewFriendObserver -// -// Bridge to suport knowing when the inventory has changed. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLIMViewFriendObserver : public LLFriendObserver -{ -public: -	LLIMViewFriendObserver(LLIMMgr* tv) : mTV(tv) {} -	virtual ~LLIMViewFriendObserver() {} -	virtual void changed(U32 mask) -	{ -		if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) -		{ -			mTV->refresh(); -		} -	} -protected: -	LLIMMgr* mTV; -}; - -  bool inviteUserResponse(const LLSD& notification, const LLSD& response)  {  	const LLSD& payload = notification["payload"]; @@ -1237,7 +1309,6 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)  //  LLIMMgr::LLIMMgr() : -	mFriendObserver(NULL),  	mIMReceived(FALSE)  {  	static bool registered_dialog = false; @@ -1246,21 +1317,11 @@ LLIMMgr::LLIMMgr() :  		LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>);  		registered_dialog = true;  	} -		 -	mFriendObserver = new LLIMViewFriendObserver(this); -	LLAvatarTracker::instance().addObserver(mFriendObserver);  	mPendingInvitations = LLSD::emptyMap();  	mPendingAgentListUpdates = LLSD::emptyMap();  } -LLIMMgr::~LLIMMgr() -{ -	LLAvatarTracker::instance().removeObserver(mFriendObserver); -	delete mFriendObserver; -	// Children all cleaned up by default view destructor. -} -  // Add a message to a session.   void LLIMMgr::addMessage(  	const LLUUID& session_id, @@ -1299,9 +1360,15 @@ void LLIMMgr::addMessage(  		fixed_session_name = session_name;  	} -	if (!LLIMModel::getInstance()->findIMSession(new_session_id)) +	bool new_session = !hasSession(session_id); +	if (new_session)  	{ -		LLIMModel::getInstance()->newSession(session_id, fixed_session_name, dialog, other_participant_id); +		// *NOTE dzaporozhan +		// Workaround for critical bug EXT-1918 + +		// *TODO  +		// Investigate cases when session_id == NULL and find solution to handle those cases +		LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id);  	}  	floater = findFloaterBySession(new_session_id); @@ -1318,15 +1385,16 @@ void LLIMMgr::addMessage(  	// create IM window as necessary  	if(!floater)  	{ - -		  		floater = createFloater(  			new_session_id,  			other_participant_id,  			fixed_session_name,  			dialog,  			FALSE); +	} +	if (new_session) +	{  		// When we get a new IM, and if you are a god, display a bit  		// of information about the source. This is to help liaisons  		// when answering questions. @@ -1336,7 +1404,7 @@ void LLIMMgr::addMessage(  			std::ostringstream bonus_info;  			bonus_info << LLTrans::getString("***")+ " "+ LLTrans::getString("IMParentEstate") + ":" + " "  				<< parent_estate_id -			<< ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "") +				<< ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "")  				<< ((parent_estate_id == 5) ? "," + LLTrans::getString ("IMTeen") : "");  			// once we have web-services (or something) which returns @@ -1439,10 +1507,7 @@ S32 LLIMMgr::getNumberOfUnreadIM()  	S32 num = 0;  	for(it = LLIMModel::sSessionsMap.begin(); it != LLIMModel::sSessionsMap.end(); ++it)  	{ -		if((*it).first != mBeingRemovedSessionID) -		{ -			num += (*it).second->mNumUnread; -		} +		num += (*it).second->mNumUnread;  	}  	return num; @@ -1458,15 +1523,6 @@ BOOL LLIMMgr::getIMReceived() const  	return mIMReceived;  } -// This method returns TRUE if the local viewer has a session -// currently open keyed to the uuid.  -BOOL LLIMMgr::isIMSessionOpen(const LLUUID& uuid) -{ -	LLFloaterIMPanel* floater = findFloaterBySession(uuid); -	if(floater) return TRUE; -	return FALSE; -} -  LLUUID LLIMMgr::addP2PSession(const std::string& name,  							const LLUUID& other_participant_id,  							const std::string& voice_session_handle, @@ -1560,41 +1616,25 @@ bool LLIMMgr::leaveSession(const LLUUID& session_id)  	return true;  } -// This removes the panel referenced by the uuid, and then restores -// internal consistency. The internal pointer is not deleted? Did you mean -// a pointer to the corresponding LLIMSession? Session data is cleared now. -// Put a copy of UUID to avoid problem when passed reference becames invalid -// if it has been come from the object removed in observer. -void LLIMMgr::removeSession(LLUUID session_id) +// Removes data associated with a particular session specified by session_id +void LLIMMgr::removeSession(const LLUUID& session_id)  { -	if (mBeingRemovedSessionID == session_id) -	{ -		return; -	} +	llassert_always(hasSession(session_id)); +	//*TODO remove this floater thing when Communicate Floater is being deleted (IB)  	LLFloaterIMPanel* floater = findFloaterBySession(session_id);  	if(floater)  	{  		mFloaters.erase(floater->getHandle());  		LLFloaterChatterBox::getInstance()->removeFloater(floater); -		//mTabContainer->removeTabPanel(floater); - -		clearPendingInvitation(session_id); -		clearPendingAgentListUpdates(session_id);  	} -	// for some purposes storing ID of a sessios that is being removed -	mBeingRemovedSessionID = session_id; -	notifyObserverSessionRemoved(session_id); +	clearPendingInvitation(session_id); +	clearPendingAgentListUpdates(session_id); -	//if we don't clear session data on removing the session -	//we can't use LLBottomTray as observer of session creation/delettion and  -	//creating chiclets only on session created even, we need to handle chiclets creation -	//the same way as LLFloaterIMPanels were managed.  	LLIMModel::getInstance()->clearSession(session_id); -	// now this session is completely removed -	mBeingRemovedSessionID.setNull(); +	notifyObserverSessionRemoved(session_id);  }  void LLIMMgr::inviteToSession( @@ -1723,10 +1763,6 @@ void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const std::stri  	}  } -void LLIMMgr::refresh() -{ -} -  void LLIMMgr::disconnectAllSessions()  {  	LLFloaterIMPanel* floater = NULL; @@ -2038,6 +2074,12 @@ void LLIMMgr::processIMTypingCore(const LLIMInfo* im_info, BOOL typing)  	{  		floater->processIMTyping(im_info, typing);  	} + +	LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); +	if ( im_floater ) +	{ +		im_floater->processIMTyping(im_info, typing); +	}  }  class LLViewerChatterBoxSessionStartReply : public LLHTTPNode @@ -2087,19 +2129,21 @@ public:  				}  			} +			LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); +			if ( im_floater ) +			{ +				if ( body.has("session_info") ) +				{ +					im_floater->processSessionUpdate(body["session_info"]); +				} +			} +  			gIMMgr->clearPendingAgentListUpdates(session_id);  		}  		else  		{ -			//throw an error dialog and close the temp session's -			//floater -			LLFloaterIMPanel* floater =  -				gIMMgr->findFloaterBySession(temp_session_id); - -			if ( floater ) -			{ -				floater->showSessionStartError(body["error"].asString()); -			} +			//throw an error dialog and close the temp session's floater +			gIMMgr->showSessionStartError(body["error"].asString(), temp_session_id);  		}  		gIMMgr->clearPendingAgentListUpdates(session_id); @@ -2132,15 +2176,10 @@ public:  		if ( !success )  		{  			//throw an error dialog -			LLFloaterIMPanel* floater =  -				gIMMgr->findFloaterBySession(session_id); - -			if (floater) -			{ -				floater->showSessionEventError( -					body["event"].asString(), -					body["error"].asString()); -			} +			gIMMgr->showSessionEventError( +				body["event"].asString(), +				body["error"].asString(), +				session_id);  		}  	}  }; @@ -2158,13 +2197,7 @@ public:  		session_id = input["body"]["session_id"].asUUID();  		reason = input["body"]["reason"].asString(); -		LLFloaterIMPanel* floater = -			gIMMgr ->findFloaterBySession(session_id); - -		if ( floater ) -		{ -			floater->showSessionForceClose(reason); -		} +		gIMMgr->showSessionForceClose(reason, session_id);  	}  }; @@ -2202,11 +2235,17 @@ public:  		const LLSD& context,  		const LLSD& input) const  	{ -		LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(input["body"]["session_id"].asUUID()); +		LLUUID session_id = input["body"]["session_id"].asUUID(); +		LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id);  		if (floaterp)  		{  			floaterp->processSessionUpdate(input["body"]["info"]);  		} +		LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); +		if ( im_floater ) +		{ +			im_floater->processSessionUpdate(input["body"]["info"]); +		}  	}  }; diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 68beb29034..ae8fd355ea 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -34,7 +34,7 @@  #define LL_LLIMVIEW_H  #include "lldarray.h" -#include "llfloateractivespeakers.h" //for LLIMSpeakerMgr +#include "llspeakers.h" //for LLIMSpeakerMgr  #include "llimpanel.h" //for voice channels  #include "llmodaldialog.h"  #include "llinstantmessage.h" @@ -70,6 +70,13 @@ public:  		LLIMSpeakerMgr* mSpeakers;  		bool mSessionInitialized; + +		//true if calling back the session URI after the session has closed is possible. +		//Currently this will be false only for PSTN P2P calls. +		bool mCallBackEnabled; + +		bool mTextIMPossible; +		bool mOtherParticipantIsAvatar;  	}; @@ -104,18 +111,35 @@ public:  	boost::signals2::connection addNewMsgCallback( session_callback_t cb ) { return mNewMsgSignal.connect(cb); }  	boost::signals2::connection addNoUnreadMsgsCallback( session_callback_t cb ) { return mNoUnreadMsgsSignal.connect(cb); } -	bool newSession(LLUUID session_id, std::string name, EInstantMessage type, LLUUID other_participant_id,  +	/** +	 * Create new session object in a model +	 */ +	bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id,   		const std::vector<LLUUID>& ids = std::vector<LLUUID>()); -	bool clearSession(LLUUID session_id); -	std::list<LLSD> getMessages(LLUUID session_id, int start_index = 0); -	bool addMessage(LLUUID session_id, std::string from, LLUUID other_participant_id, std::string utf8_text, bool log2file = true); -	bool addToHistory(LLUUID session_id, std::string from, LLUUID from_id, std::string utf8_text);  +	/** +	 * Remove all session data associated with a session specified by session_id +	 */ +	bool clearSession(const LLUUID& session_id); -	bool logToFile(const LLUUID& session_id, const std::string& from, const std::string& utf8_text); +	/** +	 * Populate supplied std::list with messages starting from index specified by start_index +	 */ +	void getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index = 0); -	//used to get the name of the session, for use as the title -	//currently just the other avatar name +	/** +	 * Add a message to an IM Model - the message is saved in a message store associated with a session specified by session_id +	 * and also saved into a file if log2file is specified. +	 * It sends new message signal for each added message. +	 */ +	bool addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& other_participant_id, const std::string& utf8_text, bool log2file = true); +	 +	/** +	 * Get a session's name.  +	 * For a P2P chat - it's an avatar's name,  +	 * For a group chat - it's a group's name +	 * For an ad-hoc chat - is received from the server and is in a from of "<Avatar's name> conference" +	 */  	const std::string& getName(const LLUUID& session_id) const;  	/**  @@ -150,7 +174,7 @@ public:  	*/  	LLIMSpeakerMgr* getSpeakerManager(const LLUUID& session_id) const; -	static void sendLeaveSession(LLUUID session_id, LLUUID other_participant_id); +	static void sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id);  	static bool sendStartSession(const LLUUID& temp_session_id, const LLUUID& other_participant_id,  						  const std::vector<LLUUID>& ids, EInstantMessage dialog);  	static void sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing); @@ -158,6 +182,19 @@ public:  								const LLUUID& other_participant_id, EInstantMessage dialog);  	void testMessages(); + +private: +	 +	/** +	 * Add message to a list of message associated with session specified by session_id +	 */ +	bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text);  + +	/** +	 * Save an IM message into a file +	 */ +	//*TODO should also save uuid of a sender +	bool logToFile(const LLUUID& session_id, const std::string& from, const std::string& utf8_text);  };  class LLIMSessionObserver @@ -183,7 +220,7 @@ public:  	};  	LLIMMgr(); -	virtual ~LLIMMgr(); +	virtual ~LLIMMgr() {};  	// Add a message to a session. The session can keyed to sesion id  	// or agent id. @@ -200,11 +237,6 @@ public:  	void addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args); -	// This method returns TRUE if the local viewer has a session -	// currently open keyed to the uuid. The uuid can be keyed by -	// either session id or agent id. -	BOOL isIMSessionOpen(const LLUUID& uuid); -  	// This adds a session to the talk view. The name is the local  	// name of the session, dialog specifies the type of  	// session. Since sessions can be keyed off of first recipient or @@ -250,9 +282,6 @@ public:  	void processIMTypingStart(const LLIMInfo* im_info);  	void processIMTypingStop(const LLIMInfo* im_info); -	// Rebuild stuff -	void refresh(); -  	void notifyNewIM();  	void clearNewIMNotification(); @@ -268,10 +297,6 @@ public:  	// good connection.  	void disconnectAllSessions(); -	// This is a helper function to determine what kind of im session -	// should be used for the given agent. -	static EInstantMessage defaultIMTypeForAgent(const LLUUID& agent_id); -  	BOOL hasSession(const LLUUID& session_id);  	// This method returns the im panel corresponding to the uuid @@ -290,11 +315,18 @@ public:  	void clearPendingAgentListUpdates(const LLUUID& session_id);  	//HACK: need a better way of enumerating existing session, or listening to session create/destroy events +	//@deprecated, is used only by LLToolBox, which is not used anywhere, right? (IB)  	const std::set<LLHandle<LLFloater> >& getIMFloaterHandles() { return mFloaters; }  	void addSessionObserver(LLIMSessionObserver *);  	void removeSessionObserver(LLIMSessionObserver *); +	//show error statuses to the user +	void showSessionStartError(const std::string& error_string, const LLUUID session_id); +	void showSessionEventError(const std::string& event_string, const std::string& error_string, const LLUUID session_id); +	void showSessionForceClose(const std::string& reason, const LLUUID session_id); +	static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response); +  	/**  	 * Start call in a session  	 * @return false if voice channel doesn't exist @@ -308,10 +340,11 @@ public:  	bool endCall(const LLUUID& session_id);  private: -	// This removes the panel referenced by the uuid, and then -	// restores internal consistency. The internal pointer is not -	// deleted. -	void removeSession(LLUUID session_id); + +	/** +	 * Remove data associated with a particular session specified by session_id +	 */ +	void removeSession(const LLUUID& session_id);  	// create a panel and update internal representation for  	// consistency. Returns the pointer, caller (the class instance @@ -340,8 +373,9 @@ private:  	void notifyObserverSessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);  private: +	 +	//*TODO should be deleted when Communicate Floater is being deleted  	std::set<LLHandle<LLFloater> > mFloaters; -	LLFriendObserver* mFriendObserver;  	typedef std::list <LLIMSessionObserver *> session_observers_list_t;  	session_observers_list_t mSessionObservers; @@ -351,9 +385,6 @@ private:  	LLSD mPendingInvitations;  	LLSD mPendingAgentListUpdates; -	// ID of a session that is being removed: observers are already told -	// that this session is being removed, but it is still present in the sessions' map -	LLUUID	mBeingRemovedSessionID;  };  class LLIncomingCallDialog : public LLModalDialog diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp index b36b7cf50e..091346d3b4 100644 --- a/indra/newview/lllandmarkactions.cpp +++ b/indra/newview/lllandmarkactions.cpp @@ -348,7 +348,7 @@ LLLandmark* LLLandmarkActions::getLandmark(const LLUUID& landmarkInventoryItemID  {  	LLViewerInventoryItem* item = gInventory.getItem(landmarkInventoryItemID);  	if (NULL == item) -		return false; +		return NULL;  	const LLUUID& asset_id = item->getAssetUUID();  	return gLandmarkList.getAsset(asset_id, NULL); diff --git a/indra/newview/lllandmarkactions.h b/indra/newview/lllandmarkactions.h index d651259790..32f05e702b 100644 --- a/indra/newview/lllandmarkactions.h +++ b/indra/newview/lllandmarkactions.h @@ -108,7 +108,7 @@ public:      /**       * @brief Retrieve a landmark from gLandmarkList by inventory item's id       *  -     * @return pointer to loaded landmark from gLandmarkList or NULL if landmark does not exist. +     * @return pointer to loaded landmark from gLandmarkList or NULL if landmark does not exist or wasn't loaded.       */      static LLLandmark* getLandmark(const LLUUID& landmarkInventoryItemID); diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index 3802d13f8b..c32ef2f22b 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -261,6 +261,15 @@ void LLNavigationBar::draw()  		onTeleportHistoryChanged();  		mPurgeTPHistoryItems = false;  	} + +	if (isBackgroundVisible()) +	{ +		static LLUICachedControl<S32> drop_shadow_floater ("DropShadowFloater", 0); +		static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow"); +		gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, +                           color_drop_shadow, drop_shadow_floater ); +	} +  	LLPanel::draw();  } diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index 148f72703c..12638ab855 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -170,22 +170,6 @@ LLColor4 nearbychat_get_text_color(const LLChat& chat)  	return text_color;  } -std::string formatCurrentTime() -{ -	time_t utc_time; -	utc_time = time_corrected(); -	std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:[" -		+LLTrans::getString("TimeMin")+"] "; - -	LLSD substitution; - -	substitution["datetime"] = (S32) utc_time; -	LLStringUtil::format (timeStr, substitution); - -	return timeStr; -} - -  void LLNearbyChat::add_timestamped_line(const LLChat& chat, const LLColor4& color)  {  	S32 font_size = gSavedSettings.getS32("ChatFontSize"); @@ -210,16 +194,14 @@ void LLNearbyChat::add_timestamped_line(const LLChat& chat, const LLColor4& colo  	style_params.font(fontp);  	LLUUID uuid = chat.mFromID;  	std::string from = chat.mFromName; -	std::string time = formatCurrentTime();  	std::string message = chat.mText; -	mChatHistory->appendWidgetMessage(uuid, from, time, message, style_params); +	mChatHistory->appendWidgetMessage(chat, style_params);  }  void	LLNearbyChat::addMessage(const LLChat& chat)  {  	LLColor4 color = nearbychat_get_text_color(chat); -  	if (chat.mChatType == CHAT_TYPE_DEBUG_MSG)  	{  		if(gSavedSettings.getBOOL("ShowScriptErrors") == FALSE) diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp index 5fa97926a5..217007fb15 100644 --- a/indra/newview/llnearbychatbar.cpp +++ b/indra/newview/llnearbychatbar.cpp @@ -45,6 +45,7 @@  #include "llviewerstats.h"  #include "llcommandhandler.h"  #include "llviewercontrol.h" +#include "llnavigationbar.h"  S32 LLNearbyChatBar::sLastSpecialChatChannel = 0; @@ -177,6 +178,31 @@ void LLGestureComboBox::draw()  	LLComboBox::draw();  } +//virtual +void LLGestureComboBox::showList() +{ +	LLComboBox::showList(); + +	// Calculating amount of space between the navigation bar and gestures combo +	LLNavigationBar* nb = LLNavigationBar::getInstance(); +	S32 x, nb_bottom; +	nb->localPointToScreen(0, 0, &x, &nb_bottom); +	 +	S32 list_bottom; +	mList->localPointToScreen(0, 0, &x, &list_bottom); + +	S32 max_height = nb_bottom - list_bottom; + +	LLRect rect = mList->getRect(); +	// List overlapped navigation bar, downsize it +	if (rect.getHeight() > max_height)  +	{ +		rect.setOriginAndSize(rect.mLeft, rect.mBottom, rect.getWidth(), max_height); +		mList->setRect(rect); +		mList->reshape(rect.getWidth(), rect.getHeight()); +	} +} +  LLNearbyChatBar::LLNearbyChatBar()   	: LLPanel()  	, mChatBox(NULL) diff --git a/indra/newview/llnearbychatbar.h b/indra/newview/llnearbychatbar.h index b902ff86cc..06204e6367 100644 --- a/indra/newview/llnearbychatbar.h +++ b/indra/newview/llnearbychatbar.h @@ -40,7 +40,7 @@  #include "llchiclet.h"  #include "llvoiceclient.h"  #include "lloutputmonitorctrl.h" -#include "llfloateractivespeakers.h" +#include "llspeakers.h"  class LLGestureComboBox  	: public LLComboBox @@ -62,6 +62,9 @@ public:  	virtual void changed() { refreshGestures(); }  protected: + +	virtual void showList(); +  	LLFrameTimer mGestureLabelTimer;  	std::vector<LLMultiGesture*> mGestures;  	std::string mLabel; diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp index 7239f49b7f..543198c1d2 100644 --- a/indra/newview/llnotificationtiphandler.cpp +++ b/indra/newview/llnotificationtiphandler.cpp @@ -86,6 +86,20 @@ bool LLTipHandler::processNotification(const LLSD& notify)  	if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change")  	{ +		// archive message in nearby chat +		LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); +		if(nearby_chat) +		{ +			LLChat chat_msg(notification->getMessage()); +			nearby_chat->addMessage(chat_msg); + +			// don't show toast if Nearby Chat is opened +			if (nearby_chat->getVisible()) +			{ +				return true; +			}			 +		} +  		LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(notification);  		LLToast::Params p; @@ -99,14 +113,6 @@ bool LLTipHandler::processNotification(const LLSD& notify)  		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);  		if(channel)  			channel->addToast(p); - -		// archive message in nearby chat -		LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); -		if(nearby_chat) -		{ -			LLChat chat_msg(notification->getMessage()); -			nearby_chat->addMessage(chat_msg); -		}  	}  	else if (notify["sigtype"].asString() == "delete")  	{ diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index 6eed956eb8..f9eeaf1e9e 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -34,6 +34,7 @@  #include "llpanelimcontrolpanel.h" +#include "llagent.h"  #include "llavataractions.h"  #include "llavatariconctrl.h"  #include "llbutton.h" @@ -41,6 +42,53 @@  #include "llavatarlist.h"  #include "llparticipantlist.h"  #include "llimview.h" +#include "llvoicechannel.h" + +void LLPanelChatControlPanel::onCallButtonClicked() +{ +	gIMMgr->startCall(mSessionId); +} + +void LLPanelChatControlPanel::onEndCallButtonClicked() +{ +	gIMMgr->endCall(mSessionId); +} + +BOOL LLPanelChatControlPanel::postBuild() +{ +	childSetAction("call_btn", boost::bind(&LLPanelChatControlPanel::onCallButtonClicked, this)); +	childSetAction("end_call_btn", boost::bind(&LLPanelChatControlPanel::onEndCallButtonClicked, this)); + +	return TRUE; +} + +void LLPanelChatControlPanel::draw() +{ +	// hide/show start call and end call buttons +	bool voice_enabled = LLVoiceClient::voiceEnabled(); + +	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId); +	if (!session) return; + +	LLVoiceChannel* voice_channel = session->mVoiceChannel; +	if (voice_channel && voice_enabled) +	{ +		childSetVisible("end_call_btn", voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); +		childSetVisible("call_btn", voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED); +	} + +	bool session_initialized = session->mSessionInitialized; +	bool callback_enabled = session->mCallBackEnabled; +	LLViewerRegion* region = gAgent.getRegion(); + +	BOOL enable_connect = (region && region->getCapability("ChatSessionRequest") != "") +		&& session_initialized +		&& voice_enabled +		&& callback_enabled; +	childSetEnabled("call_btn", enable_connect); + +	LLPanel::draw(); +}  LLPanelIMControlPanel::LLPanelIMControlPanel()  { @@ -54,11 +102,11 @@ BOOL LLPanelIMControlPanel::postBuild()  {  	childSetAction("view_profile_btn", boost::bind(&LLPanelIMControlPanel::onViewProfileButtonClicked, this));  	childSetAction("add_friend_btn", boost::bind(&LLPanelIMControlPanel::onAddFriendButtonClicked, this)); -	childSetAction("call_btn", boost::bind(&LLPanelIMControlPanel::onCallButtonClicked, this)); +  	childSetAction("share_btn", boost::bind(&LLPanelIMControlPanel::onShareButtonClicked, this));  	childSetEnabled("add_friend_btn", !LLAvatarActions::isFriend(getChild<LLAvatarIconCtrl>("avatar_icon")->getAvatarId())); - -	return TRUE; +	 +	return LLPanelChatControlPanel::postBuild();  }  void LLPanelIMControlPanel::onViewProfileButtonClicked() @@ -73,22 +121,29 @@ void LLPanelIMControlPanel::onAddFriendButtonClicked()  	LLAvatarActions::requestFriendshipDialog(avatar_icon->getAvatarId(), full_name);  } -void LLPanelIMControlPanel::onCallButtonClicked() -{ -	// *TODO: Implement -} -  void LLPanelIMControlPanel::onShareButtonClicked()  {  	// *TODO: Implement  } -void LLPanelIMControlPanel::setID(const LLUUID& avatar_id) +void LLPanelIMControlPanel::setSessionId(const LLUUID& session_id)  { +	LLPanelChatControlPanel::setSessionId(session_id); + +	LLIMModel& im_model = LLIMModel::instance(); + +	LLUUID avatar_id = im_model.getOtherParticipantID(session_id); +  	// Disable "Add friend" button for friends.  	childSetEnabled("add_friend_btn", !LLAvatarActions::isFriend(avatar_id));  	getChild<LLAvatarIconCtrl>("avatar_icon")->setValue(avatar_id); + +	// Disable profile button if participant is not realy SL avatar +	LLIMModel::LLIMSession* im_session = +		im_model.findIMSession(session_id); +	if( im_session && !im_session->mOtherParticipantIsAvatar ) +		childSetEnabled("view_profile_btn", FALSE);  } @@ -100,12 +155,11 @@ LLPanelGroupControlPanel::LLPanelGroupControlPanel(const LLUUID& session_id)  BOOL LLPanelGroupControlPanel::postBuild()  {  	childSetAction("group_info_btn", boost::bind(&LLPanelGroupControlPanel::onGroupInfoButtonClicked, this)); -	childSetAction("call_btn", boost::bind(&LLPanelGroupControlPanel::onCallButtonClicked, this));  	mAvatarList = getChild<LLAvatarList>("speakers_list");  	mParticipantList = new LLParticipantList(mSpeakerManager, mAvatarList); -	return TRUE; +	return LLPanelChatControlPanel::postBuild();  }  LLPanelGroupControlPanel::~LLPanelGroupControlPanel() @@ -127,13 +181,23 @@ void LLPanelGroupControlPanel::onGroupInfoButtonClicked()  } -void LLPanelGroupControlPanel::onCallButtonClicked() +void LLPanelGroupControlPanel::setSessionId(const LLUUID& session_id)  { -	// *TODO: Implement +	LLPanelChatControlPanel::setSessionId(session_id); + +	mGroupID = LLIMModel::getInstance()->getOtherParticipantID(session_id);  } -void LLPanelGroupControlPanel::setID(const LLUUID& id) +LLPanelAdHocControlPanel::LLPanelAdHocControlPanel(const LLUUID& session_id):LLPanelGroupControlPanel(session_id) +{ +} + +BOOL LLPanelAdHocControlPanel::postBuild()  { -	mGroupID = id; +	mAvatarList = getChild<LLAvatarList>("speakers_list"); +	mParticipantList = new LLParticipantList(mSpeakerManager, mAvatarList); + +	return LLPanelChatControlPanel::postBuild();  } + diff --git a/indra/newview/llpanelimcontrolpanel.h b/indra/newview/llpanelimcontrolpanel.h index 138b1630c4..220b7b14ba 100644 --- a/indra/newview/llpanelimcontrolpanel.h +++ b/indra/newview/llpanelimcontrolpanel.h @@ -45,8 +45,16 @@ public:  	LLPanelChatControlPanel() {};  	~LLPanelChatControlPanel() {}; -	// sets the group or avatar UUID -	virtual void setID(const LLUUID& avatar_id)= 0; +	virtual BOOL postBuild(); +	virtual void draw(); + +	void onCallButtonClicked(); +	void onEndCallButtonClicked(); + +	virtual void setSessionId(const LLUUID& session_id) { mSessionId = session_id; } + +private: +	LLUUID mSessionId;  }; @@ -58,13 +66,14 @@ public:  	BOOL postBuild(); -	void setID(const LLUUID& avatar_id); +	void setSessionId(const LLUUID& session_id);  private:  	void onViewProfileButtonClicked();  	void onAddFriendButtonClicked(); -	void onCallButtonClicked();  	void onShareButtonClicked(); + +	LLUUID mAvatarID;  }; @@ -76,19 +85,26 @@ public:  	BOOL postBuild(); -	void setID(const LLUUID& id); +	void setSessionId(const LLUUID& session_id);  	/*virtual*/ void draw(); -private: -	void onGroupInfoButtonClicked(); -	void onCallButtonClicked(); - +protected:  	LLUUID mGroupID;  	LLSpeakerMgr* mSpeakerManager;  	LLAvatarList* mAvatarList;  	LLParticipantList* mParticipantList; + +private: +	void onGroupInfoButtonClicked();  }; +class LLPanelAdHocControlPanel : public LLPanelGroupControlPanel +{ +public: +	LLPanelAdHocControlPanel(const LLUUID& session_id); + +	BOOL postBuild(); +};  #endif // LL_LLPANELIMCONTROLPANEL_H diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 83fb147a49..3d0db71045 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -38,10 +38,12 @@  #include "llsdutil.h"  #include "llsdutil_math.h" +#include "llaccordionctrl.h"  #include "llaccordionctrltab.h"  #include "llagent.h"  #include "llagentpicksinfo.h"  #include "llagentui.h" +#include "llcallbacklist.h"  #include "lldndbutton.h"  #include "llfloaterworldmap.h"  #include "llfolderviewitem.h" @@ -56,7 +58,7 @@  //static LLRegisterPanelClassWrapper<LLLandmarksPanel> t_landmarks("panel_landmarks");  static const std::string OPTIONS_BUTTON_NAME = "options_gear_btn"; -static const std::string ADD_LANDMARK_BUTTON_NAME = "add_landmark_btn"; +static const std::string ADD_BUTTON_NAME = "add_btn";  static const std::string ADD_FOLDER_BUTTON_NAME = "add_folder_btn";  static const std::string TRASH_BUTTON_NAME = "trash_btn"; @@ -75,6 +77,7 @@ LLLandmarksPanel::LLLandmarksPanel()  	,	mListCommands(NULL)  	,	mGearFolderMenu(NULL)  	,	mGearLandmarkMenu(NULL) +	,	mDirtyFilter(false)  {  	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_landmarks.xml");  } @@ -98,16 +101,37 @@ BOOL LLLandmarksPanel::postBuild()  	initMyInventroyPanel();  	initLibraryInventroyPanel(); +	gIdleCallbacks.addFunction(LLLandmarksPanel::doIdle, this);  	return TRUE;  }  // virtual  void LLLandmarksPanel::onSearchEdit(const std::string& string)  { +	static std::string prev_string(""); + +	if (prev_string == string) return; + +	// show all folders in Landmarks Accordion for empty filter +	mLandmarksInventoryPanel->setShowFolderState(string.empty() ? +		LLInventoryFilter::SHOW_ALL_FOLDERS : +		LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS +		); +  	filter_list(mFavoritesInventoryPanel, string);  	filter_list(mLandmarksInventoryPanel, string);  	filter_list(mMyInventoryPanel, string);  	filter_list(mLibraryInventoryPanel, string); + +	prev_string = string; +	mDirtyFilter = true; + +	// give FolderView a chance to be refreshed. So, made all accordions visible +	for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) +	{ +		LLAccordionCtrlTab* tab = *iter; +		tab->setVisible(true); +	}  }  // virtual @@ -300,6 +324,8 @@ void LLLandmarksPanel::processParcelInfo(const LLParcelData& parcel_data)  					panel_pick, panel_places,params));  			panel_pick->setSaveCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,  				panel_pick, panel_places,params)); +			panel_pick->setCancelCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this, +							panel_pick, panel_places,params));  		}  	}  } @@ -389,6 +415,7 @@ void LLLandmarksPanel::initLandmarksPanel(LLInventorySubTreePanel* inventory_lis  void LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLInventorySubTreePanel* inventory_list)  {  	LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>(accordion_tab_name); +	mAccordionTabs.push_back(accordion_tab);  	accordion_tab->setDropDownStateChangedCallback(  		boost::bind(&LLLandmarksPanel::onAccordionExpandedCollapsed, this, _2, inventory_list));  } @@ -433,11 +460,11 @@ void LLLandmarksPanel::initListCommandsHandlers()  	mListCommands = getChild<LLPanel>("bottom_panel");  	mListCommands->childSetAction(OPTIONS_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onActionsButtonClick, this)); -	mListCommands->childSetAction(ADD_LANDMARK_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddLandmarkButtonClick, this)); -	mListCommands->childSetAction(ADD_FOLDER_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddFolderButtonClick, this));  	mListCommands->childSetAction(TRASH_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onTrashButtonClick, this)); +	mListCommands->getChild<LLButton>(ADD_BUTTON_NAME)->setHeldDownCallback(boost::bind(&LLLandmarksPanel::onAddButtonHeldDown, this)); +	static const LLSD add_landmark_command("add_landmark"); +	mListCommands->childSetAction(ADD_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddAction, this, add_landmark_command)); -	  	LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>(TRASH_BUTTON_NAME);  	trash_btn->setDragAndDropHandler(boost::bind(&LLLandmarksPanel::handleDragAndDropToTrash, this  			,	_4 // BOOL drop @@ -453,6 +480,7 @@ void LLLandmarksPanel::initListCommandsHandlers()  	mEnableCallbackRegistrar.add("Places.LandmarksGear.Enable", boost::bind(&LLLandmarksPanel::isActionEnabled, this, _2));  	mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());  	mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +	mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());  } @@ -488,52 +516,26 @@ void LLLandmarksPanel::onActionsButtonClick()  		mGearFolderMenu->getChild<LLMenuItemCallGL>("collapse")->setVisible(cur_item->isOpen());  		menu = mGearFolderMenu;  	} -	if(menu) -	{ -		menu->buildDrawLabels(); -		menu->updateParent(LLMenuGL::sMenuContainer); -		LLView* actions_btn  = getChild<LLView>(OPTIONS_BUTTON_NAME); -		S32 menu_x, menu_y; -		actions_btn->localPointToOtherView(0,actions_btn->getRect().getHeight(),&menu_x,&menu_y, this); -		menu_y += menu->getRect().getHeight(); -		LLMenuGL::showPopup(this, menu, menu_x,menu_y); -	} +	showActionMenu(menu,OPTIONS_BUTTON_NAME);  } -void LLLandmarksPanel::onAddLandmarkButtonClick() const +void LLLandmarksPanel::onAddButtonHeldDown()  { -	if(LLLandmarkActions::landmarkAlreadyExists()) -	{ -		std::string location; -		LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_FULL); -		llwarns<<" Landmark already exists at location:  "<< location<<llendl; -		return; -	} -	LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "create_landmark")); +	showActionMenu(mMenuAdd,ADD_BUTTON_NAME);  } -void LLLandmarksPanel::onAddFolderButtonClick() const +void LLLandmarksPanel::showActionMenu(LLMenuGL* menu, std::string spawning_view_name)  { -	LLFolderViewItem*  item = getCurSelectedItem(); -	if(item &&  mCurrentSelectedList == mLandmarksInventoryPanel) +	if (menu)  	{ -		LLFolderViewEventListener* folder_bridge = NULL; -		if(item-> getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK) -		{ -			// for a landmark get parent folder bridge -			folder_bridge = item->getParentFolder()->getListener(); -		} -		else if (item-> getListener()->getInventoryType() == LLInventoryType::IT_CATEGORY)  -		{ -			// for a folder get its own bridge -			folder_bridge = item->getListener(); -		} - -		menu_create_inventory_item(mCurrentSelectedList->getRootFolder() -			, dynamic_cast<LLFolderBridge*>(folder_bridge) -			, LLSD("category") -			, gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK) -			); +		menu->buildDrawLabels(); +		menu->updateParent(LLMenuGL::sMenuContainer); +		LLView* spawning_view = getChild<LLView> (spawning_view_name); +		S32 menu_x, menu_y; +		//show menu in co-ordinates of panel +		spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this); +		menu_y += menu->getRect().getHeight(); +		LLMenuGL::showPopup(this, menu, menu_x, menu_y);  	}  } @@ -547,11 +549,39 @@ void LLLandmarksPanel::onAddAction(const LLSD& userdata) const  	std::string command_name = userdata.asString();  	if("add_landmark" == command_name)  	{ -		onAddLandmarkButtonClick(); +		if(LLLandmarkActions::landmarkAlreadyExists()) +		{ +			std::string location; +			LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_FULL); +			llwarns<<" Landmark already exists at location:  "<< location<<llendl; +			return; +		} +		LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "create_landmark"));  	}   	else if ("category" == command_name)  	{ -		onAddFolderButtonClick(); +		LLFolderViewItem* item = getCurSelectedItem(); +		if (item && mCurrentSelectedList == mLandmarksInventoryPanel) +		{ +			LLFolderViewEventListener* folder_bridge = NULL; +			if (item-> getListener()->getInventoryType() +					== LLInventoryType::IT_LANDMARK) +			{ +				// for a landmark get parent folder bridge +				folder_bridge = item->getParentFolder()->getListener(); +			} +			else if (item-> getListener()->getInventoryType() +					== LLInventoryType::IT_CATEGORY) +			{ +				// for a folder get its own bridge +				folder_bridge = item->getListener(); +			} + +			menu_create_inventory_item(mCurrentSelectedList->getRootFolder(), +					dynamic_cast<LLFolderBridge*> (folder_bridge), LLSD( +							"category"), gInventory.findCategoryUUIDForType( +							LLAssetType::AT_LANDMARK)); +		}  	}  } @@ -854,6 +884,43 @@ bool LLLandmarksPanel::handleDragAndDropToTrash(BOOL drop, EDragAndDropType carg  } +void LLLandmarksPanel::doIdle(void* landmarks_panel) +{ +	LLLandmarksPanel* panel = (LLLandmarksPanel* ) landmarks_panel; + +	if (panel->mDirtyFilter) +	{ +		panel->updateFilteredAccordions(); +	} + +} + +void LLLandmarksPanel::updateFilteredAccordions() +{ +	LLInventoryPanel* inventory_list = NULL; +	LLAccordionCtrlTab* accordion_tab = NULL; +	for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) +	{ +		accordion_tab = *iter; +		inventory_list = dynamic_cast<LLInventorySubTreePanel*> (accordion_tab->getAccordionView()); +		if (NULL == inventory_list) continue; +		LLFolderView* fv = inventory_list->getRootFolder(); + +		bool has_visible_children = fv->hasVisibleChildren(); + +		accordion_tab->setVisible(has_visible_children); +	} + +	// we have to arrange accordion tabs for cases when filter string is less restrictive but  +	// all items are still filtered. +	static LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("landmarks_accordion"); +	accordion->arrange(); + +	// now filter state is applied to accordion tabs +	mDirtyFilter = false; +} + +  //////////////////////////////////////////////////////////////////////////  // HELPER FUNCTIONS  ////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 47c9f7647c..0e7abb4865 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -41,6 +41,7 @@  #include "llpanelpick.h"  #include "llremoteparcelrequest.h" +class LLAccordionCtrlTab;  class LLFolderViewItem;  class LLMenuGL;  class LLInventoryPanel; @@ -90,8 +91,8 @@ private:  	void initListCommandsHandlers();  	void updateListCommands();  	void onActionsButtonClick(); -	void onAddLandmarkButtonClick() const; -	void onAddFolderButtonClick() const; +	void showActionMenu(LLMenuGL* menu, std::string spawning_view_name); +	void onAddButtonHeldDown();  	void onTrashButtonClick() const;  	void onAddAction(const LLSD& command_name) const;  	void onClipboardAction(const LLSD& command_name) const; @@ -114,6 +115,18 @@ private:  	 */  	bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept); +	/** +	 * Static callback for gIdleCallbacks to perform actions out of drawing +	 */ +	static void doIdle(void* landmarks_panel); + +	/** +	 * Updates accordions according to filtered items in lists. +	 * +	 * It hides accordion for empty lists +	 */ +	void updateFilteredAccordions(); +  private:  	LLInventorySubTreePanel*	mFavoritesInventoryPanel;  	LLInventorySubTreePanel*	mLandmarksInventoryPanel; @@ -121,10 +134,15 @@ private:  	LLInventorySubTreePanel*	mLibraryInventoryPanel;  	LLMenuGL*					mGearLandmarkMenu;  	LLMenuGL*					mGearFolderMenu; +	LLMenuGL*					mMenuAdd;  	LLInventorySubTreePanel*	mCurrentSelectedList;  	LLPanel*					mListCommands;  	bool 						mSortByDate; +	bool						mDirtyFilter; +	 +	typedef	std::vector<LLAccordionCtrlTab*> accordion_tabs_t; +	accordion_tabs_t			mAccordionTabs;  };  #endif //LL_LLPANELLANDMARKS_H diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 61d66873ea..4580eeb336 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -413,13 +413,17 @@ BOOL LLPanelPeople::postBuild()  	mOnlineFriendList = getChild<LLPanel>(FRIENDS_TAB_NAME)->getChild<LLAvatarList>("avatars_online");  	mAllFriendList = getChild<LLPanel>(FRIENDS_TAB_NAME)->getChild<LLAvatarList>("avatars_all");  	mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online")); +	mOnlineFriendList->setShowIcons("FriendsListShowIcons");  	mAllFriendList->setNoItemsCommentText(getString("no_friends")); +	mAllFriendList->setShowIcons("FriendsListShowIcons");  	mNearbyList = getChild<LLPanel>(NEARBY_TAB_NAME)->getChild<LLAvatarList>("avatar_list");  	mNearbyList->setNoItemsCommentText(getString("no_one_near")); +	mNearbyList->setShowIcons("NearbyListShowIcons");  	mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list");  	mRecentList->setNoItemsCommentText(getString("no_people")); +	mRecentList->setShowIcons("RecentListShowIcons");  	mGroupList = getChild<LLGroupList>("group_list");  	mGroupList->setNoItemsCommentText(getString("no_groups")); @@ -611,6 +615,10 @@ void LLPanelPeople::updateButtons()  	bool recent_tab_active	= (cur_tab == RECENT_TAB_NAME);  	LLUUID selected_id; +	std::vector<LLUUID> selected_uuids; +	getCurrentItemIDs(selected_uuids); +	bool item_selected = (selected_uuids.size() == 1); +  	buttonSetVisible("group_info_btn",		group_tab_active);  	buttonSetVisible("chat_btn",			group_tab_active);  	buttonSetVisible("add_friend_btn",		nearby_tab_active || recent_tab_active); @@ -621,7 +629,6 @@ void LLPanelPeople::updateButtons()  	if (group_tab_active)  	{ -		bool item_selected = mGroupList->getSelectedItem() != NULL;  		bool cur_group_active = true;  		if (item_selected) @@ -629,7 +636,7 @@ void LLPanelPeople::updateButtons()  			selected_id = mGroupList->getSelectedUUID();  			cur_group_active = (gAgent.getGroupID() == selected_id);  		} -	 +  		LLPanel* groups_panel = mTabContainer->getCurrentPanel();  		groups_panel->childSetEnabled("activate_btn",	item_selected && !cur_group_active); // "none" or a non-active group selected  		groups_panel->childSetEnabled("plus_btn",		item_selected); @@ -640,18 +647,18 @@ void LLPanelPeople::updateButtons()  		bool is_friend = true;  		// Check whether selected avatar is our friend. -		if ((selected_id = getCurrentItemID()).notNull()) +		if (item_selected)  		{ +			selected_id = selected_uuids.front();  			is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL;  		}  		childSetEnabled("add_friend_btn",	!is_friend);  	} -	bool item_selected = selected_id.notNull();  	buttonSetEnabled("teleport_btn",		friends_tab_active && item_selected);  	buttonSetEnabled("view_profile_btn",	item_selected); -	buttonSetEnabled("im_btn",				item_selected); +	buttonSetEnabled("im_btn",				(selected_uuids.size() >= 1)); // allow starting the friends conference for multiple selection  	buttonSetEnabled("call_btn",			item_selected && false); // not implemented yet  	buttonSetEnabled("share_btn",			item_selected && false); // not implemented yet  	buttonSetEnabled("group_info_btn",		item_selected); @@ -877,7 +884,17 @@ void LLPanelPeople::onAddFriendWizButtonClicked()  void LLPanelPeople::onDeleteFriendButtonClicked()  { -	LLAvatarActions::removeFriendDialog(getCurrentItemID()); +	std::vector<LLUUID> selected_uuids; +	getCurrentItemIDs(selected_uuids); + +	if (selected_uuids.size() == 1) +	{ +		LLAvatarActions::removeFriendDialog( selected_uuids.front() ); +	} +	else if (selected_uuids.size() > 1) +	{ +		LLAvatarActions::removeFriendsDialog( selected_uuids ); +	}  }  void LLPanelPeople::onGroupInfoButtonClicked() @@ -963,6 +980,8 @@ void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata)  	}  	else if (chosen_item == "view_icons")  	{ +		mAllFriendList->toggleIcons(); +		mOnlineFriendList->toggleIcons();  	}  	else if (chosen_item == "organize_offline")  	{ @@ -992,6 +1011,7 @@ void LLPanelPeople::onNearbyViewSortMenuItemClicked(const LLSD& userdata)  	}  	else if (chosen_item == "view_icons")  	{ +		mNearbyList->toggleIcons();  	}  	else if (chosen_item == "sort_distance")  	{ @@ -1011,7 +1031,7 @@ void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata)  	}  	else if (chosen_item == "view_icons")  	{ -		// *TODO: implement showing/hiding icons +		mRecentList->toggleIcons();  	}  } diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index cb9f7184f0..5af27a5ec1 100644 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -55,6 +55,8 @@  #include "llagent.h"  #include "llagentui.h"  #include "llavatarpropertiesprocessor.h" +#include "llcallbacklist.h" +#include "llexpandabletextbox.h"  #include "llfloaterworldmap.h"  #include "llfloaterbuycurrency.h"  #include "llinventorymodel.h" @@ -65,6 +67,7 @@  #include "llviewerinventory.h"  #include "llviewerparcelmgr.h"  #include "llviewerregion.h" +#include "llviewercontrol.h"   #include "llviewertexteditor.h"  #include "llworldmap.h"  #include "llsdutil_math.h" @@ -76,7 +79,6 @@  typedef std::pair<LLUUID, std::string> folder_pair_t;  static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right); -static std::string getFullFolderName(const LLViewerInventoryCategory* cat);  static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats);  static LLRegisterPanelClassWrapper<LLPanelPlaceInfo> t_place_info("panel_place_info"); @@ -111,7 +113,7 @@ BOOL LLPanelPlaceInfo::postBuild()  	mForSalePanel = getChild<LLPanel>("for_sale_panel");  	mYouAreHerePanel = getChild<LLPanel>("here_panel"); -	LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(boost::bind(&LLPanelPlaceInfo::updateYouAreHereBanner,this)); +	gIdleCallbacks.addFunction(&LLPanelPlaceInfo::updateYouAreHereBanner, this);  	//Icon value should contain sale price of last selected parcel.   	mForSalePanel->getChild<LLIconCtrl>("icon_for_sale")-> @@ -120,7 +122,7 @@ BOOL LLPanelPlaceInfo::postBuild()  	mSnapshotCtrl = getChild<LLTextureCtrl>("logo");  	mRegionName = getChild<LLTextBox>("region_title");  	mParcelName = getChild<LLTextBox>("parcel_title"); -	mDescEditor = getChild<LLTextEditor>("description"); +	mDescEditor = getChild<LLExpandableTextBox>("description");  	mMaturityRatingText = getChild<LLTextBox>("maturity_value");  	mParcelOwner = getChild<LLTextBox>("owner_value"); @@ -456,13 +458,13 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data)  		mSnapshotCtrl->setImageAssetID(parcel_data.snapshot_id);  	} -	if(!parcel_data.name.empty()) +	if(!parcel_data.sim_name.empty())  	{ -		mParcelName->setText(parcel_data.name); +		mRegionName->setText(parcel_data.sim_name);  	}  	else  	{ -		mParcelName->setText(LLStringUtil::null); +		mRegionName->setText(LLStringUtil::null);  	}  	if(!parcel_data.desc.empty()) @@ -509,19 +511,22 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data)  		region_z = llround(mPosRegion.mV[VZ]);  	} -	std::string name = getString("not_available"); -	if (!parcel_data.sim_name.empty()) +	if (!parcel_data.name.empty())  	{ -		name = llformat("%s (%d, %d, %d)", -						parcel_data.sim_name.c_str(), region_x, region_y, region_z); -		mRegionName->setText(name); +		mParcelName->setText(llformat("%s (%d, %d, %d)", +							 parcel_data.name.c_str(), region_x, region_y, region_z)); +	} +	else +	{ +		mParcelName->setText(getString("not_available"));  	}  	if (mInfoType == CREATE_LANDMARK)  	{  		if (parcel_data.name.empty())  		{ -			mTitleEditor->setText(name); +			mTitleEditor->setText(llformat("%s (%d, %d, %d)", +								  parcel_data.sim_name.c_str(), region_x, region_y, region_z));  		}  		else  		{ @@ -610,6 +615,9 @@ void LLPanelPlaceInfo::displaySelectedParcelInfo(LLParcel* parcel,  	parcel_data.name = parcel->getName();  	parcel_data.sim_name = region->getName();  	parcel_data.snapshot_id = parcel->getSnapshotID(); +	mPosRegion.setVec((F32)fmod(pos_global.mdV[VX], (F64)REGION_WIDTH_METERS), +					  (F32)fmod(pos_global.mdV[VY], (F64)REGION_WIDTH_METERS), +					  (F32)pos_global.mdV[VZ]);  	parcel_data.global_x = pos_global.mdV[VX];  	parcel_data.global_y = pos_global.mdV[VY];  	parcel_data.global_z = pos_global.mdV[VZ]; @@ -986,18 +994,22 @@ void LLPanelPlaceInfo::populateFoldersList()  		mFolderCombo->add(it->second, LLSD(it->first));  } -void LLPanelPlaceInfo::updateYouAreHereBanner() +//static +void LLPanelPlaceInfo::updateYouAreHereBanner(void* userdata)  {  	//YouAreHere Banner should be displayed only for selected places,   	// If you want to display it for landmark or teleport history item, you should check by mParcelId -	bool is_you_are_here = false; -	if (mSelectedParcelID != S32(-1) && !mLastSelectedRegionID.isNull()) -	{ -		is_you_are_here = gAgent.getRegion()->getRegionID()== mLastSelectedRegionID && -		mSelectedParcelID == LLViewerParcelMgr::getInstance()->getAgentParcel()->getLocalID(); -	} -	mYouAreHerePanel->setVisible(is_you_are_here); +	LLPanelPlaceInfo* self  = static_cast<LLPanelPlaceInfo*>(userdata); +	if(!self->getVisible()) +		return; + +	static F32 radius  = gSavedSettings.getF32("YouAreHereDistance"); + +	BOOL display_banner = self->mLastSelectedRegionID == gAgent.getRegion()->getRegionID() &&  +			LLAgentUI::checkAgentDistance(self->mPosRegion, radius); + +	self->mYouAreHerePanel->setVisible(display_banner);  }  void LLPanelPlaceInfo::onForSaleBannerClick() @@ -1028,14 +1040,9 @@ void LLPanelPlaceInfo::onForSaleBannerClick()  } -  - -static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right) -{ -	return left.second < right.second; -} -static std::string getFullFolderName(const LLViewerInventoryCategory* cat) +/*static*/ +std::string LLPanelPlaceInfo::getFullFolderName(const LLViewerInventoryCategory* cat)  {  	std::string name = cat->getName();  	LLUUID parent_id; @@ -1057,6 +1064,11 @@ static std::string getFullFolderName(const LLViewerInventoryCategory* cat)  	return name;  } +static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right) +{ +	return left.second < right.second; +} +  static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats)  {  	LLUUID landmarks_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK); diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index 7b3a8f050b..07a2434d59 100644 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -43,6 +43,7 @@  class LLButton;  class LLComboBox; +class LLExpandableTextBox;  class LLInventoryItem;  class LLLineEditor;  class LLPanelPickEdit; @@ -52,6 +53,7 @@ class LLTextBox;  class LLTextEditor;  class LLTextureCtrl;  class LLViewerRegion; +class LLViewerInventoryCategory;  class LLPanelPlaceInfo : public LLPanel, LLRemoteParcelInfoObserver  { @@ -131,11 +133,13 @@ public:  	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);  	/*virtual*/ void handleVisibilityChange (BOOL new_visibility); +	 +	 static std::string getFullFolderName(const LLViewerInventoryCategory* cat);  private:  	void populateFoldersList(); -	void updateYouAreHereBanner(); +	static void updateYouAreHereBanner(void*);// added to gIdleCallbacks  	void onForSaleBannerClick();  	/** @@ -161,7 +165,7 @@ private:  	LLTextureCtrl*		mSnapshotCtrl;  	LLTextBox*			mRegionName;  	LLTextBox*			mParcelName; -	LLTextEditor*		mDescEditor; +	LLExpandableTextBox*mDescEditor;  	LLTextBox*			mMaturityRatingText;  	LLTextBox*			mParcelOwner;  	LLTextBox*			mLastVisited; diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 5ab823b6e5..b2e9110e96 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -351,7 +351,16 @@ void LLPanelPlaces::setItem(LLInventoryItem* item)  	if (is_landmark_editable)  	{ -		mPlaceInfo->setLandmarkFolder(mItem->getParentUUID()); +		if(!mPlaceInfo->setLandmarkFolder(mItem->getParentUUID()) && !mItem->getParentUUID().isNull()) +		{ +			const LLViewerInventoryCategory* cat = gInventory.getCategory(mItem->getParentUUID()); +			if(cat) +			{ +				std::string cat_fullname = LLPanelPlaceInfo::getFullFolderName(cat); +				LLComboBox* folderList = mPlaceInfo->getChild<LLComboBox>("folder_combo"); +				folderList->add(cat_fullname, cat->getUUID(),ADD_TOP); +			} +		}  	}  	mPlaceInfo->displayItemInfo(mItem); diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp new file mode 100644 index 0000000000..ca7ebb1ad8 --- /dev/null +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -0,0 +1,1095 @@ +/**  + * @file llpanelprimmediacontrols.cpp + * @brief media controls popup panel + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + *  + * Copyright (c) 2003-2007, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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 "llviewerprecompiledheaders.h" + +//LLPanelPrimMediaControls +#include "llagent.h" +#include "llparcel.h" +#include "llpanel.h" +#include "llselectmgr.h" +#include "llmediaentry.h" +#include "llrender.h" +#include "lldrawable.h" +#include "llviewerwindow.h" +#include "lluictrlfactory.h" +#include "llbutton.h" +#include "llface.h" +#include "llcombobox.h" +#include "llslider.h" +#include "llhudview.h" +#include "lliconctrl.h" +#include "lltoolpie.h" +#include "llviewercamera.h" +#include "llviewerobjectlist.h" +#include "llpanelprimmediacontrols.h" +#include "llpluginclassmedia.h" +#include "llprogressbar.h" +#include "llviewercontrol.h" +#include "llviewerparcelmgr.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h" +#include "llvovolume.h" +#include "llweb.h" +#include "llwindow.h" + +glh::matrix4f glh_get_current_modelview(); +glh::matrix4f glh_get_current_projection(); + +const F32 ZOOM_NEAR_PADDING		= 1.0f; +const F32 ZOOM_MEDIUM_PADDING	= 1.15f; +const F32 ZOOM_FAR_PADDING		= 1.5f; + +// Warning: make sure these two match! +const LLPanelPrimMediaControls::EZoomLevel LLPanelPrimMediaControls::kZoomLevels[] = { ZOOM_NONE, ZOOM_MEDIUM }; +const int LLPanelPrimMediaControls::kNumZoomLevels = 2; + +// +// LLPanelPrimMediaControls +// + +LLPanelPrimMediaControls::LLPanelPrimMediaControls() :  +	mAlpha(1.f), +	mCurrentURL(""), +	mPreviousURL(""), +	mPauseFadeout(false), +	mUpdateSlider(true), +	mClearFaceOnFade(false), +	mCurrentRate(0.0), +	mMovieDuration(0.0), +	mUpdatePercent(0) +{ +	mCommitCallbackRegistrar.add("MediaCtrl.Close",		boost::bind(&LLPanelPrimMediaControls::onClickClose, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Back",		boost::bind(&LLPanelPrimMediaControls::onClickBack, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Forward",	boost::bind(&LLPanelPrimMediaControls::onClickForward, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Home",		boost::bind(&LLPanelPrimMediaControls::onClickHome, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Stop",		boost::bind(&LLPanelPrimMediaControls::onClickStop, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Reload",	boost::bind(&LLPanelPrimMediaControls::onClickReload, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Play",		boost::bind(&LLPanelPrimMediaControls::onClickPlay, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Pause",		boost::bind(&LLPanelPrimMediaControls::onClickPause, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Open",		boost::bind(&LLPanelPrimMediaControls::onClickOpen, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Zoom",		boost::bind(&LLPanelPrimMediaControls::onClickZoom, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.CommitURL",	boost::bind(&LLPanelPrimMediaControls::onCommitURL, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.JumpProgress",		boost::bind(&LLPanelPrimMediaControls::onCommitSlider, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeUp",	boost::bind(&LLPanelPrimMediaControls::onCommitVolumeUp, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeDown",	boost::bind(&LLPanelPrimMediaControls::onCommitVolumeDown, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.ToggleMute",		boost::bind(&LLPanelPrimMediaControls::onToggleMute, this)); +	 +	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_prim_media_controls.xml"); +	mInactivityTimer.reset(); +	mFadeTimer.stop(); +	mCurrentZoom = ZOOM_NONE; +	mScrollState = SCROLL_NONE; + +	mPanelHandle.bind(this); +} +LLPanelPrimMediaControls::~LLPanelPrimMediaControls() +{ +} + +BOOL LLPanelPrimMediaControls::postBuild() +{ +	LLButton* scroll_up_ctrl = getChild<LLButton>("scrollup"); +	scroll_up_ctrl->setClickedCallback(onScrollUp, this); +	scroll_up_ctrl->setHeldDownCallback(onScrollUpHeld, this); +	scroll_up_ctrl->setMouseUpCallback(onScrollStop, this); +	LLButton* scroll_left_ctrl = getChild<LLButton>("scrollleft"); +	scroll_left_ctrl->setClickedCallback(onScrollLeft, this); +	scroll_left_ctrl->setHeldDownCallback(onScrollLeftHeld, this); +	scroll_left_ctrl->setMouseUpCallback(onScrollStop, this); +	LLButton* scroll_right_ctrl = getChild<LLButton>("scrollright"); +	scroll_right_ctrl->setClickedCallback(onScrollRight, this); +	scroll_right_ctrl->setHeldDownCallback(onScrollLeftHeld, this); +	scroll_right_ctrl->setMouseUpCallback(onScrollStop, this); +	LLButton* scroll_down_ctrl = getChild<LLButton>("scrolldown"); +	scroll_down_ctrl->setClickedCallback(onScrollDown, this); +	scroll_down_ctrl->setHeldDownCallback(onScrollDownHeld, this); +	scroll_down_ctrl->setMouseUpCallback(onScrollStop, this); +	 +	LLUICtrl* media_address	= getChild<LLUICtrl>("media_address"); +	media_address->setFocusReceivedCallback(boost::bind(&LLPanelPrimMediaControls::onInputURL, _1, this )); +	mInactiveTimeout = gSavedSettings.getF32("MediaControlTimeout"); +	mControlFadeTime = gSavedSettings.getF32("MediaControlFadeTime"); + +	mCurrentZoom = ZOOM_NONE; +	// clicks on HUD buttons do not remove keyboard focus from media +	setIsChrome(TRUE); +	return TRUE; +} + +void LLPanelPrimMediaControls::setMediaFace(LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal) +{ +	if (media_impl.notNull() && objectp.notNull()) +	{ +		mTargetImplID = media_impl->getMediaTextureID(); +		mTargetObjectID = objectp->getID(); +		mTargetObjectFace = face; +		mTargetObjectNormal = pick_normal; +		mClearFaceOnFade = false; +	} +	else +	{ +		// This happens on a timer now. +//		mTargetImplID = LLUUID::null; +//		mTargetObjectID = LLUUID::null; +//		mTargetObjectFace = 0; +		mClearFaceOnFade = true; +	} + +	updateShape(); +} + +void LLPanelPrimMediaControls::focusOnTarget() +{ +	// Sets the media focus to the current target of the LLPanelPrimMediaControls. +	// This is how we transition from hover to focus when the user clicks on a control. +	LLViewerMediaImpl* media_impl = getTargetMediaImpl(); +	if(media_impl) +	{ +		if(!media_impl->hasFocus()) +		{	 +			// The current target doesn't have media focus -- focus on it. +			LLViewerObject* objectp = getTargetObject(); +			LLViewerMediaFocus::getInstance()->setFocusFace(objectp, mTargetObjectFace, media_impl, mTargetObjectNormal); +		} +	}	 +} + +LLViewerMediaImpl* LLPanelPrimMediaControls::getTargetMediaImpl() +{ +	return LLViewerMedia::getMediaImplFromTextureID(mTargetImplID); +} + +LLViewerObject* LLPanelPrimMediaControls::getTargetObject() +{ +	return gObjectList.findObject(mTargetObjectID); +} + +LLPluginClassMedia* LLPanelPrimMediaControls::getTargetMediaPlugin() +{ +	LLViewerMediaImpl* impl = getTargetMediaImpl(); +	if(impl && impl->hasMedia()) +	{ +		return impl->getMediaPlugin(); +	} +	 +	return NULL; +} + +void LLPanelPrimMediaControls::updateShape() +{ +	const S32 MIN_HUD_WIDTH=400; +	const S32 MIN_HUD_HEIGHT=120; + +	LLViewerMediaImpl* media_impl = getTargetMediaImpl(); +	LLViewerObject* objectp = getTargetObject(); +	 +	if(!media_impl) +	{ +		setVisible(FALSE); +		return; +	} + +	LLPluginClassMedia* media_plugin = NULL; +	if(media_impl->hasMedia()) +	{ +		media_plugin = media_impl->getMediaPlugin(); +	} +	 +	LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + +	bool can_navigate = parcel->getMediaAllowNavigate(); +	bool enabled = false; +	bool has_focus = media_impl->hasFocus(); +	setVisible(enabled); + +	if (objectp) +	{ +		bool mini_controls = false; +		LLMediaEntry *media_data = objectp->getTE(mTargetObjectFace)->getMediaData(); +		if (media_data && NULL != dynamic_cast<LLVOVolume*>(objectp)) +		{ +			// Don't show the media HUD if we do not have permissions +			enabled = dynamic_cast<LLVOVolume*>(objectp)->hasMediaPermission(media_data, LLVOVolume::MEDIA_PERM_CONTROL); +			mini_controls = (LLMediaEntry::MINI == media_data->getControls()); +		} +		 +		// +		// Set the state of the buttons +		// +		LLUICtrl* back_ctrl					= getChild<LLUICtrl>("back"); +		LLUICtrl* fwd_ctrl					= getChild<LLUICtrl>("fwd"); +		LLUICtrl* reload_ctrl				= getChild<LLUICtrl>("reload"); +		LLUICtrl* play_ctrl					= getChild<LLUICtrl>("play"); +		LLUICtrl* pause_ctrl				= getChild<LLUICtrl>("pause"); +		LLUICtrl* stop_ctrl					= getChild<LLUICtrl>("stop"); +		LLUICtrl* media_stop_ctrl			= getChild<LLUICtrl>("media_stop"); +		LLUICtrl* home_ctrl					= getChild<LLUICtrl>("home"); +		LLUICtrl* close_ctrl				= getChild<LLUICtrl>("close"); +		LLUICtrl* open_ctrl					= getChild<LLUICtrl>("new_window"); +        LLUICtrl* zoom_ctrl					= getChild<LLUICtrl>("zoom_frame"); +		LLPanel* media_loading_panel		= getChild<LLPanel>("media_progress_indicator"); +		LLUICtrl* media_address_ctrl		= getChild<LLUICtrl>("media_address"); +		LLUICtrl* media_play_slider_ctrl	= getChild<LLUICtrl>("media_play_position"); +		LLUICtrl* volume_ctrl				= getChild<LLUICtrl>("media_volume"); +		LLButton* volume_btn				= getChild<LLButton>("media_volume_button"); +		LLUICtrl* volume_up_ctrl			= getChild<LLUICtrl>("volume_up"); +		LLUICtrl* volume_down_ctrl			= getChild<LLUICtrl>("volume_down"); +		LLIconCtrl* whitelist_icon			= getChild<LLIconCtrl>("media_whitelist_flag"); +		LLIconCtrl* secure_lock_icon		= getChild<LLIconCtrl>("media_secure_lock_flag"); +		 +		LLUICtrl* media_panel_scroll		= getChild<LLUICtrl>("media_panel_scroll"); +		LLUICtrl* scroll_up_ctrl			= getChild<LLUICtrl>("scrollup"); +		LLUICtrl* scroll_left_ctrl			= getChild<LLUICtrl>("scrollleft"); +		LLUICtrl* scroll_right_ctrl			= getChild<LLUICtrl>("scrollright"); +		LLUICtrl* scroll_down_ctrl			= getChild<LLUICtrl>("scrolldown");		 +				 +		// XXX RSP: TODO: FIXME: clean this up so that it is clearer what mode we are in, +		// and that only the proper controls get made visible/enabled according to that mode.  +		back_ctrl->setVisible(has_focus); +		fwd_ctrl->setVisible(has_focus); +		reload_ctrl->setVisible(has_focus); +		stop_ctrl->setVisible(false); +		home_ctrl->setVisible(has_focus); +		close_ctrl->setVisible(has_focus); +		open_ctrl->setVisible(true); +		media_address_ctrl->setVisible(has_focus && !mini_controls); +		media_play_slider_ctrl->setVisible(has_focus && !mini_controls); +		volume_ctrl->setVisible(false); +		volume_up_ctrl->setVisible(false); +		volume_down_ctrl->setVisible(false); +		 +		whitelist_icon->setVisible(!mini_controls && (media_data)?media_data->getWhiteListEnable():false); +		// Disable zoom if HUD +		zoom_ctrl->setEnabled(!objectp->isHUDAttachment()); +		secure_lock_icon->setVisible(false); +		mCurrentURL = media_impl->getMediaURL(); +		 +		back_ctrl->setEnabled((media_impl != NULL) && media_impl->canNavigateBack() && can_navigate); +		fwd_ctrl->setEnabled((media_impl != NULL) && media_impl->canNavigateForward() && can_navigate); +		stop_ctrl->setEnabled(has_focus && can_navigate); +		home_ctrl->setEnabled(has_focus && can_navigate); +		LLPluginClassMediaOwner::EMediaStatus result = ((media_impl != NULL) && media_impl->hasMedia()) ? media_plugin->getStatus() : LLPluginClassMediaOwner::MEDIA_NONE; + +		if(media_plugin && media_plugin->pluginSupportsMediaTime()) +		{ +			reload_ctrl->setEnabled(FALSE); +			reload_ctrl->setVisible(FALSE); +			media_stop_ctrl->setVisible(has_focus); +			home_ctrl->setVisible(FALSE); +			back_ctrl->setEnabled(has_focus); +			fwd_ctrl->setEnabled(has_focus); +			media_address_ctrl->setVisible(false); +			media_address_ctrl->setEnabled(false); +			media_play_slider_ctrl->setVisible(!mini_controls); +			media_play_slider_ctrl->setEnabled(!mini_controls); +				 +			volume_ctrl->setVisible(has_focus); +			volume_up_ctrl->setVisible(has_focus); +			volume_down_ctrl->setVisible(has_focus); +			volume_ctrl->setEnabled(has_focus); + +			whitelist_icon->setVisible(false); +			secure_lock_icon->setVisible(false); +			scroll_up_ctrl->setVisible(false); +			scroll_left_ctrl->setVisible(false); +			scroll_right_ctrl->setVisible(false); +			scroll_down_ctrl->setVisible(false); +			media_panel_scroll->setVisible(false); +				 +			F32 volume = media_impl->getVolume(); +			// movie's url changed +			if(mCurrentURL!=mPreviousURL) +			{ +				mMovieDuration = media_plugin->getDuration(); +				mPreviousURL = mCurrentURL; +			} +				 +			if(mMovieDuration == 0)  +			{ +				mMovieDuration = media_plugin->getDuration(); +				media_play_slider_ctrl->setValue(0); +				media_play_slider_ctrl->setEnabled(false); +			} +			// TODO: What if it's not fully loaded +					 +			if(mUpdateSlider && mMovieDuration!= 0) +			{ +				F64 current_time =  media_plugin->getCurrentTime(); +				F32 percent = current_time / mMovieDuration; +				media_play_slider_ctrl->setValue(percent); +				media_play_slider_ctrl->setEnabled(true); +			} +				 +			// video vloume +			if(volume <= 0.0) +			{ +				volume_up_ctrl->setEnabled(TRUE); +				volume_down_ctrl->setEnabled(FALSE); +				media_impl->setVolume(0.0); +				volume_btn->setToggleState(true); +			} +			else if (volume >= 1.0) +			{ +				volume_up_ctrl->setEnabled(FALSE); +				volume_down_ctrl->setEnabled(TRUE); +				media_impl->setVolume(1.0); +				volume_btn->setToggleState(false); +			} +			else +			{ +				volume_up_ctrl->setEnabled(TRUE); +				volume_down_ctrl->setEnabled(TRUE); +			} +				 +			switch(result) +			{ +				case LLPluginClassMediaOwner::MEDIA_PLAYING: +					play_ctrl->setEnabled(FALSE); +					play_ctrl->setVisible(FALSE); +					pause_ctrl->setEnabled(TRUE); +					pause_ctrl->setVisible(has_focus); +					media_stop_ctrl->setEnabled(TRUE); +					 +					break; +				case LLPluginClassMediaOwner::MEDIA_PAUSED: +				default: +					pause_ctrl->setEnabled(FALSE); +					pause_ctrl->setVisible(FALSE); +					play_ctrl->setEnabled(TRUE); +					play_ctrl->setVisible(has_focus); +					media_stop_ctrl->setEnabled(FALSE); +					break; +			} +		} +		else   // web based +		{ +			if(media_plugin) +			{ +				mCurrentURL = media_plugin->getLocation(); +			} +			else +			{ +				mCurrentURL.clear(); +			} +				 +			play_ctrl->setVisible(FALSE); +			pause_ctrl->setVisible(FALSE); +			media_stop_ctrl->setVisible(FALSE); +			media_address_ctrl->setVisible(has_focus && !mini_controls); +			media_address_ctrl->setEnabled(has_focus && !mini_controls); +			media_play_slider_ctrl->setVisible(FALSE); +			media_play_slider_ctrl->setEnabled(FALSE); +				 +			volume_ctrl->setVisible(FALSE); +			volume_up_ctrl->setVisible(FALSE); +			volume_down_ctrl->setVisible(FALSE); +			volume_ctrl->setEnabled(FALSE); +			volume_up_ctrl->setEnabled(FALSE); +			volume_down_ctrl->setEnabled(FALSE); +				 +			scroll_up_ctrl->setVisible(has_focus); +			scroll_left_ctrl->setVisible(has_focus); +			scroll_right_ctrl->setVisible(has_focus); +			scroll_down_ctrl->setVisible(has_focus); +			media_panel_scroll->setVisible(has_focus); +			// TODO: get the secure lock bool from media plug in +			std::string prefix =  std::string("https://"); +			std::string test_prefix = mCurrentURL.substr(0, prefix.length()); +			LLStringUtil::toLower(test_prefix); +			if(test_prefix == prefix) +			{ +				secure_lock_icon->setVisible(has_focus); +			} +				 +			if(mCurrentURL!=mPreviousURL) +			{ +				setCurrentURL(); +				mPreviousURL = mCurrentURL; +			} + +			if(result == LLPluginClassMediaOwner::MEDIA_LOADING) +			{ +				reload_ctrl->setEnabled(FALSE); +				reload_ctrl->setVisible(FALSE); +				stop_ctrl->setEnabled(TRUE); +				stop_ctrl->setVisible(has_focus); +			} +			else +			{ +				reload_ctrl->setEnabled(TRUE); +				reload_ctrl->setVisible(has_focus); +				stop_ctrl->setEnabled(FALSE); +				stop_ctrl->setVisible(FALSE); +			} +		} + +		 +		if(media_plugin) +		{ +			// +			// Handle progress bar +			// +			mUpdatePercent = media_plugin->getProgressPercent(); +			if(mUpdatePercent<100.0f) +			{ +				media_loading_panel->setVisible(true); +				getChild<LLProgressBar>("media_progress_bar")->setPercent(mUpdatePercent); +				gFocusMgr.setTopCtrl(media_loading_panel); +			} +			else +			{ +				media_loading_panel->setVisible(false); +				gFocusMgr.setTopCtrl(NULL); +			} +		} + +		if(media_plugin) +		{ +			// +			// Handle Scrolling +			// +			switch (mScrollState)  +			{ +			case SCROLL_UP: +				media_plugin->scrollEvent(0, -1, MASK_NONE); +				break; +			case SCROLL_DOWN: +				media_plugin->scrollEvent(0, 1, MASK_NONE); +				break; +			case SCROLL_LEFT: +				media_impl->handleKeyHere(KEY_LEFT, MASK_NONE); +				break; +			case SCROLL_RIGHT: +				media_impl->handleKeyHere(KEY_RIGHT, MASK_NONE); +				break; +			case SCROLL_NONE: +			default: +				break; +			} +		} +		 +		setVisible(enabled); + +		// +		// Calculate position and shape of the controls +		// +		glh::matrix4f mat = glh_get_current_projection()*glh_get_current_modelview(); +		std::vector<LLVector3>::iterator vert_it; +		std::vector<LLVector3>::iterator vert_end; +		std::vector<LLVector3> vect_face; + +		LLVolume* volume = objectp->getVolume(); + +		if (volume) +		{ +			const LLVolumeFace& vf = volume->getVolumeFace(mTargetObjectFace); + +			const LLVector3* ext = vf.mExtents; + +			LLVector3 center = (ext[0]+ext[1])*0.5f; +			LLVector3 size = (ext[1]-ext[0])*0.5f; +			LLVector3 vert[] = +			{ +				center + size.scaledVec(LLVector3(1,1,1)), +				center + size.scaledVec(LLVector3(-1,1,1)), +				center + size.scaledVec(LLVector3(1,-1,1)), +				center + size.scaledVec(LLVector3(-1,-1,1)), +				center + size.scaledVec(LLVector3(1,1,-1)), +				center + size.scaledVec(LLVector3(-1,1,-1)), +				center + size.scaledVec(LLVector3(1,-1,-1)), +				center + size.scaledVec(LLVector3(-1,-1,-1)), +			}; + +			LLVOVolume* vo = (LLVOVolume*) objectp; + +			for (U32 i = 0; i < 8; i++) +			{ +				vect_face.push_back(vo->volumePositionToAgent(vert[i]));	 +			} +		} +		vert_it = vect_face.begin(); +		vert_end = vect_face.end(); + +		LLVector3 min = LLVector3(1,1,1); +		LLVector3 max = LLVector3(-1,-1,-1); +		for(; vert_it != vert_end; ++vert_it) +		{ +			// project silhouette vertices into screen space +			glh::vec3f screen_vert = glh::vec3f(vert_it->mV);  +			mat.mult_matrix_vec(screen_vert); + +			// add to screenspace bounding box +			update_min_max(min, max, LLVector3(screen_vert.v)); +		} + +        LLCoordGL screen_min; +		screen_min.mX = llround((F32)gViewerWindow->getWorldViewWidth() * (min.mV[VX] + 1.f) * 0.5f); +		screen_min.mY = llround((F32)gViewerWindow->getWorldViewHeight() * (min.mV[VY] + 1.f) * 0.5f); + +		LLCoordGL screen_max; +		screen_max.mX = llround((F32)gViewerWindow->getWorldViewWidth() * (max.mV[VX] + 1.f) * 0.5f); +		screen_max.mY = llround((F32)gViewerWindow->getWorldViewHeight() * (max.mV[VY] + 1.f) * 0.5f); + +		// grow panel so that screenspace bounding box fits inside "media_region" element of HUD +		LLRect media_controls_rect; +		getParent()->screenRectToLocal(LLRect(screen_min.mX, screen_max.mY, screen_max.mX, screen_min.mY), &media_controls_rect); +		LLView* media_region = getChild<LLView>("media_region"); +		media_controls_rect.mLeft -= media_region->getRect().mLeft; +		media_controls_rect.mBottom -= media_region->getRect().mBottom; +		media_controls_rect.mTop += getRect().getHeight() - media_region->getRect().mTop; +		media_controls_rect.mRight += getRect().getWidth() - media_region->getRect().mRight; + +		LLRect old_hud_rect = media_controls_rect; +		// keep all parts of HUD on-screen +		media_controls_rect.intersectWith(getParent()->getLocalRect()); + +		// clamp to minimum size, keeping centered +		media_controls_rect.setCenterAndSize(media_controls_rect.getCenterX(), media_controls_rect.getCenterY(), +			llmax(MIN_HUD_WIDTH, media_controls_rect.getWidth()), llmax(MIN_HUD_HEIGHT, media_controls_rect.getHeight())); + +		setShape(media_controls_rect, true); + +		// Test mouse position to see if the cursor is stationary +		LLCoordWindow cursor_pos_window; +		getWindow()->getCursorPosition(&cursor_pos_window); + +		// If last pos is not equal to current pos, the mouse has moved +		// We need to reset the timer, and make sure the panel is visible +		if(cursor_pos_window.mX != mLastCursorPos.mX || +			cursor_pos_window.mY != mLastCursorPos.mY || +			mScrollState != SCROLL_NONE) +		{ +			mInactivityTimer.start(); +			mLastCursorPos = cursor_pos_window; +		} +		 +		if(isMouseOver()) +		{ +			// Never fade the controls if the mouse is over them. +			mFadeTimer.stop(); +		} +		else if(!mClearFaceOnFade && (mInactivityTimer.getElapsedTimeF32() < mInactiveTimeout)) +		{ +			// Mouse is over the object, but has not been stationary for long enough to fade the UI +			mFadeTimer.stop(); +		} +		else if(! mFadeTimer.getStarted() ) +		{ +			// we need to start fading the UI (and we have not already started) +			mFadeTimer.reset(); +			mFadeTimer.start(); +		} +		else +		{ +			// I don't think this is correct anymore.  This is done in draw() after the fade has completed. +//			setVisible(FALSE); +		} +	} +} + +/*virtual*/ +void LLPanelPrimMediaControls::draw() +{ +	F32 alpha = 1.f; +	if(mFadeTimer.getStarted()) +	{ +		F32 time = mFadeTimer.getElapsedTimeF32(); +		alpha = llmax(lerp(1.0, 0.0, time / mControlFadeTime), 0.0f); + +		if(mFadeTimer.getElapsedTimeF32() >= mControlFadeTime) +		{ +			setVisible(FALSE); +			if(mClearFaceOnFade) +			{ +				mClearFaceOnFade = false; +				mTargetImplID = LLUUID::null; +				mTargetObjectID = LLUUID::null; +				mTargetObjectFace = 0; +			} +		} +	} +	 +	{ +		LLViewDrawContext context(alpha); +		LLPanel::draw(); +	} +} + +BOOL LLPanelPrimMediaControls::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ +	mInactivityTimer.start(); +	return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks); +} + +BOOL LLPanelPrimMediaControls::handleMouseDown(S32 x, S32 y, MASK mask) +{ +	mInactivityTimer.start(); +	return LLPanel::handleMouseDown(x, y, mask); +} + +BOOL LLPanelPrimMediaControls::handleMouseUp(S32 x, S32 y, MASK mask) +{ +	mInactivityTimer.start(); +	return LLPanel::handleMouseUp(x, y, mask); +} + +BOOL LLPanelPrimMediaControls::handleKeyHere( KEY key, MASK mask ) +{ +	mInactivityTimer.start(); +	return LLPanel::handleKeyHere(key, mask); +} + +bool LLPanelPrimMediaControls::isMouseOver() +{ +	bool result = false; +	 +	if( getVisible() ) +	{ +		LLCoordWindow cursor_pos_window; +		LLCoordScreen cursor_pos_screen; +		LLCoordGL cursor_pos_gl; +		S32 x, y; +		getWindow()->getCursorPosition(&cursor_pos_window); +		getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl); +		 +		LLPanel* controls_panel = NULL; +		controls_panel = getChild<LLPanel>("media_hover_controls"); +		if(controls_panel && !controls_panel->getVisible()) +		{ +			// The hover controls aren't visible -- use the focused controls instead. +			controls_panel = getChild<LLPanel>("media_focused_controls"); +		} +		 +		if(controls_panel && controls_panel->getVisible()) +		{ +			controls_panel->screenPointToLocal(cursor_pos_gl.mX, cursor_pos_gl.mY, &x, &y); + +			LLView *hit_child = controls_panel->childFromPoint(x, y); +			if(hit_child) +			{ +				// This was useful for debugging both coordinate translation and view hieararchy problems... +//				llinfos << "mouse coords: " << x << ", " << y << " hit child " << hit_child->getName() << llendl; +				result = true; +			} +		} +	} + +	return result; +} + + +void LLPanelPrimMediaControls::onClickClose() +{ +	close(); +} + +void LLPanelPrimMediaControls::close() +{ +	LLViewerMediaFocus::getInstance()->clearFocus(); +	resetZoomLevel(); +	setVisible(FALSE); +} + + +void LLPanelPrimMediaControls::onClickBack() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* impl =getTargetMediaImpl(); +	 +	if (impl) +	{ +		impl->navigateBack(); +	} +} + +void LLPanelPrimMediaControls::onClickForward() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* impl = getTargetMediaImpl(); +	 +	if (impl) +	{ +		impl->navigateForward(); +	} +} + +void LLPanelPrimMediaControls::onClickHome() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* impl = getTargetMediaImpl(); + +	if(impl) +	{ +		impl->navigateHome(); +	} +} + +void LLPanelPrimMediaControls::onClickOpen() +{ +	LLViewerMediaImpl* impl =getTargetMediaImpl(); +	if(impl) +	{ +		if(impl->getMediaPlugin()) +		{	 +			if(impl->getMediaPlugin()->getLocation().empty()) +			{ +				LLWeb::loadURL(impl->getMediaURL()); +			} +			else +			{ +				LLWeb::loadURL( impl->getMediaPlugin()->getLocation()); +			} +		} +	}	 +} + +void LLPanelPrimMediaControls::onClickReload() +{ +	focusOnTarget(); + +	//LLViewerMedia::navigateHome(); +	LLViewerMediaImpl* impl = getTargetMediaImpl(); + +	if(impl) +	{ +		impl->navigateReload(); +	} +} + +void LLPanelPrimMediaControls::onClickPlay() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* impl = getTargetMediaImpl(); + +	if(impl) +	{ +		impl->play(); +	} +} + +void LLPanelPrimMediaControls::onClickPause() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* impl = getTargetMediaImpl(); + +	if(impl) +	{ +		impl->pause(); +	} +} + +void LLPanelPrimMediaControls::onClickStop() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* impl = getTargetMediaImpl(); + +	if(impl) +	{ +		impl->stop(); +	} +} + +void LLPanelPrimMediaControls::onClickZoom() +{ +	focusOnTarget(); + +	nextZoomLevel(); +} +void LLPanelPrimMediaControls::nextZoomLevel() +{ +	int index = 0; +	while (index < kNumZoomLevels) +	{ +		if (kZoomLevels[index] == mCurrentZoom)  +		{ +			index++; +			break; +		} +		index++; +	} +	mCurrentZoom = kZoomLevels[index % kNumZoomLevels]; +	updateZoom(); +} + +void LLPanelPrimMediaControls::resetZoomLevel() +{ +	if(mCurrentZoom != ZOOM_NONE) +	{ +		mCurrentZoom = ZOOM_NONE; +		updateZoom(); +	} +} + +void LLPanelPrimMediaControls::updateZoom() +{ +	F32 zoom_padding = 0.0f; +	switch (mCurrentZoom) +	{ +	case ZOOM_NONE: +		{ +			gAgent.setFocusOnAvatar(TRUE, ANIMATE); +			break; +		} +	case ZOOM_FAR: +		{ +			zoom_padding = ZOOM_FAR_PADDING; +			break; +		} +	case ZOOM_MEDIUM: +		{ +			zoom_padding = ZOOM_MEDIUM_PADDING; +			break; +		} +	case ZOOM_NEAR: +		{ +			zoom_padding = ZOOM_NEAR_PADDING; +			break; +		} +	default: +		{ +			gAgent.setFocusOnAvatar(TRUE, ANIMATE); +			break; +		} +	} + +	if (zoom_padding > 0.0f)		 +		LLViewerMediaFocus::setCameraZoom(getTargetObject(), mTargetObjectNormal, zoom_padding); +} +void LLPanelPrimMediaControls::onScrollUp(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->focusOnTarget(); + +	LLPluginClassMedia* plugin = this_panel->getTargetMediaPlugin(); +	 +	if(plugin) +	{ +		plugin->scrollEvent(0, -1, MASK_NONE); +	} +} +void LLPanelPrimMediaControls::onScrollUpHeld(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->mScrollState = SCROLL_UP; +} +void LLPanelPrimMediaControls::onScrollRight(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->focusOnTarget(); + +	LLViewerMediaImpl* impl = this_panel->getTargetMediaImpl(); + +	if(impl) +	{ +		impl->handleKeyHere(KEY_RIGHT, MASK_NONE); +	} +} +void LLPanelPrimMediaControls::onScrollRightHeld(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->mScrollState = SCROLL_RIGHT; +} + +void LLPanelPrimMediaControls::onScrollLeft(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->focusOnTarget(); + +	LLViewerMediaImpl* impl = this_panel->getTargetMediaImpl(); + +	if(impl) +	{ +		impl->handleKeyHere(KEY_LEFT, MASK_NONE); +	} +} +void LLPanelPrimMediaControls::onScrollLeftHeld(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->mScrollState = SCROLL_LEFT; +} + +void LLPanelPrimMediaControls::onScrollDown(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->focusOnTarget(); + +	LLPluginClassMedia* plugin = this_panel->getTargetMediaPlugin(); +	 +	if(plugin) +	{ +		plugin->scrollEvent(0, 1, MASK_NONE); +	} +} +void LLPanelPrimMediaControls::onScrollDownHeld(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->mScrollState = SCROLL_DOWN; +} + +void LLPanelPrimMediaControls::onScrollStop(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->mScrollState = SCROLL_NONE; +} + +void LLPanelPrimMediaControls::onCommitURL() +{ +	focusOnTarget(); + +	LLUICtrl *media_address_ctrl = getChild<LLUICtrl>("media_address_url"); +	std::string url = media_address_ctrl->getValue().asString(); +	if(getTargetMediaImpl() && !url.empty()) +	{ +		getTargetMediaImpl()->navigateTo( url, "", true); + +		// Make sure keyboard focus is set to the media focus object. +		gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance()); +			 +	} +	mPauseFadeout = false; +	mFadeTimer.start(); +} + + +void LLPanelPrimMediaControls::onInputURL(LLFocusableElement* caller, void *userdata) +{ + +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (userdata); +	this_panel->focusOnTarget(); + +	this_panel->mPauseFadeout = true; +	this_panel->mFadeTimer.stop(); +	this_panel->mFadeTimer.reset(); +	 +} + +void LLPanelPrimMediaControls::setCurrentURL() +{	 +	LLComboBox* media_address_combo	= getChild<LLComboBox>("media_address_combo"); +	// redirects will navigate momentarily to about:blank, don't add to history +	if (media_address_combo && mCurrentURL != "about:blank") +	{ +		media_address_combo->remove(mCurrentURL); +		media_address_combo->add(mCurrentURL, ADD_SORTED); +		media_address_combo->selectByValue(mCurrentURL); +	} +} + +void LLPanelPrimMediaControls::onCommitSlider() +{ +	focusOnTarget(); + +	LLSlider* media_play_slider_ctrl	= getChild<LLSlider>("media_play_slider"); +	LLViewerMediaImpl* media_impl = getTargetMediaImpl(); +	if (media_impl)  +	{ +		// get slider value +		F64 slider_value = media_play_slider_ctrl->getValue().asReal(); +		if(slider_value <= 0.0) +		{	 +			media_impl->stop(); +		} +		else  +		{ +			media_impl->seek(slider_value*mMovieDuration); +			//mUpdateSlider= false; +		} +	} +}		 + +void LLPanelPrimMediaControls::onCommitVolumeUp() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* media_impl = getTargetMediaImpl(); +	if (media_impl)  +	{ +		F32 volume = media_impl->getVolume(); +		 +		volume += 0.1f; +		if(volume >= 1.0f) +		{ +			volume = 1.0f; +		} +		 +		media_impl->setVolume(volume); +		getChild<LLButton>("media_volume")->setToggleState(false); +	} +}		 + +void LLPanelPrimMediaControls::onCommitVolumeDown() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* media_impl = getTargetMediaImpl(); +	if (media_impl)  +	{ +		F32 volume = media_impl->getVolume(); +		 +		volume -= 0.1f; +		if(volume <= 0.0f) +		{ +			volume = 0.0f; +		} + +		media_impl->setVolume(volume); +		getChild<LLButton>("media_volume")->setToggleState(false); +	} +}		 + + +void LLPanelPrimMediaControls::onToggleMute() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* media_impl = getTargetMediaImpl(); +	if (media_impl)  +	{ +		F32 volume = media_impl->getVolume(); +		 +		if(volume > 0.0) +		{ +			media_impl->setVolume(0.0); +		} +		else  +		{ +			media_impl->setVolume(0.5); +		} +	} +} + diff --git a/indra/newview/llpanelprimmediacontrols.h b/indra/newview/llpanelprimmediacontrols.h new file mode 100644 index 0000000000..3ec7aa2356 --- /dev/null +++ b/indra/newview/llpanelprimmediacontrols.h @@ -0,0 +1,148 @@ +/**  + * @file llpanelprimmediacontrols.h + * @brief Pop-up media controls panel + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + *  + * Copyright (c) 2003-2007, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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_PANELPRIMMEDIACONTROLS_H +#define LL_PANELPRIMMEDIACONTROLS_H + +#include "llpanel.h" +#include "llviewermedia.h" + +class LLCoordWindow; +class LLViewerMediaImpl; + +class LLPanelPrimMediaControls : public LLPanel +{ +public: +	LLPanelPrimMediaControls(); +	virtual ~LLPanelPrimMediaControls(); +	/*virtual*/ BOOL postBuild(); +	virtual void draw(); +	virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + +	virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); +	virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); +	virtual BOOL handleKeyHere(KEY key, MASK mask); +	 +	void updateShape(); +	bool isMouseOver(); +	void nextZoomLevel(); +	void resetZoomLevel(); +	void close(); + +	LLHandle<LLPanelPrimMediaControls>	getHandle() const { return mPanelHandle; } +	void setMediaFace(LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal = LLVector3::zero); + + +	enum EZoomLevel +	{ +		ZOOM_NONE = 0, +		ZOOM_FAR, +		ZOOM_MEDIUM, +		ZOOM_NEAR +	}; +	static const EZoomLevel kZoomLevels[]; +	static const int kNumZoomLevels; +	 +	enum EScrollDir +	{ +		SCROLL_UP = 0, +		SCROLL_DOWN, +		SCROLL_LEFT, +		SCROLL_RIGHT, +		SCROLL_NONE +	}; + +private: +	void onClickClose(); +	void onClickBack(); +	void onClickForward(); +	void onClickHome(); +	void onClickOpen(); +	void onClickReload(); +	void onClickPlay(); +	void onClickPause(); +	void onClickStop(); +	void onClickZoom(); +	void onCommitURL(); +	 +	void updateZoom(); +	void setCurrentURL(); +	void onCommitSlider(); +	 +	void onCommitVolumeUp(); +	void onCommitVolumeDown(); +	void onToggleMute(); +	 +	static void onScrollUp(void* user_data); +	static void onScrollUpHeld(void* user_data); +	static void onScrollLeft(void* user_data); +	static void onScrollLeftHeld(void* user_data); +	static void onScrollRight(void* user_data); +	static void onScrollRightHeld(void* user_data); +	static void onScrollDown(void* user_data); +	static void onScrollDownHeld(void* user_data); +	static void onScrollStop(void* user_data); +	 +	static void onInputURL(LLFocusableElement* caller, void *userdata); +	static bool hasControlsPermission(LLViewerObject *obj, const LLMediaEntry *media_entry); +	 +	void focusOnTarget(); +	 +	LLViewerMediaImpl* getTargetMediaImpl(); +	LLViewerObject* getTargetObject(); +	LLPluginClassMedia* getTargetMediaPlugin(); +	bool mPauseFadeout; +	bool mUpdateSlider; +	bool mClearFaceOnFade; + +	LLMatrix4 mLastCameraMat; +	EZoomLevel mCurrentZoom; +	EScrollDir mScrollState; +	LLCoordWindow mLastCursorPos; +	LLFrameTimer mInactivityTimer; +	LLFrameTimer mFadeTimer; +	F32 mInactiveTimeout; +	F32 mControlFadeTime; +	LLRootHandle<LLPanelPrimMediaControls> mPanelHandle; +	F32 mAlpha; +	std::string mCurrentURL; +	std::string mPreviousURL; +	F64 mCurrentRate; +	F64 mMovieDuration; +	int mUpdatePercent; + +	LLUUID mTargetObjectID; +	S32 mTargetObjectFace; +	LLUUID mTargetImplID; +	LLVector3 mTargetObjectNormal; +}; + +#endif // LL_PANELPRIMMEDIACONTROLS_H diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index 25e773e8b8..e97eb1df2b 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -34,7 +34,7 @@  #include "llparticipantlist.h"  #include "llavatarlist.h" -#include "llfloateractivespeakers.h" +#include "llspeakers.h"  //LLParticipantList retrieves add, clear and remove events and updates view accordingly   LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* avatar_list): @@ -48,6 +48,18 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* av  	mSpeakerMgr->addListener(mSpeakerAddListener, "add");  	mSpeakerMgr->addListener(mSpeakerRemoveListener, "remove");  	mSpeakerMgr->addListener(mSpeakerClearListener, "clear"); + +	//Lets fill avatarList with existing speakers +	LLAvatarList::uuid_vector_t& group_members = mAvatarList->getIDs(); + +	LLSpeakerMgr::speaker_list_t speaker_list; +	mSpeakerMgr->getSpeakerList(&speaker_list, true); +	for(LLSpeakerMgr::speaker_list_t::iterator it = speaker_list.begin(); it != speaker_list.end(); it++) +	{ +		group_members.push_back((*it)->mID); +	} +	mAvatarList->setDirty(); +	mAvatarList->sortByName();  }  LLParticipantList::~LLParticipantList() @@ -87,8 +99,12 @@ bool LLParticipantList::SpeakerAddListener::handleEvent(LLPointer<LLOldEvents::L  bool LLParticipantList::SpeakerRemoveListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)  {  	LLAvatarList::uuid_vector_t& group_members = mAvatarList->getIDs(); -	group_members.erase(std::find(group_members.begin(), group_members.end(), event->getValue().asUUID())); -	mAvatarList->setDirty(); +	LLAvatarList::uuid_vector_t::iterator pos = std::find(group_members.begin(), group_members.end(), event->getValue().asUUID()); +	if(pos != group_members.end()) +	{ +		group_members.erase(pos); +		mAvatarList->setDirty(); +	}  	return true;  } diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 1683d113a9..73dcd1dd92 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -191,19 +191,22 @@ void LLScreenChannel::onToastFade(LLToast* toast)  {	  	std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), static_cast<LLPanel*>(toast)); -	bool delete_toast = !mCanStoreToasts || !toast->getCanBeStored(); -	if(delete_toast) -	{ -		mToastList.erase(it); -		deleteToast(toast); -	} -	else +	if(it != mToastList.end())  	{ -		storeToast((*it)); -		mToastList.erase(it); -	}	 +		bool delete_toast = !mCanStoreToasts || !toast->getCanBeStored(); +		if(delete_toast) +		{ +			mToastList.erase(it); +			deleteToast(toast); +		} +		else +		{ +			storeToast((*it)); +			mToastList.erase(it); +		}	 -	redrawToasts(); +		redrawToasts(); +	}  }  //-------------------------------------------------------------------------- @@ -247,6 +250,7 @@ void LLScreenChannel::loadStoredToastsToChannel()  	for(it = mStoredToastList.begin(); it != mStoredToastList.end(); ++it)  	{ +		(*it).toast->setIsHidden(false);  		(*it).toast->resetTimer();  		mToastList.push_back((*it));  	} @@ -266,6 +270,7 @@ void LLScreenChannel::loadStoredToastByNotificationIDToChannel(LLUUID id)  	mOverflowToastHidden = false;  	LLToast* toast = (*it).toast; +	toast->setIsHidden(false);  	toast->resetTimer();  	mToastList.push_back((*it));  	mStoredToastList.erase(it); @@ -519,6 +524,7 @@ void LLScreenChannel::createStartUpToast(S32 notif_num, F32 timer)  	LLRect toast_rect;  	LLToast::Params p;  	p.lifetime_secs = timer; +	p.enable_hide_btn = false;  	mStartUpToastPanel = new LLToast(p);  	if(!mStartUpToastPanel) diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp new file mode 100644 index 0000000000..2341fcfc6d --- /dev/null +++ b/indra/newview/llspeakers.cpp @@ -0,0 +1,639 @@ +/**  + * @file llspeakers.cpp + * @brief Management interface for muting and controlling volume of residents currently speaking + * + * $LicenseInfo:firstyear=2005&license=viewergpl$ + *  + * Copyright (c) 2005-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 "llviewerprecompiledheaders.h" + +#include "llspeakers.h" + +#include "llagent.h" +#include "llappviewer.h" +#include "llmutelist.h" +#include "llsdutil.h" +#include "lluicolortable.h" +#include "llviewerobjectlist.h" +#include "llvoavatar.h" +#include "llworld.h" + +const F32 SPEAKER_TIMEOUT = 10.f; // seconds of not being on voice channel before removed from list of active speakers +const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f); +const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f); + +LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerType type) :  +	mStatus(LLSpeaker::STATUS_TEXT_ONLY), +	mLastSpokeTime(0.f),  +	mSpeechVolume(0.f),  +	mHasSpoken(FALSE), +	mHasLeftCurrentCall(FALSE), +	mDotColor(LLColor4::white), +	mID(id), +	mTyping(FALSE), +	mSortIndex(0), +	mType(type), +	mIsModerator(FALSE), +	mModeratorMutedVoice(FALSE), +	mModeratorMutedText(FALSE) +{ +	if (name.empty() && type == SPEAKER_AGENT) +	{ +		lookupName(); +	} +	else +	{ +		mDisplayName = name; +	} + +	gVoiceClient->setUserVolume(id, LLMuteList::getInstance()->getSavedResidentVolume(id)); + +	mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); +} + + +void LLSpeaker::lookupName() +{ +	gCacheName->get(mID, FALSE, boost::bind(&LLSpeaker::onAvatarNameLookup, this, _1, _2, _3, _4)); +} + +void LLSpeaker::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) +{ +	mDisplayName = first + " " + last; +} + +LLSpeakerTextModerationEvent::LLSpeakerTextModerationEvent(LLSpeaker* source) +: LLEvent(source, "Speaker text moderation event") +{ +} + +LLSD LLSpeakerTextModerationEvent::getValue() +{ +	return std::string("text"); +} + + +LLSpeakerVoiceModerationEvent::LLSpeakerVoiceModerationEvent(LLSpeaker* source) +: LLEvent(source, "Speaker voice moderation event") +{ +} + +LLSD LLSpeakerVoiceModerationEvent::getValue() +{ +	return std::string("voice"); +} + +LLSpeakerListChangeEvent::LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id) +: LLEvent(source, "Speaker added/removed from speaker mgr"), +  mSpeakerID(speaker_id) +{ +} + +LLSD LLSpeakerListChangeEvent::getValue() +{ +	return mSpeakerID; +} + +// helper sort class +struct LLSortRecentSpeakers +{ +	bool operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const; +}; + +bool LLSortRecentSpeakers::operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const +{ +	// Sort first on status +	if (lhs->mStatus != rhs->mStatus)  +	{ +		return (lhs->mStatus < rhs->mStatus); +	} + +	// and then on last speaking time +	if(lhs->mLastSpokeTime != rhs->mLastSpokeTime) +	{ +		return (lhs->mLastSpokeTime > rhs->mLastSpokeTime); +	} +	 +	// and finally (only if those are both equal), on name. +	return(	lhs->mDisplayName.compare(rhs->mDisplayName) < 0 ); +} + + +// +// LLSpeakerMgr +// + +LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) :  +	mVoiceChannel(channelp) +{ +} + +LLSpeakerMgr::~LLSpeakerMgr() +{ +} + +LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type) +{ +	if (id.isNull()) return NULL; + +	LLPointer<LLSpeaker> speakerp; +	if (mSpeakers.find(id) == mSpeakers.end()) +	{ +		speakerp = new LLSpeaker(id, name, type); +		speakerp->mStatus = status; +		mSpeakers.insert(std::make_pair(speakerp->mID, speakerp)); +		mSpeakersSorted.push_back(speakerp); +		fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add"); +	} +	else +	{ +		speakerp = findSpeaker(id); +		if (speakerp.notNull()) +		{ +			// keep highest priority status (lowest value) instead of overriding current value +			speakerp->mStatus = llmin(speakerp->mStatus, status); +			speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); +			// RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id +			// we need to override speakers that we think are objects when we find out they are really +			// residents +			if (type == LLSpeaker::SPEAKER_AGENT) +			{ +				speakerp->mType = LLSpeaker::SPEAKER_AGENT; +				speakerp->lookupName(); +			} +		} +	} + +	return speakerp; +} + +void LLSpeakerMgr::update(BOOL resort_ok) +{ +	if (!gVoiceClient) +	{ +		return; +	} +	 +	LLColor4 speaking_color = LLUIColorTable::instance().getColor("SpeakingColor"); +	LLColor4 overdriven_color = LLUIColorTable::instance().getColor("OverdrivenColor"); + +	if(resort_ok) // only allow list changes when user is not interacting with it +	{ +		updateSpeakerList(); +	} + +	// update status of all current speakers +	BOOL voice_channel_active = (!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); +	for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();) +	{ +		LLUUID speaker_id = speaker_it->first; +		LLSpeaker* speakerp = speaker_it->second; +		 +		speaker_map_t::iterator  cur_speaker_it = speaker_it++; + +		if (voice_channel_active && gVoiceClient->getVoiceEnabled(speaker_id)) +		{ +			speakerp->mSpeechVolume = gVoiceClient->getCurrentPower(speaker_id); +			BOOL moderator_muted_voice = gVoiceClient->getIsModeratorMuted(speaker_id); +			if (moderator_muted_voice != speakerp->mModeratorMutedVoice) +			{ +				speakerp->mModeratorMutedVoice = moderator_muted_voice; +				speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp)); +			} + +			if (gVoiceClient->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice) +			{ +				speakerp->mStatus = LLSpeaker::STATUS_MUTED; +			} +			else if (gVoiceClient->getIsSpeaking(speaker_id)) +			{ +				// reset inactivity expiration +				if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING) +				{ +					speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); +					speakerp->mHasSpoken = TRUE; +				} +				speakerp->mStatus = LLSpeaker::STATUS_SPEAKING; +				// interpolate between active color and full speaking color based on power of speech output +				speakerp->mDotColor = speaking_color; +				if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL) +				{ +					speakerp->mDotColor = overdriven_color; +				} +			} +			else +			{ +				speakerp->mSpeechVolume = 0.f; +				speakerp->mDotColor = ACTIVE_COLOR; + +				if (speakerp->mHasSpoken) +				{ +					// have spoken once, not currently speaking +					speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN; +				} +				else +				{ +					// default state for being in voice channel +					speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE; +				} +			} +		} +		// speaker no longer registered in voice channel, demote to text only +		else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL) +		{ +			if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL) +			{ +				// external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice) +				speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; +			} +			else +			{ +				speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY; +				speakerp->mSpeechVolume = 0.f; +				speakerp->mDotColor = ACTIVE_COLOR; +			} +		} +	} + +	if(resort_ok)  // only allow list changes when user is not interacting with it +	{ +		// sort by status then time last spoken +		std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers()); +	} + +	// for recent speakers who are not currently speaking, show "recent" color dot for most recent +	// fading to "active" color + +	S32 recent_speaker_count = 0; +	S32 sort_index = 0; +	speaker_list_t::iterator sorted_speaker_it; +	for(sorted_speaker_it = mSpeakersSorted.begin();  +		sorted_speaker_it != mSpeakersSorted.end(); ) +	{ +		LLPointer<LLSpeaker> speakerp = *sorted_speaker_it; +		 +		// color code recent speakers who are not currently speaking +		if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN) +		{ +			speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f)); +			recent_speaker_count++; +		} + +		// stuff sort ordinal into speaker so the ui can sort by this value +		speakerp->mSortIndex = sort_index++; + +		// remove speakers that have been gone too long +		if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL && speakerp->mActivityTimer.hasExpired()) +		{ +			fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "remove"); + +			mSpeakers.erase(speakerp->mID); +			sorted_speaker_it = mSpeakersSorted.erase(sorted_speaker_it); +		} +		else +		{ +			++sorted_speaker_it; +		} +	} +} + +void LLSpeakerMgr::updateSpeakerList() +{ +	// are we bound to the currently active voice channel? +	if ((!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) +	{ +		LLVoiceClient::participantMap* participants = gVoiceClient->getParticipantList(); +		if(participants) +		{ +			LLVoiceClient::participantMap::iterator participant_it; + +			// add new participants to our list of known speakers +			for (participant_it = participants->begin(); participant_it != participants->end(); ++participant_it) +			{ +				LLVoiceClient::participantState* participantp = participant_it->second; +				setSpeaker(participantp->mAvatarID, participantp->mDisplayName, LLSpeaker::STATUS_VOICE_ACTIVE, (participantp->isAvatar()?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); +			} +		} +	} +} + +LLPointer<LLSpeaker> LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id) +{ +	speaker_map_t::iterator found_it = mSpeakers.find(speaker_id); +	if (found_it == mSpeakers.end()) +	{ +		return NULL; +	} +	return found_it->second; +} + +void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_text) +{ +	speaker_list->clear(); +	for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) +	{ +		LLPointer<LLSpeaker> speakerp = speaker_it->second; +		// what about text only muted or inactive? +		if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY) +		{ +			speaker_list->push_back(speakerp); +		} +	} +} + +const LLUUID LLSpeakerMgr::getSessionID()  +{  +	return mVoiceChannel->getSessionID();  +} + + +void LLSpeakerMgr::setSpeakerTyping(const LLUUID& speaker_id, BOOL typing) +{ +	LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); +	if (speakerp.notNull()) +	{ +		speakerp->mTyping = typing; +	} +} + +// speaker has chatted via either text or voice +void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id) +{ +	LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); +	if (speakerp.notNull()) +	{ +		speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); +		speakerp->mHasSpoken = TRUE; +	} +} + +BOOL LLSpeakerMgr::isVoiceActive() +{ +	// mVoiceChannel = NULL means current voice channel, whatever it is +	return LLVoiceClient::voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive(); +} + + +// +// LLIMSpeakerMgr +// +LLIMSpeakerMgr::LLIMSpeakerMgr(LLVoiceChannel* channel) : LLSpeakerMgr(channel) +{ +} + +void LLIMSpeakerMgr::updateSpeakerList() +{ +	// don't do normal updates which are pulled from voice channel +	// rely on user list reported by sim +	 +	// We need to do this to allow PSTN callers into group chats to show in the list. +	LLSpeakerMgr::updateSpeakerList(); +	 +	return; +} + +void LLIMSpeakerMgr::setSpeakers(const LLSD& speakers) +{ +	if ( !speakers.isMap() ) return; + +	if ( speakers.has("agent_info") && speakers["agent_info"].isMap() ) +	{ +		LLSD::map_const_iterator speaker_it; +		for(speaker_it = speakers["agent_info"].beginMap(); +			speaker_it != speakers["agent_info"].endMap(); +			++speaker_it) +		{ +			LLUUID agent_id(speaker_it->first); + +			LLPointer<LLSpeaker> speakerp = setSpeaker( +				agent_id, +				LLStringUtil::null, +				LLSpeaker::STATUS_TEXT_ONLY); + +			if ( speaker_it->second.isMap() ) +			{ +				speakerp->mIsModerator = speaker_it->second["is_moderator"]; +				speakerp->mModeratorMutedText = +					speaker_it->second["mutes"]["text"]; +			} +		} +	} +	else if ( speakers.has("agents" ) && speakers["agents"].isArray() ) +	{ +		//older, more decprecated way.  Need here for +		//using older version of servers +		LLSD::array_const_iterator speaker_it; +		for(speaker_it = speakers["agents"].beginArray(); +			speaker_it != speakers["agents"].endArray(); +			++speaker_it) +		{ +			const LLUUID agent_id = (*speaker_it).asUUID(); + +			LLPointer<LLSpeaker> speakerp = setSpeaker( +				agent_id, +				LLStringUtil::null, +				LLSpeaker::STATUS_TEXT_ONLY); +		} +	} +} + +void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) +{ +	if ( !update.isMap() ) return; + +	if ( update.has("agent_updates") && update["agent_updates"].isMap() ) +	{ +		LLSD::map_const_iterator update_it; +		for( +			update_it = update["agent_updates"].beginMap(); +			update_it != update["agent_updates"].endMap(); +			++update_it) +		{ +			LLUUID agent_id(update_it->first); +			LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id); + +			LLSD agent_data = update_it->second; + +			if (agent_data.isMap() && agent_data.has("transition")) +			{ +				if (agent_data["transition"].asString() == "LEAVE" && speakerp.notNull()) +				{ +					speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; +					speakerp->mDotColor = INACTIVE_COLOR; +					speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); +				} +				else if (agent_data["transition"].asString() == "ENTER") +				{ +					// add or update speaker +					speakerp = setSpeaker(agent_id); +				} +				else +				{ +					llwarns << "bad membership list update " << ll_print_sd(agent_data["transition"]) << llendl; +				} +			} + +			if (speakerp.isNull()) continue; + +			// should have a valid speaker from this point on +			if (agent_data.isMap() && agent_data.has("info")) +			{ +				LLSD agent_info = agent_data["info"]; + +				if (agent_info.has("is_moderator")) +				{ +					speakerp->mIsModerator = agent_info["is_moderator"]; +				} + +				if (agent_info.has("mutes")) +				{ +					speakerp->mModeratorMutedText = agent_info["mutes"]["text"]; +				} +			} +		} +	} +	else if ( update.has("updates") && update["updates"].isMap() ) +	{ +		LLSD::map_const_iterator update_it; +		for ( +			update_it = update["updates"].beginMap(); +			update_it != update["updates"].endMap(); +			++update_it) +		{ +			LLUUID agent_id(update_it->first); +			LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id); + +			std::string agent_transition = update_it->second.asString(); +			if (agent_transition == "LEAVE" && speakerp.notNull()) +			{ +				speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; +				speakerp->mDotColor = INACTIVE_COLOR; +				speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); +			} +			else if ( agent_transition == "ENTER") +			{ +				// add or update speaker +				speakerp = setSpeaker(agent_id); +			} +			else +			{ +				llwarns << "bad membership list update " +						<< agent_transition << llendl; +			} +		} +	} +} + + +// +// LLActiveSpeakerMgr +// + +LLActiveSpeakerMgr::LLActiveSpeakerMgr() : LLSpeakerMgr(NULL) +{ +} + +void LLActiveSpeakerMgr::updateSpeakerList() +{ +	// point to whatever the current voice channel is +	mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); + +	// always populate from active voice channel +	if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) +	{ +		fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear"); +		mSpeakers.clear(); +		mSpeakersSorted.clear(); +		mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); +	} +	LLSpeakerMgr::updateSpeakerList(); + +	// clean up text only speakers +	for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) +	{ +		LLUUID speaker_id = speaker_it->first; +		LLSpeaker* speakerp = speaker_it->second; +		if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) +		{ +			// automatically flag text only speakers for removal +			speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; +		} +	} + +} + + + +// +// LLLocalSpeakerMgr +// + +LLLocalSpeakerMgr::LLLocalSpeakerMgr() : LLSpeakerMgr(LLVoiceChannelProximal::getInstance()) +{ +} + +LLLocalSpeakerMgr::~LLLocalSpeakerMgr () +{ +} + +void LLLocalSpeakerMgr::updateSpeakerList() +{ +	// pull speakers from voice channel +	LLSpeakerMgr::updateSpeakerList(); + +	if (gDisconnected)//the world is cleared. +	{ +		return ; +	} + +	// pick up non-voice speakers in chat range +	std::vector<LLUUID> avatar_ids; +	std::vector<LLVector3d> positions; +	LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS); +	for(U32 i=0; i<avatar_ids.size(); i++) +	{ +		setSpeaker(avatar_ids[i]); +	} + +	// check if text only speakers have moved out of chat range +	for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) +	{ +		LLUUID speaker_id = speaker_it->first; +		LLSpeaker* speakerp = speaker_it->second; +		if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) +		{ +			LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id); +			if (!avatarp || dist_vec(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS) +			{ +				speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; +				speakerp->mDotColor = INACTIVE_COLOR; +				speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); +			} +		} +	} +} diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h new file mode 100644 index 0000000000..e0f22bff4f --- /dev/null +++ b/indra/newview/llspeakers.h @@ -0,0 +1,172 @@ +/**  + * @file llspeakers.h + * @brief Management interface for muting and controlling volume of residents currently speaking + * + * $LicenseInfo:firstyear=2005&license=viewergpl$ + *  + * Copyright (c) 2005-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_LLSPEAKERS_H +#define LL_LLSPEAKERS_H + +#include "llevent.h" +#include "llspeakers.h" +#include "llvoicechannel.h" + +class LLSpeakerMgr; + +// data for a given participant in a voice channel +class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider<LLSpeaker>, public boost::signals2::trackable +{ +public: +	typedef enum e_speaker_type +	{ +		SPEAKER_AGENT, +		SPEAKER_OBJECT, +		SPEAKER_EXTERNAL	// Speaker that doesn't map to an avatar or object (i.e. PSTN caller in a group) +	} ESpeakerType; + +	typedef enum e_speaker_status +	{ +		STATUS_SPEAKING, +		STATUS_HAS_SPOKEN, +		STATUS_VOICE_ACTIVE, +		STATUS_TEXT_ONLY, +		STATUS_NOT_IN_CHANNEL, +		STATUS_MUTED +	} ESpeakerStatus; + + +	LLSpeaker(const LLUUID& id, const std::string& name = LLStringUtil::null, const ESpeakerType type = SPEAKER_AGENT); +	~LLSpeaker() {}; +	void lookupName(); + +	void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); + +	ESpeakerStatus	mStatus;			// current activity status in speech group +	F32				mLastSpokeTime;		// timestamp when this speaker last spoke +	F32				mSpeechVolume;		// current speech amplitude (timea average rms amplitude?) +	std::string		mDisplayName;		// cache user name for this speaker +	LLFrameTimer	mActivityTimer;	// time out speakers when they are not part of current voice channel +	BOOL			mHasSpoken;			// has this speaker said anything this session? +	BOOL			mHasLeftCurrentCall;	// has this speaker left the current voice call? +	LLColor4		mDotColor; +	LLUUID			mID; +	BOOL			mTyping; +	S32				mSortIndex; +	ESpeakerType	mType; +	BOOL			mIsModerator; +	BOOL			mModeratorMutedVoice; +	BOOL			mModeratorMutedText; +}; + +class LLSpeakerTextModerationEvent : public LLOldEvents::LLEvent +{ +public: +	LLSpeakerTextModerationEvent(LLSpeaker* source); +	/*virtual*/ LLSD getValue(); +}; + +class LLSpeakerVoiceModerationEvent : public LLOldEvents::LLEvent +{ +public: +	LLSpeakerVoiceModerationEvent(LLSpeaker* source); +	/*virtual*/ LLSD getValue(); +}; + +class LLSpeakerListChangeEvent : public LLOldEvents::LLEvent +{ +public: +	LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id); +	/*virtual*/ LLSD getValue(); + +private: +	const LLUUID& mSpeakerID; +}; + +class LLSpeakerMgr : public LLOldEvents::LLObservable +{ +public: +	LLSpeakerMgr(LLVoiceChannel* channelp); +	virtual ~LLSpeakerMgr(); + +	LLPointer<LLSpeaker> findSpeaker(const LLUUID& avatar_id); +	void update(BOOL resort_ok); +	void setSpeakerTyping(const LLUUID& speaker_id, BOOL typing); +	void speakerChatted(const LLUUID& speaker_id); +	LLPointer<LLSpeaker> setSpeaker(const LLUUID& id,  +					const std::string& name = LLStringUtil::null,  +					LLSpeaker::ESpeakerStatus status = LLSpeaker::STATUS_TEXT_ONLY,  +					LLSpeaker::ESpeakerType = LLSpeaker::SPEAKER_AGENT); + +	BOOL isVoiceActive(); + +	typedef std::vector<LLPointer<LLSpeaker> > speaker_list_t; +	void getSpeakerList(speaker_list_t* speaker_list, BOOL include_text); +	LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; } +	const LLUUID getSessionID(); + +protected: +	virtual void updateSpeakerList(); + +	typedef std::map<LLUUID, LLPointer<LLSpeaker> > speaker_map_t; +	speaker_map_t		mSpeakers; + +	speaker_list_t		mSpeakersSorted; +	LLFrameTimer		mSpeechTimer; +	LLVoiceChannel*		mVoiceChannel; +}; + +class LLIMSpeakerMgr : public LLSpeakerMgr +{ +public: +	LLIMSpeakerMgr(LLVoiceChannel* channel); +	 +	void updateSpeakers(const LLSD& update); +	void setSpeakers(const LLSD& speakers); +protected: +	virtual void updateSpeakerList(); +}; + +class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLActiveSpeakerMgr> +{ +public: +	LLActiveSpeakerMgr(); +protected: +	virtual void updateSpeakerList(); +}; + +class LLLocalSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLLocalSpeakerMgr> +{ +public: +	LLLocalSpeakerMgr(); +	~LLLocalSpeakerMgr (); +protected: +	virtual void updateSpeakerList(); +}; + +#endif // LL_LLSPEAKERS_H diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index 86290e6695..93a931dc78 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -113,6 +113,12 @@ void LLSysWellWindow::connectListUpdaterToSignal(std::string notification_type)  }  //--------------------------------------------------------------------------------- +void LLSysWellWindow::onStartUpToastClick(S32 x, S32 y, MASK mask) +{ +	onChicletClick(); +} + +//---------------------------------------------------------------------------------  void LLSysWellWindow::onChicletClick()  {  	// 1 - remove StartUp toast and channel if present diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h index fa6a1abea4..cbc5f7358f 100644 --- a/indra/newview/llsyswellwindow.h +++ b/indra/newview/llsyswellwindow.h @@ -76,6 +76,7 @@ public:  	void onItemClose(LLSysWellItem* item);  	void onStoreToast(LLPanel* info_panel, LLUUID id);  	void onChicletClick(); +	void onStartUpToastClick(S32 x, S32 y, MASK mask);  	// size constants for the window and for its elements  	static const S32 MAX_WINDOW_HEIGHT		= 200; diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index 17547cae39..5d9046ac90 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -804,8 +804,9 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,  	gGL.setColorMask(false, true);  	gGL.setSceneBlendType(LLRender::BT_REPLACE); +	  	// (Optionally) replace alpha with a single component image from a tga file. -	if (!info->mStaticAlphaFileName.empty() && mMaskLayerList.empty()) +	if (!info->mStaticAlphaFileName.empty())  	{  		LLGLSNoAlphaTest gls_no_alpha_test;  		gGL.flush(); diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index eba43d76a6..24824a095c 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -63,6 +63,7 @@ LLToast::LLToast(const LLToast::Params& p)  	mHideBtnEnabled(p.enable_hide_btn),  	mHideBtn(NULL),  	mNotification(p.notification), +	mIsHidden(false),  	mHideBtnPressed(false)  {  	LLUICtrlFactory::getInstance()->buildFloater(this, "panel_toast.xml", NULL); @@ -143,7 +144,8 @@ void LLToast::hide()  {  	setVisible(FALSE);  	mTimer.stop(); -	mOnFadeSignal(this); +	mIsHidden = true; +	mOnFadeSignal(this);   }  //-------------------------------------------------------------------------- @@ -159,9 +161,7 @@ void LLToast::tick()  {  	if(mCanFade)  	{ -		setVisible(FALSE); -		mTimer.stop(); -		mOnFadeSignal(this);  +		hide();  	}  } @@ -206,6 +206,16 @@ void LLToast::draw()  //--------------------------------------------------------------------------  void LLToast::setVisible(BOOL show)  { +	if(mIsHidden) +	{ +		// this toast is invisible after fade until its ScreenChannel will allow it +		// +		// (EXT-1849) according to this bug a toast can be resurrected from +		// invisible state if it faded during a teleportation +		// then it fades a second time and causes a crash +		return; +	} +  	if(show)  	{  		setBackgroundOpaque(TRUE); diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 1826c13ebc..0698c94880 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -125,6 +125,8 @@ public:  	void setCanBeStored(bool can_be_stored) { mCanBeStored = can_be_stored; }  	//  	bool getCanBeStored() { return mCanBeStored; } +	// set whether this toast considered as hidden or not +	void setIsHidden( bool is_toast_hidden ) { mIsHidden = is_toast_hidden; }  	// Registers signals/callbacks for events @@ -164,6 +166,7 @@ private:  	bool		mCanBeStored;  	bool		mHideBtnEnabled;  	bool		mHideBtnPressed; +	bool		mIsHidden;  // this flag is TRUE when a toast has faded or was hidden with (x) button (EXT-1849)  };  } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 57a4117d5d..366e5602bd 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -42,7 +42,6 @@  #include "llconsole.h"  #include "llinventorymodel.h"  #include "llnotify.h" -#include "llimview.h"  #include "llgesturemgr.h"  #include "llinventorybridge.h" diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 02fda191be..8bd74dcb04 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -156,10 +156,10 @@ public:  	{  		if(!mInitialized && ! mime_type.empty())  		{ -			if (mMediaImpl->initializeMedia(mime_type)) +			if(mMediaImpl->initializeMedia(mime_type))  			{  				mInitialized = true; -				mMediaImpl->play(); +				mMediaImpl->loadURI();  			}  		}  	} @@ -267,10 +267,6 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s  			{  				needs_navigate = (media_entry->getCurrentURL() != previous_url);  			} -			else if(!media_entry->getHomeURL().empty()) -			{ -				needs_navigate = (media_entry->getHomeURL() != previous_url); -			}  		}  	}  	else @@ -293,8 +289,6 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s  	if(media_impl && needs_navigate)  	{  		std::string url = media_entry->getCurrentURL(); -		if(url.empty()) -			url = media_entry->getHomeURL();  		media_impl->navigateTo(url, "", true, true);  	} @@ -639,13 +633,14 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,  	mUsedInUI(false),  	mHasFocus(false),  	mPriority(LLPluginClassMedia::PRIORITY_UNLOADED), -	mDoNavigateOnLoad(false), -	mDoNavigateOnLoadRediscoverType(false), -	mDoNavigateOnLoadServerRequest(false), +	mNavigateRediscoverType(false), +	mNavigateServerRequest(false),  	mMediaSourceFailed(false),  	mRequestedVolume(1.0f),  	mIsMuted(false),  	mNeedsMuteCheck(false), +	mPreviousMediaState(MEDIA_NONE), +	mPreviousMediaTime(0.0f),  	mIsUpdated(false)  {  @@ -716,7 +711,6 @@ bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type)  		mMimeType = mime_type;  	} -	// play();  	return (mMediaSource != NULL);  } @@ -729,16 +723,13 @@ void LLViewerMediaImpl::createMediaSource()  		return;  	} -	if(mDoNavigateOnLoad) +	if(! mMediaURL.empty())  	{ -		if(! mMediaURL.empty()) -		{ -			navigateTo(mMediaURL, mMimeType, mDoNavigateOnLoadRediscoverType, mDoNavigateOnLoadServerRequest); -		} -		else if(! mMimeType.empty()) -		{ -			initializeMedia(mMimeType); -		} +		navigateInternal(); +	} +	else if(! mMimeType.empty()) +	{ +		initializeMedia(mMimeType);  	}  } @@ -869,6 +860,46 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)  	return false;  } +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::loadURI() +{ +	if(mMediaSource) +	{ +		mMediaSource->loadURI( mMediaURL ); + +		if(mPreviousMediaState == MEDIA_PLAYING) +		{ +			// This media was playing before this instance was unloaded. + +			if(mPreviousMediaTime != 0.0f) +			{ +				// Seek back to where we left off, if possible. +				seek(mPreviousMediaTime); +			} +			 +			start(); +		} +		else if(mPreviousMediaState == MEDIA_PAUSED) +		{ +			// This media was paused before this instance was unloaded. + +			if(mPreviousMediaTime != 0.0f) +			{ +				// Seek back to where we left off, if possible. +				seek(mPreviousMediaTime); +			} +			 +			pause(); +		} +		else +		{ +			// No relevant previous media play state -- if we're loading the URL, we want to start playing. +			start(); +		} +	} +} + +//////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::setSize(int width, int height)  {  	mMediaWidth = width; @@ -882,24 +913,21 @@ void LLViewerMediaImpl::setSize(int width, int height)  //////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::play()  { -	// first stop any previously playing media -	// stop(); - -	// mMediaSource->addObserver( this ); +	// If the media source isn't there, try to initialize it and load an URL.  	if(mMediaSource == NULL)  	{ -	 	if(!initializePlugin(mMimeType)) +	 	if(!initializeMedia(mMimeType))  		{  			// This may be the case where the plugin's priority is PRIORITY_UNLOADED  			return;  		} +		 +		// Only do this if the media source was just loaded. +		loadURI();  	} -	mMediaSource->loadURI( mMediaURL ); -	if(/*mMediaSource->pluginSupportsMediaTime()*/ true) -	{ -		start(); -	} +	// always start the media +	start();  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -1165,27 +1193,21 @@ void LLViewerMediaImpl::navigateHome()  //////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type,  bool rediscover_type, bool server_request)  { -	if(server_request) -	{ -		setNavState(MEDIANAVSTATE_SERVER_SENT); -	} -	else +	if(mMediaURL != url)  	{ -		setNavState(MEDIANAVSTATE_NONE); +		// Don't carry media play state across distinct URLs. +		resetPreviousMediaState();  	}  	// Always set the current URL and MIME type.  	mMediaURL = url;  	mMimeType = mime_type; -	// If the current URL is not null, make the instance do a navigate on load. -	mDoNavigateOnLoad = !mMediaURL.empty(); -  	// if mime type discovery was requested, we'll need to do it when the media loads -	mDoNavigateOnLoadRediscoverType = rediscover_type; +	mNavigateRediscoverType = rediscover_type;  	// and if this was a server request, the navigate on load will also need to be one. -	mDoNavigateOnLoadServerRequest = server_request; +	mNavigateServerRequest = server_request;  	// An explicit navigate resets the "failed" flag.  	mMediaSourceFailed = false; @@ -1193,7 +1215,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi  	if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)  	{  		// Helpful to have media urls in log file. Shouldn't be spammy. -		llinfos << "UNLOADED media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl; +		llinfos << "NOT LOADING media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl;  		// This impl should not be loaded at this time.  		LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; @@ -1201,10 +1223,24 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi  		return;  	} +	navigateInternal(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateInternal() +{  	// Helpful to have media urls in log file. Shouldn't be spammy. -	llinfos << "media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl; -	 -	 +	llinfos << "media id= " << mTextureId << " url=" << mMediaURL << " mime_type=" << mMimeType << llendl; + +	if(mNavigateServerRequest) +	{ +		setNavState(MEDIANAVSTATE_SERVER_SENT); +	} +	else +	{ +		setNavState(MEDIANAVSTATE_NONE); +	} +			  	// If the caller has specified a non-empty MIME type, look that up in our MIME types list.  	// If we have a plugin for that MIME type, use that instead of attempting auto-discovery.  	// This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type @@ -1216,11 +1252,11 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi  		if(!plugin_basename.empty())  		{  			// We have a plugin for this mime type -			rediscover_type = false; +			mNavigateRediscoverType = false;  		}  	} -	if(rediscover_type) +	if(mNavigateRediscoverType)  	{  		LLURI uri(mMediaURL); @@ -1236,7 +1272,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi  			// We use "data" internally for a text/html url for loading the login screen  			if(initializeMedia("text/html"))  			{ -				mMediaSource->loadURI( mMediaURL ); +				loadURI();  			}  		}  		else @@ -1244,24 +1280,18 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi  			// This catches 'rtsp://' urls  			if(initializeMedia(scheme))  			{ -				mMediaSource->loadURI( mMediaURL ); +				loadURI();  			}  		}  	} -	else if (mMediaSource) +	else if(initializeMedia(mMimeType))  	{ -		mMediaSource->loadURI( mMediaURL ); -	} -	else if(initializeMedia(mime_type) && mMediaSource) -	{ -		mMediaSource->loadURI( mMediaURL ); +		loadURI();  	}  	else  	{ -		LL_WARNS("Media") << "Couldn't navigate to: " << url << " as there is no media type for: " << mime_type << LL_ENDL; -		return; +		LL_WARNS("Media") << "Couldn't navigate to: " << mMediaURL << " as there is no media type for: " << mMimeType << LL_ENDL;  	} -  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -1390,6 +1420,7 @@ void LLViewerMediaImpl::update()  	if(mMediaSource->isPluginExited())  	{ +		resetPreviousMediaState();  		destroyMediaSource();  		return;  	} @@ -1586,6 +1617,14 @@ bool LLViewerMediaImpl::hasMedia()  }  ////////////////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaImpl::resetPreviousMediaState() +{ +	mPreviousMediaState = MEDIA_NONE; +	mPreviousMediaTime = 0.0f; +} + +//////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent event)  {  	switch(event) @@ -1595,6 +1634,9 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  			// The plugin failed to load properly.  Make sure the timer doesn't retry.  			// TODO: maybe mark this plugin as not loadable somehow?  			mMediaSourceFailed = true; + +			// Reset the last known state of the media to defaults. +			resetPreviousMediaState();  			// TODO: may want a different message for this case?  			LLSD args; @@ -1608,6 +1650,9 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  			// The plugin crashed.  			mMediaSourceFailed = true; +			// Reset the last known state of the media to defaults. +			resetPreviousMediaState(); +  			LLSD args;  			args["PLUGIN"] = LLMIMETypes::implType(mMimeType);  			// SJB: This is getting called every frame if the plugin fails to load, continuously respawining the alert! @@ -1833,11 +1878,11 @@ void LLViewerMediaImpl::setUsedInUI(bool used_in_ui)  	{  		if(getVisible())  		{ -			mPriority = LLPluginClassMedia::PRIORITY_NORMAL; +			setPriority(LLPluginClassMedia::PRIORITY_NORMAL);  		}  		else  		{ -			mPriority = LLPluginClassMedia::PRIORITY_HIDDEN; +			setPriority(LLPluginClassMedia::PRIORITY_HIDDEN);  		}  		createMediaSource(); @@ -1858,6 +1903,15 @@ F64 LLViewerMediaImpl::getCPUUsage() const  void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority)  { +	if(mPriority != priority) +	{ +		LL_INFOS("PluginPriority") +			<< "changing priority of media id " << mTextureId +			<< " from " << LLPluginClassMedia::priorityToString(mPriority) +			<< " to " << LLPluginClassMedia::priorityToString(priority) +			<< LL_ENDL; +	} +	  	mPriority = priority;  	if(priority == LLPluginClassMedia::PRIORITY_UNLOADED) @@ -1865,6 +1919,11 @@ void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority)  		if(mMediaSource)  		{  			// Need to unload the media source +			 +			// First, save off previous media state +			mPreviousMediaState = mMediaSource->getStatus(); +			mPreviousMediaTime = mMediaSource->getCurrentTime(); +			  			destroyMediaSource();  		}  	} diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index b15314e954..4f0d39dd80 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -123,6 +123,7 @@ public:  	void setMediaType(const std::string& media_type);  	bool initializeMedia(const std::string& mime_type);  	bool initializePlugin(const std::string& media_type); +	void loadURI();  	LLPluginClassMedia* getMediaPlugin() { return mMediaSource; }  	void setSize(int width, int height); @@ -151,6 +152,7 @@ public:  	void navigateReload();  	void navigateHome();  	void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false, bool server_request = false); +	void navigateInternal();  	void navigateStop();  	bool handleKeyHere(KEY key, MASK mask);  	bool handleUnicodeCharHere(llwchar uni_char); @@ -174,6 +176,7 @@ public:  	bool isMediaPaused();  	bool hasMedia();  	bool isMediaFailed() { return mMediaSourceFailed; }; +	void resetPreviousMediaState();  	ECursorType getLastSetCursor() { return mLastSetCursor; }; @@ -287,14 +290,14 @@ public:  	bool mUsedInUI;  	bool mHasFocus;  	LLPluginClassMedia::EPriority mPriority; -	bool mDoNavigateOnLoad; -	bool mDoNavigateOnLoadRediscoverType; -	bool mDoNavigateOnLoadServerRequest; +	bool mNavigateRediscoverType; +	bool mNavigateServerRequest;  	bool mMediaSourceFailed;  	F32 mRequestedVolume;  	bool mIsMuted;  	bool mNeedsMuteCheck; - +	int mPreviousMediaState; +	F64 mPreviousMediaTime;  private:  	BOOL mIsUpdated ; diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index b47e0b8406..5d0b77d4fb 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -35,7 +35,7 @@  //LLViewerMediaFocus  #include "llviewerobjectlist.h" -#include "llpanelmediahud.h" +#include "llpanelprimmediacontrols.h"  #include "llpluginclassmedia.h"  #include "llagent.h"  #include "lltoolpie.h" @@ -106,19 +106,19 @@ void LLViewerMediaFocus::setFocusFace(LLPointer<LLViewerObject> objectp, S32 fac  		// We must do this before  processing the media HUD zoom, or it may zoom to the wrong face.   		update(); -		if(mMediaHUD.get() && face_auto_zoom && ! parcel->getMediaPreventCameraZoom()) +		if(mMediaControls.get() && face_auto_zoom && ! parcel->getMediaPreventCameraZoom())  		{ -			mMediaHUD.get()->resetZoomLevel(); -			mMediaHUD.get()->nextZoomLevel(); +			mMediaControls.get()->resetZoomLevel(); +			mMediaControls.get()->nextZoomLevel();  		}  	}  	else  	{  		if(mFocusedImplID != LLUUID::null)  		{ -			if(mMediaHUD.get()) +			if(mMediaControls.get())  			{ -				mMediaHUD.get()->resetZoomLevel(); +				mMediaControls.get()->resetZoomLevel();  			}  			gFocusMgr.setKeyboardFocus(NULL); @@ -327,20 +327,20 @@ void LLViewerMediaFocus::update()  		// We have an object and impl to point at.  		// Make sure the media HUD object exists. -		if(! mMediaHUD.get()) +		if(! mMediaControls.get())  		{ -			LLPanelMediaHUD* media_hud = new LLPanelMediaHUD(); -			mMediaHUD = media_hud->getHandle(); -			gHUDView->addChild(media_hud);	 +			LLPanelPrimMediaControls* media_controls = new LLPanelPrimMediaControls(); +			mMediaControls = media_controls->getHandle(); +			gHUDView->addChild(media_controls);	  		} -		mMediaHUD.get()->setMediaFace(viewer_object, face, media_impl, normal); +		mMediaControls.get()->setMediaFace(viewer_object, face, media_impl, normal);  	}  	else  	{  		// The media HUD is no longer needed. -		if(mMediaHUD.get()) +		if(mMediaControls.get())  		{ -			mMediaHUD.get()->setMediaFace(NULL, 0, NULL); +			mMediaControls.get()->setMediaFace(NULL, 0, NULL);  		}  	}  } diff --git a/indra/newview/llviewermediafocus.h b/indra/newview/llviewermediafocus.h index c77533ba5a..c1179de39d 100644 --- a/indra/newview/llviewermediafocus.h +++ b/indra/newview/llviewermediafocus.h @@ -40,7 +40,7 @@  #include "llselectmgr.h"  class LLViewerMediaImpl; -class LLPanelMediaHUD; +class LLPanelPrimMediaControls;  class LLViewerMediaFocus :   	public LLFocusableElement,  @@ -88,7 +88,7 @@ protected:  private: -	LLHandle<LLPanelMediaHUD> mMediaHUD; +	LLHandle<LLPanelPrimMediaControls> mMediaControls;  	LLUUID mFocusedObjectID;  	S32 mFocusedObjectFace; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 058f44ef57..864cf9d57b 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -3483,7 +3483,6 @@ void set_god_level(U8 god_level)  {  	U8 old_god_level = gAgent.getGodLevel();  	gAgent.setGodLevel( god_level ); -	gIMMgr->refresh();  	LLViewerParcelMgr::getInstance()->notifyObservers();  	// God mode changes sim visibility diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 791ec07349..320f0f83ff 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -72,7 +72,6 @@  #include "llviewercontrol.h"  #include "lldrawpool.h"  #include "llfirstuse.h" -#include "llfloateractivespeakers.h"  #include "llfloateranimpreview.h"  #include "llfloaterbuycurrency.h"  #include "llfloaterbuyland.h" @@ -5680,7 +5679,7 @@ void onCovenantLoadComplete(LLVFS *vfs,  	LLPanelLandCovenant::updateCovenantText(covenant_text);  	LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid); -	LLPanelPlaceInfo* panel = dynamic_cast<LLPanelPlaceInfo*>(LLSideTray::getInstance()->showPanel("panel_place_info", LLSD())); +	LLPanelPlaceInfo* panel = LLSideTray::getInstance()->findChild<LLPanelPlaceInfo>("panel_place_info");  	if (panel)  	{  		panel->updateCovenantText(covenant_text); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index aea312dd69..9e1ba3f2ef 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -143,7 +143,6 @@  #include "llstatview.h"  #include "llsurface.h"  #include "llsurfacepatch.h" -#include "llimview.h"  #include "lltexlayer.h"  #include "lltextbox.h"  #include "lltexturecache.h" diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index a402aff8ab..f9c95afc31 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -6400,6 +6400,11 @@ LLBBox LLVOAvatar::getHUDBBox() const  				 ++attachment_iter)  			{  				const LLViewerObject* attached_object = (*attachment_iter); +				if (attached_object == NULL) +				{ +					llwarns << "HUD attached object is NULL!" << llendl; +					continue; +				}  				// initialize bounding box to contain identity orientation and center point for attached object  				bbox.addPointLocal(attached_object->getPosition());  				// add rotated bounding box for attached object diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp new file mode 100644 index 0000000000..96fcf61e62 --- /dev/null +++ b/indra/newview/llvoicechannel.cpp @@ -0,0 +1,872 @@ +/**  + * @file llvoicechannel.cpp + * @brief Voice Channel related classes + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-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 "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llfloaterreg.h" +#include "llimview.h" +#include "llnotifications.h" +#include "llpanel.h" +#include "llrecentpeople.h" +#include "llviewercontrol.h" +#include "llvoicechannel.h" + + +LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap; +LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap; +LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL; +LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL; + +BOOL LLVoiceChannel::sSuspended = FALSE; + +// +// Constants +// +const U32 DEFAULT_RETRIES_COUNT = 3; + + +class LLVoiceCallCapResponder : public LLHTTPClient::Responder +{ +public: +	LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; + +	virtual void error(U32 status, const std::string& reason);	// called with bad status codes +	virtual void result(const LLSD& content); + +private: +	LLUUID mSessionID; +}; + + +void LLVoiceCallCapResponder::error(U32 status, const std::string& reason) +{ +	llwarns << "LLVoiceCallCapResponder::error(" +		<< status << ": " << reason << ")" +		<< llendl; +	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); +	if ( channelp ) +	{ +		if ( 403 == status ) +		{ +			//403 == no ability +			LLNotifications::instance().add( +				"VoiceNotAllowed", +				channelp->getNotifyArgs()); +		} +		else +		{ +			LLNotifications::instance().add( +				"VoiceCallGenericError", +				channelp->getNotifyArgs()); +		} +		channelp->deactivate(); +	} +} + +void LLVoiceCallCapResponder::result(const LLSD& content) +{ +	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); +	if (channelp) +	{ +		//*TODO: DEBUG SPAM +		LLSD::map_const_iterator iter; +		for(iter = content.beginMap(); iter != content.endMap(); ++iter) +		{ +			llinfos << "LLVoiceCallCapResponder::result got "  +				<< iter->first << llendl; +		} + +		channelp->setChannelInfo( +			content["voice_credentials"]["channel_uri"].asString(), +			content["voice_credentials"]["channel_credentials"].asString()); +	} +} + +// +// LLVoiceChannel +// +LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) :  +	mSessionID(session_id),  +	mState(STATE_NO_CHANNEL_INFO),  +	mSessionName(session_name), +	mIgnoreNextSessionLeave(FALSE) +{ +	mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName; + +	if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second) +	{ +		// a voice channel already exists for this session id, so this instance will be orphaned +		// the end result should simply be the failure to make voice calls +		llwarns << "Duplicate voice channels registered for session_id " << session_id << llendl; +	} + +	LLVoiceClient::getInstance()->addObserver(this); +} + +LLVoiceChannel::~LLVoiceChannel() +{ +	// Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed. +	if(gVoiceClient) +	{ +		gVoiceClient->removeObserver(this); +	} +	 +	sVoiceChannelMap.erase(mSessionID); +	sVoiceChannelURIMap.erase(mURI); +} + +void LLVoiceChannel::setChannelInfo( +	const std::string& uri, +	const std::string& credentials) +{ +	setURI(uri); + +	mCredentials = credentials; + +	if (mState == STATE_NO_CHANNEL_INFO) +	{ +		if (mURI.empty()) +		{ +			LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); +			llwarns << "Received empty URI for channel " << mSessionName << llendl; +			deactivate(); +		} +		else if (mCredentials.empty()) +		{ +			LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); +			llwarns << "Received empty credentials for channel " << mSessionName << llendl; +			deactivate(); +		} +		else +		{ +			setState(STATE_READY); + +			// if we are supposed to be active, reconnect +			// this will happen on initial connect, as we request credentials on first use +			if (sCurrentVoiceChannel == this) +			{ +				// just in case we got new channel info while active +				// should move over to new channel +				activate(); +			} +		} +	} +} + +void LLVoiceChannel::onChange(EStatusType type, const std::string &channelURI, bool proximal) +{ +	if (channelURI != mURI) +	{ +		return; +	} + +	if (type < BEGIN_ERROR_STATUS) +	{ +		handleStatusChange(type); +	} +	else +	{ +		handleError(type); +	} +} + +void LLVoiceChannel::handleStatusChange(EStatusType type) +{ +	// status updates +	switch(type) +	{ +	case STATUS_LOGIN_RETRY: +		//mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle(); +		LLNotifications::instance().add("VoiceLoginRetry"); +		break; +	case STATUS_LOGGED_IN: +		//if (!mLoginNotificationHandle.isDead()) +		//{ +		//	LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get(); +		//	if (notifyp) +		//	{ +		//		notifyp->close(); +		//	} +		//	mLoginNotificationHandle.markDead(); +		//} +		break; +	case STATUS_LEFT_CHANNEL: +		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) +		{ +			// if forceably removed from channel +			// update the UI and revert to default channel +			LLNotifications::instance().add("VoiceChannelDisconnected", mNotifyArgs); +			deactivate(); +		} +		mIgnoreNextSessionLeave = FALSE; +		break; +	case STATUS_JOINING: +		if (callStarted()) +		{ +			setState(STATE_RINGING); +		} +		break; +	case STATUS_JOINED: +		if (callStarted()) +		{ +			setState(STATE_CONNECTED); +		} +	default: +		break; +	} +} + +// default behavior is to just deactivate channel +// derived classes provide specific error messages +void LLVoiceChannel::handleError(EStatusType type) +{ +	deactivate(); +	setState(STATE_ERROR); +} + +BOOL LLVoiceChannel::isActive() +{  +	// only considered active when currently bound channel matches what our channel +	return callStarted() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI;  +} + +BOOL LLVoiceChannel::callStarted() +{ +	return mState >= STATE_CALL_STARTED; +} + +void LLVoiceChannel::deactivate() +{ +	if (mState >= STATE_RINGING) +	{ +		// ignore session leave event +		mIgnoreNextSessionLeave = TRUE; +	} + +	if (callStarted()) +	{ +		setState(STATE_HUNG_UP); +		// mute the microphone if required when returning to the proximal channel +		if (gSavedSettings.getBOOL("AutoDisengageMic") && sCurrentVoiceChannel == this) +		{ +			gSavedSettings.setBOOL("PTTCurrentlyEnabled", true); +		} +	} + +	if (sCurrentVoiceChannel == this) +	{ +		// default channel is proximal channel +		sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); +		sCurrentVoiceChannel->activate(); +	} +} + +void LLVoiceChannel::activate() +{ +	if (callStarted()) +	{ +		return; +	} + +	// deactivate old channel and mark ourselves as the active one +	if (sCurrentVoiceChannel != this) +	{ +		// mark as current before deactivating the old channel to prevent +		// activating the proximal channel between IM calls +		LLVoiceChannel* old_channel = sCurrentVoiceChannel; +		sCurrentVoiceChannel = this; +		if (old_channel) +		{ +			old_channel->deactivate(); +		} +	} + +	if (mState == STATE_NO_CHANNEL_INFO) +	{ +		// responsible for setting status to active +		getChannelInfo(); +	} +	else +	{ +		setState(STATE_CALL_STARTED); +	} +} + +void LLVoiceChannel::getChannelInfo() +{ +	// pretend we have everything we need +	if (sCurrentVoiceChannel == this) +	{ +		setState(STATE_CALL_STARTED); +	} +} + +//static  +LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id) +{ +	voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id); +	if (found_it == sVoiceChannelMap.end()) +	{ +		return NULL; +	} +	else +	{ +		return found_it->second; +	} +} + +//static  +LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri) +{ +	voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri); +	if (found_it == sVoiceChannelURIMap.end()) +	{ +		return NULL; +	} +	else +	{ +		return found_it->second; +	} +} + +void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id) +{ +	sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID)); +	mSessionID = new_session_id; +	sVoiceChannelMap.insert(std::make_pair(mSessionID, this)); +} + +void LLVoiceChannel::setURI(std::string uri) +{ +	sVoiceChannelURIMap.erase(mURI); +	mURI = uri; +	sVoiceChannelURIMap.insert(std::make_pair(mURI, this)); +} + +void LLVoiceChannel::setState(EState state) +{ +	switch(state) +	{ +	case STATE_RINGING: +		gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs); +		break; +	case STATE_CONNECTED: +		gIMMgr->addSystemMessage(mSessionID, "connected", mNotifyArgs); +		break; +	case STATE_HUNG_UP: +		gIMMgr->addSystemMessage(mSessionID, "hang_up", mNotifyArgs); +		break; +	default: +		break; +	} + +	mState = state; +} + +void LLVoiceChannel::toggleCallWindowIfNeeded(EState state) +{ +	if (state == STATE_CONNECTED) +	{ +		LLFloaterReg::showInstance("voice_call", mSessionID); +	} +	// By checking that current state is CONNECTED we make sure that the call window +	// has been shown, hence there's something to hide. This helps when user presses +	// the "End call" button right after initiating the call. +	// *TODO: move this check to LLFloaterCall? +	else if (state == STATE_HUNG_UP && mState == STATE_CONNECTED) +	{ +		LLFloaterReg::hideInstance("voice_call", mSessionID); +	} +} + +//static +void LLVoiceChannel::initClass() +{ +	sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); +} + + +//static  +void LLVoiceChannel::suspend() +{ +	if (!sSuspended) +	{ +		sSuspendedVoiceChannel = sCurrentVoiceChannel; +		sSuspended = TRUE; +	} +} + +//static  +void LLVoiceChannel::resume() +{ +	if (sSuspended) +	{ +		if (gVoiceClient->voiceEnabled()) +		{ +			if (sSuspendedVoiceChannel) +			{ +				sSuspendedVoiceChannel->activate(); +			} +			else +			{ +				LLVoiceChannelProximal::getInstance()->activate(); +			} +		} +		sSuspended = FALSE; +	} +} + + +// +// LLVoiceChannelGroup +// + +LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) :  +	LLVoiceChannel(session_id, session_name) +{ +	mRetries = DEFAULT_RETRIES_COUNT; +	mIsRetrying = FALSE; +} + +void LLVoiceChannelGroup::deactivate() +{ +	if (callStarted()) +	{ +		LLVoiceClient::getInstance()->leaveNonSpatialChannel(); +	} +	LLVoiceChannel::deactivate(); +} + +void LLVoiceChannelGroup::activate() +{ +	if (callStarted()) return; + +	LLVoiceChannel::activate(); + +	if (callStarted()) +	{ +		// we have the channel info, just need to use it now +		LLVoiceClient::getInstance()->setNonSpatialChannel( +			mURI, +			mCredentials); + +#if 0 // *TODO +		if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel +		{ +			// Add the party to the list of people with which we've recently interacted. +			for (/*people in the chat*/) +				LLRecentPeople::instance().add(buddy_id); +		} +#endif +	} +} + +void LLVoiceChannelGroup::getChannelInfo() +{ +	LLViewerRegion* region = gAgent.getRegion(); +	if (region) +	{ +		std::string url = region->getCapability("ChatSessionRequest"); +		LLSD data; +		data["method"] = "call"; +		data["session-id"] = mSessionID; +		LLHTTPClient::post(url, +						   data, +						   new LLVoiceCallCapResponder(mSessionID)); +	} +} + +void LLVoiceChannelGroup::setChannelInfo( +	const std::string& uri, +	const std::string& credentials) +{ +	setURI(uri); + +	mCredentials = credentials; + +	if (mState == STATE_NO_CHANNEL_INFO) +	{ +		if(!mURI.empty() && !mCredentials.empty()) +		{ +			setState(STATE_READY); + +			// if we are supposed to be active, reconnect +			// this will happen on initial connect, as we request credentials on first use +			if (sCurrentVoiceChannel == this) +			{ +				// just in case we got new channel info while active +				// should move over to new channel +				activate(); +			} +		} +		else +		{ +			//*TODO: notify user +			llwarns << "Received invalid credentials for channel " << mSessionName << llendl; +			deactivate(); +		} +	} +	else if ( mIsRetrying ) +	{ +		// we have the channel info, just need to use it now +		LLVoiceClient::getInstance()->setNonSpatialChannel( +			mURI, +			mCredentials); +	} +} + +void LLVoiceChannelGroup::handleStatusChange(EStatusType type) +{ +	// status updates +	switch(type) +	{ +	case STATUS_JOINED: +		mRetries = 3; +		mIsRetrying = FALSE; +	default: +		break; +	} + +	LLVoiceChannel::handleStatusChange(type); +} + +void LLVoiceChannelGroup::handleError(EStatusType status) +{ +	std::string notify; +	switch(status) +	{ +	case ERROR_CHANNEL_LOCKED: +	case ERROR_CHANNEL_FULL: +		notify = "VoiceChannelFull"; +		break; +	case ERROR_NOT_AVAILABLE: +		//clear URI and credentials +		//set the state to be no info +		//and activate +		if ( mRetries > 0 ) +		{ +			mRetries--; +			mIsRetrying = TRUE; +			mIgnoreNextSessionLeave = TRUE; + +			getChannelInfo(); +			return; +		} +		else +		{ +			notify = "VoiceChannelJoinFailed"; +			mRetries = DEFAULT_RETRIES_COUNT; +			mIsRetrying = FALSE; +		} + +		break; + +	case ERROR_UNKNOWN: +	default: +		break; +	} + +	// notification +	if (!notify.empty()) +	{ +		LLNotificationPtr notification = LLNotifications::instance().add(notify, mNotifyArgs); +		// echo to im window +		gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage()); +	} + +	LLVoiceChannel::handleError(status); +} + +void LLVoiceChannelGroup::setState(EState state) +{ +	// HACK: Open/close the call window if needed. +	toggleCallWindowIfNeeded(state); + +	switch(state) +	{ +	case STATE_RINGING: +		if ( !mIsRetrying ) +		{ +			gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs); +		} + +		mState = state; +		break; +	default: +		LLVoiceChannel::setState(state); +	} +} + +// +// LLVoiceChannelProximal +// +LLVoiceChannelProximal::LLVoiceChannelProximal() :  +	LLVoiceChannel(LLUUID::null, LLStringUtil::null) +{ +	activate(); +} + +BOOL LLVoiceChannelProximal::isActive() +{ +	return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();  +} + +void LLVoiceChannelProximal::activate() +{ +	if (callStarted()) return; + +	LLVoiceChannel::activate(); + +	if (callStarted()) +	{ +		// this implicitly puts you back in the spatial channel +		LLVoiceClient::getInstance()->leaveNonSpatialChannel(); +	} +} + +void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal) +{ +	if (!proximal) +	{ +		return; +	} + +	if (type < BEGIN_ERROR_STATUS) +	{ +		handleStatusChange(type); +	} +	else +	{ +		handleError(type); +	} +} + +void LLVoiceChannelProximal::handleStatusChange(EStatusType status) +{ +	// status updates +	switch(status) +	{ +	case STATUS_LEFT_CHANNEL: +		// do not notify user when leaving proximal channel +		return; +	case STATUS_VOICE_DISABLED: +		 gIMMgr->addSystemMessage(LLUUID::null, "unavailable", mNotifyArgs); +		return; +	default: +		break; +	} +	LLVoiceChannel::handleStatusChange(status); +} + + +void LLVoiceChannelProximal::handleError(EStatusType status) +{ +	std::string notify; +	switch(status) +	{ +	  case ERROR_CHANNEL_LOCKED: +	  case ERROR_CHANNEL_FULL: +		notify = "ProximalVoiceChannelFull"; +		break; +	  default: +		 break; +	} + +	// notification +	if (!notify.empty()) +	{ +		LLNotifications::instance().add(notify, mNotifyArgs); +	} + +	LLVoiceChannel::handleError(status); +} + +void LLVoiceChannelProximal::deactivate() +{ +	if (callStarted()) +	{ +		setState(STATE_HUNG_UP); +	} +} + + +// +// LLVoiceChannelP2P +// +LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id) :  +		LLVoiceChannelGroup(session_id, session_name),  +		mOtherUserID(other_user_id), +		mReceivedCall(FALSE) +{ +	// make sure URI reflects encoded version of other user's agent id +	setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id)); +} + +void LLVoiceChannelP2P::handleStatusChange(EStatusType type) +{ +	// status updates +	switch(type) +	{ +	case STATUS_LEFT_CHANNEL: +		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) +		{ +			if (mState == STATE_RINGING) +			{ +				// other user declined call +				LLNotifications::instance().add("P2PCallDeclined", mNotifyArgs); +			} +			else +			{ +				// other user hung up +				LLNotifications::instance().add("VoiceChannelDisconnectedP2P", mNotifyArgs); +			} +			deactivate(); +		} +		mIgnoreNextSessionLeave = FALSE; +		return; +	default: +		break; +	} + +	LLVoiceChannel::handleStatusChange(type); +} + +void LLVoiceChannelP2P::handleError(EStatusType type) +{ +	switch(type) +	{ +	case ERROR_NOT_AVAILABLE: +		LLNotifications::instance().add("P2PCallNoAnswer", mNotifyArgs); +		break; +	default: +		break; +	} + +	LLVoiceChannel::handleError(type); +} + +void LLVoiceChannelP2P::activate() +{ +	if (callStarted()) return; + +	LLVoiceChannel::activate(); + +	if (callStarted()) +	{ +		// no session handle yet, we're starting the call +		if (mSessionHandle.empty()) +		{ +			mReceivedCall = FALSE; +			LLVoiceClient::getInstance()->callUser(mOtherUserID); +		} +		// otherwise answering the call +		else +		{ +			LLVoiceClient::getInstance()->answerInvite(mSessionHandle); +			 +			// using the session handle invalidates it.  Clear it out here so we can't reuse it by accident. +			mSessionHandle.clear(); +		} + +		// Add the party to the list of people with which we've recently interacted. +		LLRecentPeople::instance().add(mOtherUserID); +	} +} + +void LLVoiceChannelP2P::getChannelInfo() +{ +	// pretend we have everything we need, since P2P doesn't use channel info +	if (sCurrentVoiceChannel == this) +	{ +		setState(STATE_CALL_STARTED); +	} +} + +// receiving session from other user who initiated call +void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::string &inURI) +{  +	BOOL needs_activate = FALSE; +	if (callStarted()) +	{ +		// defer to lower agent id when already active +		if (mOtherUserID < gAgent.getID()) +		{ +			// pretend we haven't started the call yet, so we can connect to this session instead +			deactivate(); +			needs_activate = TRUE; +		} +		else +		{ +			// we are active and have priority, invite the other user again +			// under the assumption they will join this new session +			mSessionHandle.clear(); +			LLVoiceClient::getInstance()->callUser(mOtherUserID); +			return; +		} +	} + +	mSessionHandle = handle; + +	// The URI of a p2p session should always be the other end's SIP URI. +	if(!inURI.empty()) +	{ +		setURI(inURI); +	} +	else +	{ +		setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID)); +	} +	 +	mReceivedCall = TRUE; + +	if (needs_activate) +	{ +		activate(); +	} +} + +void LLVoiceChannelP2P::setState(EState state) +{ +	// HACK: Open/close the call window if needed. +	toggleCallWindowIfNeeded(state); + +	// you only "answer" voice invites in p2p mode +	// so provide a special purpose message here +	if (mReceivedCall && state == STATE_RINGING) +	{ +		gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs); +		mState = state; +		return; +	} +	LLVoiceChannel::setState(state); +} diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h new file mode 100644 index 0000000000..9966bdd5ab --- /dev/null +++ b/indra/newview/llvoicechannel.h @@ -0,0 +1,168 @@ +/**  + * @file llvoicechannel.h + * @brief Voice channel related classes + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-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_VOICECHANNEL_H +#define LL_VOICECHANNEL_H + +#include "llhandle.h" +#include "llvoiceclient.h" + +class LLPanel; + +class LLVoiceChannel : public LLVoiceClientStatusObserver +{ +public: +	typedef enum e_voice_channel_state +	{ +		STATE_NO_CHANNEL_INFO, +		STATE_ERROR, +		STATE_HUNG_UP, +		STATE_READY, +		STATE_CALL_STARTED, +		STATE_RINGING, +		STATE_CONNECTED +	} EState; + +	LLVoiceChannel(const LLUUID& session_id, const std::string& session_name); +	virtual ~LLVoiceChannel(); + +	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + +	virtual void handleStatusChange(EStatusType status); +	virtual void handleError(EStatusType status); +	virtual void deactivate(); +	virtual void activate(); +	virtual void setChannelInfo( +		const std::string& uri, +		const std::string& credentials); +	virtual void getChannelInfo(); +	virtual BOOL isActive(); +	virtual BOOL callStarted(); +	const std::string& getSessionName() const { return mSessionName; } + +	const LLUUID getSessionID() { return mSessionID; } +	EState getState() { return mState; } + +	void updateSessionID(const LLUUID& new_session_id); +	const LLSD& getNotifyArgs() { return mNotifyArgs; } + +	static LLVoiceChannel* getChannelByID(const LLUUID& session_id); +	static LLVoiceChannel* getChannelByURI(std::string uri); +	static LLVoiceChannel* getCurrentVoiceChannel() { return sCurrentVoiceChannel; } +	static void initClass(); +	 +	static void suspend(); +	static void resume(); + +protected: +	virtual void setState(EState state); +	void toggleCallWindowIfNeeded(EState state); +	void setURI(std::string uri); + +	std::string	mURI; +	std::string	mCredentials; +	LLUUID		mSessionID; +	EState		mState; +	std::string	mSessionName; +	LLSD mNotifyArgs; +	BOOL		mIgnoreNextSessionLeave; +	LLHandle<LLPanel> mLoginNotificationHandle; + +	typedef std::map<LLUUID, LLVoiceChannel*> voice_channel_map_t; +	static voice_channel_map_t sVoiceChannelMap; + +	typedef std::map<std::string, LLVoiceChannel*> voice_channel_map_uri_t; +	static voice_channel_map_uri_t sVoiceChannelURIMap; + +	static LLVoiceChannel* sCurrentVoiceChannel; +	static LLVoiceChannel* sSuspendedVoiceChannel; +	static BOOL sSuspended; +}; + +class LLVoiceChannelGroup : public LLVoiceChannel +{ +public: +	LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name); + +	/*virtual*/ void handleStatusChange(EStatusType status); +	/*virtual*/ void handleError(EStatusType status); +	/*virtual*/ void activate(); +	/*virtual*/ void deactivate(); +	/*vritual*/ void setChannelInfo( +		const std::string& uri, +		const std::string& credentials); +	/*virtual*/ void getChannelInfo(); + +protected: +	virtual void setState(EState state); + +private: +	U32 mRetries; +	BOOL mIsRetrying; +}; + +class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoiceChannelProximal> +{ +public: +	LLVoiceChannelProximal(); + +	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); +	/*virtual*/ void handleStatusChange(EStatusType status); +	/*virtual*/ void handleError(EStatusType status); +	/*virtual*/ BOOL isActive(); +	/*virtual*/ void activate(); +	/*virtual*/ void deactivate(); + +}; + +class LLVoiceChannelP2P : public LLVoiceChannelGroup +{ +public: +	LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id); + +	/*virtual*/ void handleStatusChange(EStatusType status); +	/*virtual*/ void handleError(EStatusType status); +    /*virtual*/ void activate(); +	/*virtual*/ void getChannelInfo(); + +	void setSessionHandle(const std::string& handle, const std::string &inURI); + +protected: +	virtual void setState(EState state); + +private: +	std::string	mSessionHandle; +	LLUUID		mOtherUserID; +	BOOL		mReceivedCall; +}; + +#endif  // LL_VOICECHANNEL_H diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 02f63a848b..2834284a9b 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -57,13 +57,13 @@  #include "llagent.h"  #include "llcachename.h"  #include "llimview.h" // for LLIMMgr -#include "llimpanel.h" // for LLVoiceChannel  #include "llparcel.h"  #include "llviewerparcelmgr.h"  #include "llfirstuse.h"  #include "llviewerwindow.h"  #include "llviewercamera.h"  #include "llvoavatarself.h" +#include "llvoicechannel.h"  #include "llfloaterfriends.h"  //VIVOX, inorder to refresh communicate panel  #include "llfloaterchat.h"		// for LLFloaterChat::addChat() diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index 8f74ea29ac..a091028ec2 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -545,7 +545,7 @@ BOOL LLWearable::isDirty() const  				else  				{  					// image found in current image list but not saved image list -					return FALSE; +					return TRUE;  				}  			}  		} diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index b46b766fc0..d3366cdcaa 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -144,6 +144,7 @@    <texture name="Info" file_name="icons/Info.png" preload="false" />    <texture name="Info_Small" file_name="icons/Info_Small.png" preload="false" />    <texture name="Info_Off" file_name="navbar/Info_Off.png" preload="false" /> +  <texture name="Info_Over" file_name="icons/Info_Over.png" preload="false" />    <texture name="Info_Press" file_name="navbar/Info_Press.png" preload="false" />    <texture name="Inspector_Background" file_name="windows/Inspector_Background.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index b194b533af..5cd11ba292 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -7,66 +7,56 @@   save_rect="true"   title="About [APP_NAME]"   width="470"> -    <floater.string -     name="you_are_at"> -        You are at [POSITION] -    </floater.string> -    <floater.string -     name="in_region"> -        in [REGION] located at -    </floater.string> -    <floater.string -     name="CPU"> -        CPU: -    </floater.string> -    <floater.string -     name="Memory"> -        Memory: [MEM] MB -    </floater.string> -    <floater.string -     name="OSVersion"> -        OS Version: -    </floater.string> -    <floater.string -     name="GraphicsCardVendor"> -        Graphics Card Vendor: -    </floater.string> -    <floater.string -     name="GraphicsCard"> -        Graphics Card: -    </floater.string> -    <floater.string -     name="OpenGLVersion"> -        OpenGL Version: -    </floater.string> -    <floater.string -     name="LibCurlVersion"> -        libcurl Version: -    </floater.string> -    <floater.string -     name="J2CDecoderVersion"> -        J2C Decoder Version: -    </floater.string> -    <floater.string -     name="AudioDriverVersion"> -        Audio Driver Version: -    </floater.string> -    <floater.string -     name="none"> -        (none) -    </floater.string> -    <floater.string -     name="LLMozLibVersion"> -        LLMozLib Version: -    </floater.string>    <floater.string -     name="LLQtWebkitVersion"> -        Qt Webkit Version: 4.5.2 +     name="AboutHeader"> +[APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2] ([VIEWER_VERSION_3]) [BUILD_DATE] [BUILD_TIME] ([CHANNEL]) +[[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]] + +</floater.string> +  <floater.string +     name="AboutCompiler"> +Built with [COMPILER] version [COMPILER_VERSION] + +</floater.string> +  <floater.string +     name="AboutPosition"> +You are at [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1] in [REGION] located at [HOSTNAME] ([HOSTIP]) +[SERVER_VERSION] +[[SERVER_RELEASE_NOTES_URL] [ReleaseNotes]] + +</floater.string> +  <!-- *NOTE: Do not translate text like GPU, Graphics Card, etc - +       Most PC users who know what these mean will be used to the English versions, +       and this info sometimes gets sent to support. --> +  <floater.string +     name="AboutSystem"> +CPU: [CPU] +Memory: [MEMORY_MB] MB +OS Version: [OS_VERSION] +Graphics Card Vendor: [GRAPHICS_CARD_VENDOR] +Graphics Card: [GRAPHICS_CARD] +</floater.string> +  <floater.string +     name="AboutDriver"> +Windows Graphics Driver Version: [GRAPHICS_DRIVER_VERSION] +</floater.string> +  <floater.string +     name="AboutLibs"> +OpenGL Version: [OPENGL_VERSION] + +libcurl Version: [LIBCURL_VERSION] +J2C Decoder Version: [J2C_VERSION] +Audio Driver Version: [AUDIO_DRIVER_VERSION] +Qt Webkit Version: [QT_WEBKIT_VERSION] +</floater.string> +  <floater.string +     name="none"> +      (none)    </floater.string>    <floater.string -     name="PacketsLost"> -        Packets Lost: [LOST]/[IN] ([PCT]%) -    </floater.string> +     name="AboutTraffic"> +Packets Lost: [PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number,1]%) +</floater.string>    <tab_container      follows="all"       top="25" diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index 072fafd06e..aa0b4094b4 100644 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -28,7 +28,9 @@       follows="left|top|right|bottom"       height="400"       layout="topleft" +     font="SansSerifSmall"       left="1" +       tab_padding_right="5"       name="landtab"       tab_position="top"       top="20" diff --git a/indra/newview/skins/default/xui/en/floater_camera.xml b/indra/newview/skins/default/xui/en/floater_camera.xml index 520249c2a2..a713cc32a0 100644 --- a/indra/newview/skins/default/xui/en/floater_camera.xml +++ b/indra/newview/skins/default/xui/en/floater_camera.xml @@ -1,17 +1,17 @@  <?xml version="1.0" encoding="utf-8" standalone="yes" ?>  <floater   can_dock="true" - can_minimize="true" - can_close="true"  + can_minimize="false" + can_close="true"   center_horiz="true" - follows="top" - height="110" + follows="bottom" + height="152"   layout="topleft"   name="camera_floater"   help_topic="camera_floater"   save_rect="true"   save_visibility="true" - width="105"> + width="150">      <floater.string       name="rotate_tooltip">          Rotate Camera Around Focus @@ -25,69 +25,71 @@          Move Camera Up and Down, Left and Right      </floater.string>      <panel -     border="true" -     height="79" +     border="false" +     height="110"       layout="topleft" -     left="0" +     left="2"       top="0" -     mouse_opaque="false"  +     mouse_opaque="false"       name="controls" -     width="105"> -        <joystick_rotate -         follows="top|left" -         height="64" -         image_selected="cam_rotate_in.tga" -         image_unselected="cam_rotate_out.tga" -         layout="topleft" -         left="2" -         name="cam_rotate_stick" -         picture_style="true" -         quadrant="left" -         scale_image="false" -         sound_flags="3" -         tool_tip="Orbit camera around focus" -         top="15" -         width="64" /> +     width="148">          <joystick_track           follows="top|left" -         height="64" -         image_selected="cam_tracking_in.tga" -         image_unselected="cam_tracking_out.tga" +         height="78" +         image_selected="Cam_Tracking_In" +         image_unselected="Cam_Tracking_Out"           layout="topleft" -         left="2" +         left="45"           name="cam_track_stick"           picture_style="true"           quadrant="left"           scale_image="false"           sound_flags="3"           tool_tip="Move camera up and down, left and right" -         top="15" +         top="22"           visible="false" -         width="64" /> +         width="78" /> +         <!--TODO: replace with slider, + - images -->          <joystick_zoom           follows="top|left" -         height="64" -         image_unselected="cam_zoom_out.tga" +         height="78" +         image_unselected="ScrollThumb_Vert"           layout="topleft" -         left_delta="70" -         minus_image="cam_zoom_minus_in.tga" +         left="7" +         minus_image="ScrollThumb_Vert"           name="zoom"           picture_style="true" -         plus_image="cam_zoom_plus_in.tga" +         plus_image="ScrollThumb_Vert"           quadrant="left"           scale_image="false"           sound_flags="3"           tool_tip="Zoom camera toward focus" -         top_delta="0" -         width="16" /> +         top="22" +         width="20" /> +         <joystick_rotate +         follows="top|left" +         height="78" +         image_selected="Cam_Rotate_In" +         image_unselected="Cam_Rotate_Out" +         layout="topleft" +         left="45" +         name="cam_rotate_stick" +         picture_style="true" +         quadrant="left" +         scale_image="false" +         sound_flags="3" +         visible="true" +         tool_tip="Orbit camera around focus" +         top="22" +         width="78" />          <panel -         height="70" +         height="78"           layout="topleft" -         left="15" +         left="36"           name="camera_presets" -         top="15" +         top="30"           visible="false" -         width="75"> +         width="78">              <button               height="30"               image_selected="CameraPreset_Rear" @@ -127,7 +129,7 @@               name="front_view"               picture_style="true"               tool_tip="Front View" -             top_pad="2" +             top_pad="5"               width="30">                  <click_callback                   function="CameraPresets.ChangeView" @@ -151,21 +153,21 @@          </panel>      </panel>      <panel -     border="true" -     height="25" +     border="false" +     height="42"       layout="topleft" -     left="0" -     top_pad="1" +     left="2" +     top_pad="0"       name="buttons" -     width="105"> +     width="148">          <button           height="23"           label=""           layout="topleft" -         left="2" +         left="23"           is_toggle="true"           image_overlay="Cam_Orbit_Off" -         image_selected="PushButton_Selected_Press"  +         image_selected="PushButton_Selected_Press"           name="orbit_btn"           tab_stop="false"           tool_tip="Orbit camera" @@ -179,7 +181,7 @@           left_pad="0"           is_toggle="true"           image_overlay="Cam_Pan_Off" -         image_selected="PushButton_Selected_Press"  +         image_selected="PushButton_Selected_Press"           name="pan_btn"           tab_stop="false"           tool_tip="Pan camera" @@ -191,7 +193,7 @@           layout="topleft"           left_pad="0"           image_overlay="Cam_Avatar_Off" -         image_selected="PushButton_Selected_Press"  +         image_selected="PushButton_Selected_Press"           name="avatarview_btn"           tab_stop="false"           tool_tip="See as avatar" @@ -204,12 +206,11 @@           left_pad="0"           is_toggle="true"           image_overlay="Cam_FreeCam_Off" -         image_selected="PushButton_Selected_Press"  +         image_selected="PushButton_Selected_Press"           name="freecamera_btn"           tab_stop="false"           tool_tip="View object"           width="25">          </button> -              </panel>  </floater> diff --git a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml index 0bd4b441c6..d24d1b7064 100644 --- a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml +++ b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml @@ -14,7 +14,7 @@   save_rect="true"   title="Nearby Chat"   save_visibility="true" - single_instance="true"  + single_instance="true"   width="320">              <chat_history               allow_html="true"  diff --git a/indra/newview/skins/default/xui/en/floater_pay.xml b/indra/newview/skins/default/xui/en/floater_pay.xml index 5f70f09a34..69525d48d2 100644 --- a/indra/newview/skins/default/xui/en/floater_pay.xml +++ b/indra/newview/skins/default/xui/en/floater_pay.xml @@ -34,7 +34,7 @@       type="string"       length="1"       follows="left|top" -     font="SansSerif" +     font="SansSerifSmall"       height="16"       layout="topleft"       left_pad="7" @@ -44,6 +44,7 @@      </text>      <button       height="23" +     font="SansSerifSmall"         label="L$1"       label_selected="L$1"       layout="topleft" @@ -53,7 +54,8 @@       width="80" />      <button       height="23" -     label="L$5" +     label="L$1" +     font="SansSerif"         label_selected="L$5"       layout="topleft"       left_pad="15" @@ -62,6 +64,7 @@      <button       height="23"       label="L$10" +     font="SansSerifHuge"         label_selected="L$10"       layout="topleft"       left="25" diff --git a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml index 8cdafe110a..d2b8455eab 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml @@ -83,7 +83,7 @@          Loading...      </text_editor>      <button -     follows="left|bottom" +     follows="right|bottom"       height="22"       label="Save"       label_selected="Save" diff --git a/indra/newview/skins/default/xui/en/floater_report_abuse.xml b/indra/newview/skins/default/xui/en/floater_report_abuse.xml index abde4ba5fa..884532c7a3 100644 --- a/indra/newview/skins/default/xui/en/floater_report_abuse.xml +++ b/indra/newview/skins/default/xui/en/floater_report_abuse.xml @@ -14,19 +14,19 @@       allow_no_texture="true"       default_image_name="None"       follows="left|top" -     height="125" +     height="150"       layout="topleft" -     left="10" -     name="screenshot" -     top="23" -     width="160" /> +     left="60" +     name="" +     top="15" +     width="220" />      <check_box       height="15"       label="Use this screenshot"       layout="topleft" -     left_pad="5" +     left="8"       name="screen_check" -     top="120" +     top_pad="-12"       width="116" />      <text       type="string" @@ -38,8 +38,8 @@       layout="topleft"       left="10"       name="reporter_title" -     top="140" -     width="60"> +     top_pad="0" +     width="100">          Reporter:      </text>      <text @@ -48,24 +48,25 @@       follows="left|top"       height="16"       layout="topleft" -     left_pad="10" +     left_pad="5"       name="reporter_field"       top_delta="0" -     width="193"> -        Loremipsum Dolorsitamut +     use_ellipses="true" +     width="200"> +        Loremipsum Dolorsitamut Longnamez      </text>      <text       type="string"       length="1"       follows="left|top"       height="16" -     font.name="SansSerif"  +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left="10"       name="sim_title" -     top_pad="5" -     width="60"> +     top_pad="2" +     width="100">          Region:      </text>      <text @@ -74,10 +75,11 @@       follows="left|top"       height="16"       layout="topleft" -     left_pad="2" +     left_pad="5"       name="sim_field"       top_delta="0" -     width="193"> +     use_ellipses="true" +     width="200">          Region Name      </text>      <text @@ -85,13 +87,13 @@       length="1"       follows="left|top"       height="16" -     font.name="SansSerif"  +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left="10"       name="pos_title" -     top_pad="5" -     width="50"> +     top_pad="2" +     width="100">          Position:      </text>      <text @@ -100,10 +102,10 @@       follows="left|top"       height="16"       layout="topleft" -     left_pad="12" +     left_pad="5"       name="pos_field"       top_delta="0" -     width="193"> +     width="200">          {128.1, 128.1, 15.4}      </text>   <text @@ -114,7 +116,7 @@       layout="topleft"       left="10"       name="select_object_label" -     top_pad="5" +     top_pad="2"       width="310">          Click the button, then the abusive object:      </text> @@ -133,13 +135,13 @@       length="1"       follows="left|top"       height="16" -     font.name="SansSerif"  +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left="48"       name="object_name_label"       top_delta="0" -     width="60"> +     width="80">          Object:      </text>      <text @@ -151,7 +153,8 @@       left_pad="6"       name="object_name"       top_delta="0" -     width="157"> +     use_ellipses="true" +     width="185">          Consetetur Sadipscing      </text>      <text @@ -159,13 +162,13 @@       length="1"       follows="left|top"       height="16" -     font.name="SansSerif"  +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left="48"       name="owner_name_label"       top_pad="0" -     width="60"> +     width="80">          Owner:      </text>      <text @@ -177,8 +180,9 @@       left_pad="6"       name="owner_name"       top_delta="0" -     width="157"> -        Hendrerit Vulputate +     use_ellipses="true" +     width="185"> +        Hendrerit Vulputate Kamawashi Longname      </text>      <combo_box       height="23" @@ -349,8 +353,8 @@       type="string"       length="1"       follows="left|top" -     height="16" -     font.name="SansSerif"  +     height="14" +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left_delta="0" @@ -368,11 +372,10 @@       left_delta="0"       max_length="32"       name="abuser_name_edit" -     top_pad="2" +     top_pad="0"       width="195" />      <button       height="23" -     font="SansSerifSmall"       label="Choose"       layout="topleft"       left_pad="5" @@ -394,13 +397,13 @@       type="string"       length="1"       follows="left|top" -     height="16" -     font.name="SansSerif"  +     height="14" +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left="10"       name="abuser_name_title2" -     top_pad="5" +     top_pad="2"       width="313">          Location of Abuse:      </text> @@ -413,19 +416,19 @@       left="10"       max_length="256"       name="abuse_location_edit" -     top_pad="2" +     top_pad="0"       width="313" />      <text       type="string"       length="1"       follows="left|top"       height="16" -     font.name="SansSerif"  +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left_delta="0"       name="sum_title" -     top_pad="5" +     top_pad="2"       width="313">          Summary:      </text> @@ -438,14 +441,14 @@       left_delta="0"       max_length="64"       name="summary_edit" -     top_pad="2" +     top_pad="0"       width="313" />      <text       type="string"       length="1"       follows="left|top" -     height="16" -     font.name="SansSerif"  +     height="14" +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left_delta="0" @@ -461,9 +464,9 @@       height="16"       layout="topleft"       name="bug_aviso" -     left_pad="0" +     left_pad="10"       width="200"> -        Please be as specific as possible. +        Please be as specific as possible      </text>      <text_editor       follows="left|top" @@ -479,16 +482,15 @@       type="string"       length="1"       follows="left|top" -     height="50" +     height="30"       layout="topleft"       left="10" -     font.name="SansSerif"  -     font.style="BOLD" +     font.name="SansSerifSmall"       name="incomplete_title" -     top_pad="5" +     top_pad="2"       word_wrap="true"       width="313"> -        Note: Incomplete reports won't be investigated. +        * Incomplete reports won't be investigated      </text>       <button       left="80" diff --git a/indra/newview/skins/default/xui/en/floater_test_textbox.xml b/indra/newview/skins/default/xui/en/floater_test_textbox.xml index 8305452c85..c33ab8aa70 100644 --- a/indra/newview/skins/default/xui/en/floater_test_textbox.xml +++ b/indra/newview/skins/default/xui/en/floater_test_textbox.xml @@ -114,16 +114,59 @@          Escaped greater than >      </text>      <text -     type="string" -     length="1" -     bottom="390" -     label="N" -     layout="topleft" -     left="10" -     name="floater_map_north" -     right="30" -     text_color="1 1 1 0.7" -     top="370"> -        N -    </text> +   type="string" +   length="1" +   bottom="390" +   label="N" +   layout="topleft" +   left="10" +   name="right_aligned_text" +   width="380" +   halign="right"  +   text_color="1 1 1 0.7" +   top_pad="10"> +    Right aligned text +  </text> +  <text + type="string" + length="1" + bottom="390" + label="N" + layout="topleft" + left="10" + name="centered_text" + width="380" + halign="center" + text_color="1 1 1 0.7" + top_pad="10"> +    Centered text +  </text> +  <text + type="string" + length="1" + bottom="390" + label="N" + layout="topleft" + left="10" + name="centered_text" + width="380" + halign="left" + text_color="1 1 1 0.7" + top_pad="10"> +    Left aligned text +  </text> +  <text +   type="string" +   length="1" +   bottom="390" +   label="N" +   layout="topleft" +   left="10" +   name="floater_map_north" +   right="30" +   text_color="1 1 1 0.7" +   top="370"> +    N +  </text> +  </floater> diff --git a/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml index cc17e9dd4b..eedb4383bb 100644 --- a/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml +++ b/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml @@ -23,9 +23,14 @@         parameter="sort_status" />    </menu_item_check>    <menu_item_separator layout="topleft" /> -  <menu_item_call name="view_icons" label="View People Icons"> -    <menu_item_call.on_click function="People.Friends.ViewSort.Action" userdata="view_icons" /> -  </menu_item_call> +  <menu_item_check name="view_icons" label="View People Icons"> +    <menu_item_check.on_click +     function="People.Friends.ViewSort.Action" +     parameter="view_icons" /> +    <menu_item_check.on_check +     function="CheckControl" +     parameter="FriendsListShowIcons" /> +  </menu_item_check>    <menu_item_call name="organize_offline" label="Organize Offline Friends">      <menu_item_call.on_click function="People.Friends.ViewSort.Action" userdata="organize_offline" />    </menu_item_call> diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml index f91a961388..c002cd078f 100644 --- a/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml +++ b/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml @@ -12,9 +12,14 @@      <menu_item_call.on_click function="People.Nearby.ViewSort.Action" userdata="sort_distance" />    </menu_item_call>    <menu_item_separator layout="topleft" /> -  <menu_item_call name="view_icons" label="View People Icons"> -    <menu_item_call.on_click function="People.Nearby.ViewSort.Action" userdata="view_icons" /> -  </menu_item_call> +  <menu_item_check name="view_icons" label="View People Icons"> +    <menu_item_check.on_click +     function="People.Nearby.ViewSort.Action" +     parameter="view_icons" /> +    <menu_item_check.on_check +     function="CheckControl" +     parameter="NearbyListShowIcons" /> +  </menu_item_check>    <menu_item_separator layout="topleft" />    <menu_item_call name="show_blocked_list" label="Show Blocked Residents & Objects">      <menu_item_call.on_click function="SideTray.ShowPanel" userdata="panel_block_list_sidetray" /> diff --git a/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml index d09871cff3..cfd6dc78b6 100644 --- a/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml +++ b/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml @@ -23,9 +23,14 @@         parameter="sort_name" />    </menu_item_check>    <menu_item_separator layout="topleft" /> -  <menu_item_call name="view_icons" label="View People Icons"> -    <menu_item_call.on_click function="People.Recent.ViewSort.Action" userdata="view_icons" /> -  </menu_item_call> +  <menu_item_check name="view_icons" label="View People Icons"> +    <menu_item_check.on_click +     function="People.Recent.ViewSort.Action" +     parameter="view_icons" /> +    <menu_item_check.on_check +     function="CheckControl" +     parameter="RecentListShowIcons" /> +  </menu_item_check>    <menu_item_separator layout="topleft" />    <menu_item_call name="show_blocked_list" label="Show Blocked Residents & Objects">      <menu_item_call.on_click function="SideTray.ShowPanel" userdata="panel_block_list_sidetray" /> diff --git a/indra/newview/skins/default/xui/en/menu_place_add_button.xml b/indra/newview/skins/default/xui/en/menu_place_add_button.xml new file mode 100644 index 0000000000..e3a39a1242 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_place_add_button.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<menu + layout="topleft" + left="0" + mouse_opaque="false" + name="menu_folder_gear" + visible="false"> +    <menu_item_call +     label="Add Folder" +     layout="topleft" +     name="add_folder"> +        <on_click +         function="Places.LandmarksGear.Add.Action" +         parameter="category" /> +        <on_enable +         function="Places.LandmarksGear.Enable" +         parameter="category" /> +    </menu_item_call> +    <menu_item_call +     label="Add Landmark" +     layout="topleft" +     name="add_landmark"> +        <on_click +         function="Places.LandmarksGear.Add.Action" +         parameter="add_landmark" /> +    </menu_item_call> +</menu> diff --git a/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml new file mode 100644 index 0000000000..8db745fab7 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + name="panel_im_control_panel" + width="146" + height="215" + border="false"> +    <avatar_list +     color="DkGray2" +     follows="left|top|right|bottom" +     height="130" +     ignore_online_status="true" +     layout="topleft" +     left="3" +     name="speakers_list" +     opaque="false" +     top="10" +     width="140" /> +    <button +     name="call_btn" +     label="Call" +     width="90" +     height="20" /> +    <button +     name="end_call_btn" +     label="End Call" +     width="90" +     height="20"  +     visible="false"/> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_group_control_panel.xml b/indra/newview/skins/default/xui/en/panel_group_control_panel.xml index 9767a673f6..15b6b2a00d 100644 --- a/indra/newview/skins/default/xui/en/panel_group_control_panel.xml +++ b/indra/newview/skins/default/xui/en/panel_group_control_panel.xml @@ -7,12 +7,14 @@      <avatar_list       color="DkGray2"       follows="left|top|right|bottom" -     height="150" +     height="130" +     ignore_online_status="true"       layout="topleft"       left="3"       name="speakers_list" +     opaque="false"       top="10" -     width="140"/> +     width="140" />      <button       name="group_info_btn"       label="Group Info" @@ -24,4 +26,10 @@       label="Call"       width="90"       height="20" /> +    <button +     name="end_call_btn" +     label="End Call" +     width="90" +     height="20"  +     visible="false"/>  </panel> diff --git a/indra/newview/skins/default/xui/en/panel_group_roles.xml b/indra/newview/skins/default/xui/en/panel_group_roles.xml index 75ded4f249..af1919bd8f 100644 --- a/indra/newview/skins/default/xui/en/panel_group_roles.xml +++ b/indra/newview/skins/default/xui/en/panel_group_roles.xml @@ -486,7 +486,7 @@ things in this group. There's a broad variety of Abilities.          </panel>      </tab_container>      <panel -     height="170" +     height="190"       layout="topleft"       follows="left|top"       left="10" @@ -556,7 +556,7 @@ things in this group. There's a broad variety of Abilities.          </scroll_list>      </panel>      <panel -     height="215" +     height="252"       layout="topleft"       left_delta="0"       name="roles_footer" diff --git a/indra/newview/skins/default/xui/en/panel_im_control_panel.xml b/indra/newview/skins/default/xui/en/panel_im_control_panel.xml index 7dc94d1141..dca52def49 100644 --- a/indra/newview/skins/default/xui/en/panel_im_control_panel.xml +++ b/indra/newview/skins/default/xui/en/panel_im_control_panel.xml @@ -1,7 +1,7 @@  <?xml version="1.0" encoding="utf-8" standalone="yes" ?>  <panel name="panel_im_control_panel"         width="96" -       height="215" +       height="225"         border="false">    <avatar_icon name="avatar_icon" @@ -24,6 +24,13 @@            width="90"            height="20" /> +    <button +     height="20" +     label="End Call" +     name="end_call_btn" +     visible="false" +     width="90" /> +    <button name="share_btn"            label="Share"            width="90" diff --git a/indra/newview/skins/default/xui/en/panel_landmarks.xml b/indra/newview/skins/default/xui/en/panel_landmarks.xml index c33f68eaf7..5293043ba7 100644 --- a/indra/newview/skins/default/xui/en/panel_landmarks.xml +++ b/indra/newview/skins/default/xui/en/panel_landmarks.xml @@ -114,22 +114,10 @@           image_disabled="AddItem_Disabled"           layout="topleft"           left_pad="5" -         name="add_landmark_btn" +         name="add_btn"           picture_style="true"           tool_tip="Add new landmark"           width="18" /> -        <button -         follows="bottom|left" -         height="18" -         image_selected="AddItem_Press" -         image_unselected="AddItem_Off" -         image_disabled="AddItem_Disabled" -         layout="topleft" -         left_pad="5" -         name="add_folder_btn" -         picture_style="true" -         tool_tip="Add new folder" -         width="18" />          <dnd_button           follows="bottom|right"           height="18" diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index 7b19ab1a1c..69089e0e26 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -49,11 +49,13 @@ background_visible="true"       height="500"       layout="topleft"       left="10" +       font="SansSerifBigBold"       name="tabs"       tab_min_width="70"       tab_height="30"       tab_position="top"       top_pad="10" +     halign="center"         width="313">          <panel           follows="all" diff --git a/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml new file mode 100644 index 0000000000..b21fbc1795 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml @@ -0,0 +1,594 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel +	follows="left|right|top|bottom" +	name="MediaControls" +	bg_alpha_color="1 1 1 0" +	height="160" +	layout="topleft" +	mouse_opaque="false" +	width="800"> +  <panel +	  name="media_region" +	  bottom="125" +	  follows="left|right|top|bottom" +	  layout="topleft" +	  left="20" +	  mouse_opaque="false" +	  right="-20" +	  top="20" /> +  <layout_stack +	  follows="left|right|bottom" +	  height="32" +	  layout="topleft" +	  animate="false" +	  left="0" +	  orientation="horizontal" +	  top="96"> +	<!-- outer layout_panels center the inner one --> +	<layout_panel +		width="0" +		layout="topleft" +		user_resize="false" /> +	<panel +		name="media_progress_indicator" +		height="22" +		layout="topleft" +		left="0" +		top="0" +		auto_resize="false" +		user_resize="false" +		min_width="100" +		width="200"> +	  <progress_bar +		  name="media_progress_bar" +		  color_bar="1 1 1 0.96" +		  follows="left|right|top" +		  height="16" +		  layout="topleft" +		  left="0" +		  tool_tip="Media is Loading"/> +	</panel> +	<layout_panel +		width="0" +		layout="topleft" +		user_resize="false" /> +  </layout_stack> +  <layout_stack +	  name="media_controls" +	  follows="left|right" +	  animate="false" +	  height="32" +	  layout="topleft" +	  left="0" +	  orientation="horizontal" +	  top="128"> +	<!-- outer layout_panels center the inner one --> +	<layout_panel +		width="0" +		layout="topleft" +		user_resize="false" /> +	<layout_panel +		name="back" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		min_width="22" +		width="22" +		top="4"> +	  <button +		  auto_resize="false" +		  height="22" +		  image_selected="media_btn_back.png" +		  image_unselected="media_btn_back.png" +		  layout="topleft" +		  tool_tip="Step back" +		  picture_style="true" +		  width="22" +		  top_delta="4"> +		<button.commit_callback +			function="MediaCtrl.Back" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="fwd" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="10" +		min_width="17" +		width="17"> +	  <button +		  height="22" +		  image_selected="media_btn_forward.png" +		  image_unselected="media_btn_forward.png" +		  layout="topleft" +		  tool_tip="Step forward" +		  picture_style="true" +		  top_delta="0" +		  min_width="17" +		  width="17"> +		<button.commit_callback +			function="MediaCtrl.Forward" /> +	  </button> +	</layout_panel> +<!-- +	<panel +		height="22" +		layout="topleft" +		auto_resize="false" +		min_width="3" +		width="3"> +	  <icon +		  height="22" +		  image_name="media_panel_divider.png" +		  layout="topleft" +		  top="0" +		  min_width="3" +		  width="3" /> +	</panel> +--> +	<layout_panel +		name="home" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="-2" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="media_btn_home.png" +		  image_unselected="media_btn_home.png" +		  layout="topleft" +		  tool_tip="Home page" +		  picture_style="true" +		  min_width="22" +		  width="22"> +		<button.commit_callback +			function="MediaCtrl.Home" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="media_stop" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="2" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="button_anim_stop.tga" +		  image_unselected="button_anim_stop.tga" +		  layout="topleft" +		  tool_tip="Stop media" +		  picture_style="true" +		  min_width="22" +		  width="22"> +		<button.commit_callback +			function="MediaCtrl.Stop" /> +	  </button> +	</layout_panel> +<!-- +	<panel +		height="22" +		layout="topleft" +		auto_resize="false" +		min_width="3" +		width="3"> +	  <icon +		  height="22" +		  image_name="media_panel_divider.png" +		  layout="topleft" +		  top="0" +		  min_width="3" +		  width="3" /> +	</panel> +--> +	<layout_panel +		name="reload" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="6" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="media_btn_reload.png" +		  image_unselected="media_btn_reload.png" +		  layout="topleft" +		  tool_tip="Reload" +		  picture_style="true" +		  min_width="22" +		  width="22"> +		<button.commit_callback +			function="MediaCtrl.Reload" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="stop" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="10" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="media_btn_stoploading.png" +		  image_unselected="media_btn_stoploading.png" +		  layout="topleft" +		  picture_style="true" +		  tool_tip = "Stop loading" +		  min_width="22" +		  width="22"> +		<button.commit_callback +			function="MediaCtrl.Stop" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="play" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="14" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="button_anim_play.tga" +		  image_unselected="button_anim_play.tga" +		  layout="topleft" +		  tool_tip = "Play media" +		  picture_style="true" +		  min_width="22" +		  width="22"> +		<button.commit_callback +			function="MediaCtrl.Play" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="pause" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="18" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="button_anim_pause.tga" +		  image_unselected="button_anim_pause.tga" +		  layout="topleft" +		  tool_tip = "Pause media" +		  picture_style="true"> +		<button.commit_callback +			function="MediaCtrl.Pause" /> +	  </button> +	</layout_panel> +	<!-- media URL entry  --> +	<layout_panel +		name="media_address" +		auto_resize="true" +		user_resize="false" +		height="22" +		follows="left|right|bottom" +		layout="topleft" +		width="190" +		min_width="90"> +	  <!-- +		  RE-ENABLE THIS WHEN WE HAVE A HISTORY DROP-DOWN AGAIN + +<combo_box +name="media_address_url" +allow_text_entry="true" +height="22" +layout="topleft" +max_chars="1024" +tool_tip = "Media URL" +<combo_box.commit_callback +function="MediaCtrl.CommitURL" /> +</combo_box> +	  --> +	  <line_editor  +		  name="media_address_url" +		  follows="left|right"  +		  height="22" +		  top="0" +		  tool_tip="Media URL" +		  text_pad_right="16">  +		<line_editor.commit_callback +			function="MediaCtrl.CommitURL"/> +	  </line_editor> +	  <layout_stack +		  animate="false" +		  follows="right" +		  width="32" +		  min_width="32" +		  height="16" +		  top="3" +		  orientation="horizontal" +		  left_pad="-38"> +		<icon +			name="media_whitelist_flag" +			follows="top|right" +			height="16" +			image_name="smicon_warn.tga" +			layout="topleft" +			tool_tip="White List enabled" +			min_width="16" +			width="16" /> +		<icon +			name="media_secure_lock_flag" +			height="16" +			image_name="inv_item_eyes.tga" +			layout="topleft" +			tool_tip="Secured Browsing" +			min_width="16" +			width="16" /> +	  </layout_stack> +	</layout_panel> +	<layout_panel +		name="media_play_position" +		auto_resize="true" +		user_resize="false" +		follows="left|right|top|bottom" +		layout="topleft" +		min_width="100" +		width="200"> +	  <slider_bar +		  name="media_play_slider" +		  follows="left|right|top" +		  height="22" +		  increment="0.05" +		  initial_value="0.5" +		  layout="topleft" +		  tool_tip="Movie play progress" +		  min_width="100" +		  width="200"> +		<slider_bar.commit_callback +			function="MediaCtrl.JumpProgress" /> +	  </slider_bar> +	</layout_panel> +	<layout_panel +		name="media_volume" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		height="24" +		min_width="24" +		width="24"> +	  <button +		  name="media_volume_button" +		  height="22" +		  image_selected="icn_speaker-muted_dark.tga" +		  image_unselected="icn_speaker_dark.tga" +		  is_toggle="true" +		  layout="topleft" +		  scale_image="false"  +		  picture_style="true" +		  tool_tip="Mute This Media" +		  top_delta="22" +		  min_width="24" +		  width="24" > +		<button.commit_callback +			function="MediaCtrl.ToggleMute" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="volume_up" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		min_width="20" +		height="14" +		width="20"> +	  <button +		  top="-3" +		  height="14" +		  image_selected="media_btn_scrollup.png" +		  image_unselected="media_btn_scrollup.png" +		  layout="topleft" +		  tool_tip="Volume up" +		  picture_style="true" +		  scale_image="true" +		  min_width="20" +		  width="20" > +		<button.commit_callback +			function="MediaCtrl.CommitVolumeUp" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="volume_down" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		min_width="20" +		height="14" +		width="20"> +	  <button +		  top="-5" +		  height="14" +		  image_selected="media_btn_scrolldown.png" +		  image_unselected="media_btn_scrolldown.png" +		  layout="topleft" +		  tool_tip="Volume down" +		  picture_style="true" +		  scale_image="true" +		  min_width="20" +		  width="20"> +		<button.commit_callback +			function="MediaCtrl.CommitVolumeDown" /> +	  </button> +	</layout_panel> +	<!-- Scroll pad --> +	<layout_panel +		name="media_panel_scroll" +		auto_resize="false" +		user_resize="false" +		height="32" +		follows="left|right|top|bottom" +		layout="topleft" +		min_width="32" +		width="32"> +	  <icon +		  height="32" +		  image_name="media_panel_scrollbg.png" +		  layout="topleft" +		  top="0" +		  min_width="32" +		  width="32" /> +	  <button +		  name="scrollup" +		  height="8" +		  image_selected="media_btn_scrollup.png" +		  image_unselected="media_btn_scrollup.png" +		  layout="topleft" +		  tool_tip="Scroll up" +		  picture_style="true" +		  scale_image="false" +		  left="12" +		  top_delta="4" +		  min_width="8" +		  width="8" /> +	  <button +		  name="scrollleft" +		  height="8" +		  image_selected="media_btn_scrollleft.png" +		  image_unselected="media_btn_scrollleft.png" +		  layout="topleft" +		  left="3" +		  tool_tip="Scroll left" +		  picture_style="true" +		  scale_image="false" +		  top="12" +		  min_width="8" +		  width="8" /> +	  <button +		  name="scrollright" +		  height="8" +		  image_selected="media_btn_scrollright.png" +		  image_unselected="media_btn_scrollright.png" +		  layout="topleft" +		  left_pad="9" +		  tool_tip="Scroll right" +		  picture_style="true" +		  scale_image="false" +		  top_delta="0" +		  min_width="8" +		  width="8" /> +	  <button +		  name="scrolldown" +		  height="8" +		  image_selected="media_btn_scrolldown.png" +		  image_unselected="media_btn_scrolldown.png" +		  layout="topleft" +		  left="12" +		  tool_tip="Scroll down" +		  picture_style="true" +		  scale_image="false" +		  top="20" +		  min_width="8" +		  width="8" /> +	</layout_panel> +	<layout_panel +		name="zoom_frame" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		height="28" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="media_btn_optimalzoom.png" +		  image_unselected="media_btn_optimalzoom.png" +		  layout="topleft" +		  tool_tip="Zoom" +		  picture_style="true" +		  min_width="22" +		  width="22"> +		<button.commit_callback +			function="MediaCtrl.Zoom" /> +	  </button> +	</layout_panel> +<!-- +	<panel +		height="22" +		layout="topleft" +		auto_resize="false" +		min_width="3" +		width="3"> +	  <icon +		  height="22" +		  image_name="media_panel_divider.png" +		  layout="topleft" +		  top="0" +		  min_width="3" +		  width="3" /> +	</panel> +--> +	<layout_panel +		name="new_window" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="media_btn_newwindow.png" +		  image_unselected="media_btn_newwindow.png" +		  layout="topleft" +		  tool_tip = "Open URL in browser" +		  picture_style="true" +		  top_delta="-3" +		  min_width="24" +		  width="24" > +		<button.commit_callback +			function="MediaCtrl.Open" /> +	  </button> +	</layout_panel> +<!-- +	<panel +		height="22" +		layout="topleft" +		auto_resize="false" +		min_width="3" +		width="3"> +	  <icon +		  height="22" +		  image_name="media_panel_divider.png" +		  layout="topleft" +		  top="0" +		  min_width="3" +		  width="3" /> +	</panel> +--> +	<layout_panel +		name="close" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		min_width="21" +		width="21" > +	  <button +		  height="22" +		  image_selected="media_btn_done.png" +		  image_unselected="media_btn_done.png" +		  layout="topleft" +		  tool_tip ="Close media control" +		  picture_style="true" +		  top_delta="-4" +		  width="21" > +		<button.commit_callback +			function="MediaCtrl.Close" /> +	  </button> +	</layout_panel> +	<layout_panel +		width="0" +		layout="topleft" +		user_resize="false" /> +  </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 81bc12c33c..4eacd72a7d 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -61,9 +61,7 @@  	<string name="TooltipFlagGroupScripts">Group Scripts</string>  	<string name="TooltipFlagNoScripts">No Scripts</string>  	<string name="TooltipLand">Land:</string> -	<string name="TooltipMustSingleDrop">Only a single item can be dragged here</string>	 -	<string name="TooltipAltLeft">Alt+← for previous tab</string>	 -	<string name="TooltipAltRight">Alt+→ for next tab</string>	 +	<string name="TooltipMustSingleDrop">Only a single item can be dragged here</string>  	<!-- tooltips for Urls -->  	<string name="TooltipHttpUrl">Click to view this web page</string> @@ -264,10 +262,6 @@  	<string name="TrackYourCamera">Track your camera</string>  	<string name="ControlYourCamera">Control your camera</string> -	<!-- IM --> -	<string name="IM_logging_string">-- Instant message logging enabled --</string> -	<string name="Unnamed">(Unnamed)</string> -	  	<!-- Sim Access labels -->  	<string name="SIM_ACCESS_PG">PG</string>  	<string name="SIM_ACCESS_MATURE">Mature</string> @@ -2022,15 +2016,14 @@ this texture in your inventory  	<string name="IMTeen">teen</string>  	<!-- floater region info --> +	<!-- The following will replace variable [ALL_ESTATES] in notifications EstateAllowed*, EstateBanned*, EstateManager* -->  	<string name="RegionInfoError">error</string>  	<string name="RegionInfoAllEstatesOwnedBy"> -		all estates -owned by [OWNER] +		all estates owned by [OWNER]  	</string> -	<string name="RegionInfoAllEstatesYouOwn">all estates you owned</string> +	<string name="RegionInfoAllEstatesYouOwn">all estates that you own</string>  	<string name="RegionInfoAllEstatesYouManage"> -		all estates that -you managed for [OWNER] +		all estates that you manage for [OWNER]  	</string>  	<string name="RegionInfoAllowedResidents">Allowed residents: ([ALLOWEDAGENTS], max [MAXACCESS])</string>  	<string name="RegionInfoAllowedGroups">Allowed groups: ([ALLOWEDGROUPS], max [MAXACCESS])</string> @@ -2884,7 +2877,14 @@ If you continue to receive this message, contact the [SUPPORT_SITE].  	  Failed to start viewer  	</string> -  <!-- IM system messages --> +	<!-- IM system messages --> +	<string name="IM_logging_string">-- Instant message logging enabled --</string> +	<string name="IM_typing_start_string">[NAME] is typing...</string> +	<string name="Unnamed">(Unnamed)</string> +	<string name="IM_moderated_chat_label">(Moderated: Voices off by default)</string> +	<string name="IM_unavailable_text_label">Text chat is not available for this call.</string> + +    <string name="ringing-im">      Joining Voice Chat...    </string> diff --git a/indra/newview/skins/default/xui/en/widgets/chat_history.xml b/indra/newview/skins/default/xui/en/widgets/chat_history.xml index b72d59524e..ea6997ebd5 100644 --- a/indra/newview/skins/default/xui/en/widgets/chat_history.xml +++ b/indra/newview/skins/default/xui/en/widgets/chat_history.xml @@ -4,8 +4,8 @@      message_separator="panel_chat_separator.xml"      left_text_pad="10"  	right_text_pad="15" -    left_widget_pad="5" -	rigth_widget_pad="10" +    left_widget_pad="0" +	right_widget_pad="10"  	max_length="2147483647"  	enabled="false"  	track_bottom="true" diff --git a/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml b/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml index 89e442baec..ab4ad94089 100644 --- a/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml +++ b/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml @@ -23,7 +23,8 @@                                image_selected="DropDown_Selected"                                image_disabled="DropDown_Disabled"                                image_disabled_selected="DropDown_Disabled_Selected" /> -  <gesture_combo_box.combo_list bg_writeable_color="MenuDefaultBgColor" /> +  <gesture_combo_box.combo_list bg_writeable_color="MenuDefaultBgColor" +                                scroll_bar_bg_visible="true" />    <gesture_combo_box.combo_editor name="Combo Text Entry"                            select_on_focus="true"                            font="SansSerifSmall" /> diff --git a/indra/newview/skins/default/xui/en/widgets/tab_container.xml b/indra/newview/skins/default/xui/en/widgets/tab_container.xml index 2fe5f517a2..7d10df1af7 100644 --- a/indra/newview/skins/default/xui/en/widgets/tab_container.xml +++ b/indra/newview/skins/default/xui/en/widgets/tab_container.xml @@ -1,6 +1,7 @@  <?xml version="1.0" encoding="utf-8" standalone="yes" ?>  <tab_container tab_min_width="60"                 tab_max_width="150" +               font_halign="left"                 tab_height="16">    <first_tab tab_top_image_unselected="TabTop_Left_Off"                 tab_top_image_selected="TabTop_Left_Selected"  | 
