diff options
94 files changed, 2046 insertions, 817 deletions
| diff --git a/BuildParams b/BuildParams index 84d30f651b..accc019a72 100755 --- a/BuildParams +++ b/BuildParams @@ -131,17 +131,6 @@ viewer-materials.build_debug_release_separately = true  viewer-materials.build_CYGWIN_Debug = false  viewer-materials.build_viewer_update_version_manager = false -# viewer-chui -# -# ======================================== - -viewer-chui.viewer_channel = "Project Viewer - CHUI" -viewer-chui.login_channel = "Project Viewer - CHUI" -viewer-chui.viewer_grid = agni -viewer-chui.build_debug_release_separately = true -viewer-chui.build_CYGWIN_Debug = false -viewer-chui.build_viewer_update_version_manager = false -  # =================================================================  # asset delivery 2010 projects  # ================================================================= diff --git a/doc/contributions.txt b/doc/contributions.txt index 66ccb404a8..9d65411563 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -176,6 +176,8 @@ Ansariel Hiller  	STORM-1713  	STORM-1899  Aralara Rajal +Arare Chantilly +	CHUIBUG-191  Ardy Lay  	STORM-859  	VWR-19499 diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt index e003ed7788..774e8c0676 100755 --- a/indra/edit-me-to-trigger-new-build.txt +++ b/indra/edit-me-to-trigger-new-build.txt @@ -3,3 +3,4 @@ Wed Nov  7 00:25:19 UTC 2012 + diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index a8149a9a1d..44f2c1efe9 100755 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -644,7 +644,7 @@ void LLButton::draw()      //  Cancel sticking of color, if the button is pressed,  	//  or when a flashing of the previously selected button is ended  	if (mFlashingTimer -		&& ((selected && !mFlashingTimer->isFlashingInProgress()) || pressed)) +		&& ((selected && !mFlashingTimer->isFlashingInProgress() && !mForceFlashing) || pressed))  	{  		mFlashing = false;  	} @@ -971,8 +971,9 @@ void LLButton::setToggleState(BOOL b)  	}  } -void LLButton::setFlashing(bool b)	 +void LLButton::setFlashing(bool b, bool force_flashing/* = false */)  {  +	mForceFlashing = force_flashing;  	if (mFlashingTimer)  	{  		mFlashing = b;  diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 060db59a8a..7b4719866d 100755 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -201,7 +201,7 @@ public:  	void			setToggleState(BOOL b);  	void			setHighlight(bool b); -	void			setFlashing( bool b ); +	void			setFlashing( bool b, bool force_flashing = false );  	BOOL			getFlashing() const		{ return mFlashing; }      LLFlashTimer*   getFlashTimer() {return mFlashingTimer;} @@ -378,7 +378,7 @@ protected:  	LLFrameTimer				mFrameTimer;  	LLFlashTimer *				mFlashingTimer; - +	bool                        mForceFlashing; // Stick flashing color even if button is pressed  	bool						mHandleRightMouse;  }; diff --git a/indra/llui/llchatentry.cpp b/indra/llui/llchatentry.cpp index 6a1b48a08a..c04b70eb64 100755 --- a/indra/llui/llchatentry.cpp +++ b/indra/llui/llchatentry.cpp @@ -62,9 +62,9 @@ void LLChatEntry::draw()  {  	if(mIsExpandable)  	{ +		reflow();  		expandText();  	} -  	LLTextEditor::draw();  } @@ -158,19 +158,21 @@ void LLChatEntry::onValueChange(S32 start, S32 end)      resetLabel();  } -bool LLChatEntry::useLabel() +bool LLChatEntry::useLabel() const  {      return !getLength() && !mLabel.empty();  }  void LLChatEntry::onFocusReceived()  { - +	LLUICtrl::onFocusReceived(); +	updateAllowingLanguageInput();  }  void LLChatEntry::onFocusLost()  { - +	LLTextEditor::focusLostHelper(); +	LLUICtrl::onFocusLost();  }  BOOL LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) diff --git a/indra/llui/llchatentry.h b/indra/llui/llchatentry.h index 49c8d21450..e67f39b21b 100755 --- a/indra/llui/llchatentry.h +++ b/indra/llui/llchatentry.h @@ -56,14 +56,14 @@ protected:  	LLChatEntry(const Params& p);      /*virtual*/ void    beforeValueChange();      /*virtual*/ void    onValueChange(S32 start, S32 end); -    /*virtual*/ bool    useLabel(); +    /*virtual*/ bool    useLabel() const;  public:  	virtual void	draw();  	virtual	void	onCommit(); -    /*virtual*/ void	onFocusReceived(); -    /*virtual*/ void	onFocusLost(); +	/*virtual*/ void	onFocusReceived(); +	/*virtual*/ void	onFocusLost();  	void enableSingleLineMode(bool single_line_mode);  	boost::signals2::connection setTextExpandedCallback(const commit_signal_t::slot_type& cb); diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 09e27a264a..273ceb4038 100755 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -507,22 +507,11 @@ LLFloater::~LLFloater()  {  	LLFloaterReg::removeInstance(mInstanceName, mKey); -//	delete mNotificationContext; -//	mNotificationContext = NULL; - -	//// am I not hosted by another floater? -	//if (mHostHandle.isDead()) -	//{ -	//	LLFloaterView* parent = (LLFloaterView*) getParent(); - -	//	if( parent ) -	//	{ -	//		parent->removeChild( this ); -	//	} -	//} - -	// Just in case we might still have focus here, release it. -	releaseFocus(); +	if( gFocusMgr.childHasKeyboardFocus(this)) +	{ +		// Just in case we might still have focus here, release it. +		releaseFocus(); +	}  	// This is important so that floaters with persistent rects (i.e., those  	// created with rect control rather than an LLRect) are restored in their @@ -1486,6 +1475,7 @@ void LLFloater::moveResizeHandlesToFront()  	}  } +/*virtual*/  BOOL LLFloater::isFrontmost()  {  	LLFloaterView* floater_view = getParentByType<LLFloaterView>(); @@ -1504,7 +1494,7 @@ void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition)  		floaterp->setRect(gFloaterView->findNeighboringPosition(this, floaterp));  		floaterp->setSnapTarget(getHandle());  	} -	gFloaterView->adjustToFitScreen(floaterp, FALSE); +	gFloaterView->adjustToFitScreen(floaterp, FALSE, TRUE);  	if (floaterp->isFrontmost())  	{  		// make sure to bring self and sibling floaters to front @@ -2735,7 +2725,7 @@ void LLFloaterView::refresh()  const S32 FLOATER_MIN_VISIBLE_PIXELS = 16; -void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_outside) +void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_outside, BOOL snap_in_toolbars/* = false*/)  {  	if (floater->getParent() != this)  	{ @@ -2788,7 +2778,7 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out  	}  	// move window fully onscreen -	if (floater->translateIntoRect( getSnapRect(), allow_partial_outside ? FLOATER_MIN_VISIBLE_PIXELS : S32_MAX )) +	if (floater->translateIntoRect( snap_in_toolbars ? getSnapRect() : gFloaterView->getRect(), allow_partial_outside ? FLOATER_MIN_VISIBLE_PIXELS : S32_MAX ))  	{  		floater->clearSnapTarget();  	} @@ -3258,6 +3248,11 @@ bool LLFloater::isShown() const      return ! isMinimized() && isInVisibleChain();  } +bool LLFloater::isDetachedAndNotMinimized() +{ +	return !getHost() && !isMinimized(); +} +  /* static */  bool LLFloater::isShown(const LLFloater* floater)  { diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 4dba1e645f..3482314698 100755 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -238,6 +238,7 @@ public:  	void			center();  	LLMultiFloater* getHost(); +	bool isDetachedAndNotMinimized();  	void			applyTitle();  	std::string		getCurrentTitle() const; @@ -261,7 +262,7 @@ public:  	static bool     isVisible(const LLFloater* floater);  	static bool     isMinimized(const LLFloater* floater);  	BOOL			isFirstLook() { return mFirstLook; } // EXT-2653: This function is necessary to prevent overlapping for secondary showed toasts -	BOOL			isFrontmost(); +	virtual BOOL	isFrontmost();  	BOOL			isDependent()					{ return !mDependeeHandle.isDead(); }  	void			setCanMinimize(BOOL can_minimize);  	void			setCanClose(BOOL can_close); @@ -528,7 +529,7 @@ public:  	LLRect			findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor );  	// Given a child of gFloaterView, make sure this view can fit entirely onscreen. -	void			adjustToFitScreen(LLFloater* floater, BOOL allow_partial_outside); +	void			adjustToFitScreen(LLFloater* floater, BOOL allow_partial_outside, BOOL snap_in_toolbars = false);  	void			setMinimizePositionVerticalOffset(S32 offset) { mMinimizePositionVOffset = offset; }  	void			getMinimizePosition( S32 *left, S32 *bottom); diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 8aa1eb7cd5..cf449217f5 100755 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -323,9 +323,11 @@ static LLFastTimer::DeclareTimer FTM_FILTER("Filter Folder View");  void LLFolderView::filter( LLFolderViewFilter& filter )  { +    // Entry point of inventory filtering (CHUI-849)  	LLFastTimer t2(FTM_FILTER); -	filter.setFilterCount(llclamp(LLUI::sSettingGroups["config"]->getS32("FilterItemsPerFrame"), 1, 5000)); +    filter.resetTime(llclamp(LLUI::sSettingGroups["config"]->getS32(mParentPanel->getVisible() ? "FilterItemsMaxTimePerFrameVisible" : "FilterItemsMaxTimePerFrameUnvisible"), 1, 100)); +    // Note: we filter the model, not the view  	getViewModelItem()->filter(filter);  } @@ -661,7 +663,7 @@ void LLFolderView::draw()  		// get preferable text height...  		S32 pixel_height = mStatusTextBox->getTextPixelHeight(); -		bool height_changed = local_rect.getHeight() != pixel_height; +		bool height_changed = (local_rect.getHeight() < pixel_height);  		if (height_changed)  		{  			// ... if it does not match current height, lets rearrange current view. @@ -1601,15 +1603,17 @@ void LLFolderView::update()  	{  		mNeedsAutoSelect = TRUE;  	} -	// filter to determine visibility before arranging +     +	// Filter to determine visibility before arranging  	filter(getFolderViewModel()->getFilter()); -	// Clear the modified setting on the filter only if the filter count is non-zero after running the filter process -	// Note: if the filter count is zero, then the filter most likely halted before completing the entire set of items -	if (getFolderViewModel()->getFilter().isModified() && (getFolderViewModel()->getFilter().getFilterCount() > 0)) +     +	// Clear the modified setting on the filter only if the filter finished after running the filter process +	// Note: if the filter count has timed out, that means the filter halted before completing the entire set of items +    if (getFolderViewModel()->getFilter().isModified() && (!getFolderViewModel()->getFilter().isTimedOut()))  	{  		getFolderViewModel()->getFilter().clearModified();  	} - +      	// automatically show matching items, and select first one if we had a selection  	if (mNeedsAutoSelect)  	{ @@ -1649,11 +1653,13 @@ void LLFolderView::update()    BOOL is_visible = isInVisibleChain(); -  //Puts folders/items in proper positions -  if ( is_visible ) +  // Puts folders/items in proper positions +  // arrange() takes the model filter flag into account and call sort() if necessary (CHUI-849) +  // It also handles the open/close folder animation +  if (is_visible)    {      sanitizeSelection(); -    if( needsArrange() ) +    if (needsArrange())      {        S32 height = 0;        S32 width = 0; diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index fdb4108afb..6c147ccc12 100755 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -274,6 +274,7 @@ void LLFolderViewItem::refresh()  	}  	mLabelWidthDirty = true; +    // Dirty the filter flag of the model from the view (CHUI-849)  	vmi.dirtyFilter();  } @@ -943,11 +944,17 @@ void LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder)  static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange"); -// Finds width and height of this object and its children. Also -// makes sure that this view and its children are the right size. +// Make everything right and in the right place ready for drawing (CHUI-849) +// * Sort everything correctly if necessary +// * Turn widgets visible/invisible according to their model filtering state +// * Takes animation state into account for opening/closing of folders (this makes widgets visible/invisible) +// * Reposition visible widgets so that they line up correctly with no gap +// * Compute the width and height of the current folder and its children +// * Makes sure that this view and its children are the right size  S32 LLFolderViewFolder::arrange( S32* width, S32* height )  { -	// sort before laying out contents +	// Sort before laying out contents +    // Note that we sort from the root (CHUI-849)  	getRoot()->getFolderViewModel()->sort(this);  	LLFastTimer t2(FTM_ARRANGE); @@ -1613,16 +1620,13 @@ void LLFolderViewFolder::addFolder(LLFolderViewFolder* folder)  }  void LLFolderViewFolder::requestArrange() -{  -	if ( mLastArrangeGeneration != -1) -	{ -		mLastArrangeGeneration = -1;  -		// flag all items up to root -		if (mParentFolder) -		{ -			mParentFolder->requestArrange(); -		} -	} +{ +    mLastArrangeGeneration = -1; +    // flag all items up to root +    if (mParentFolder) +    { +        mParentFolder->requestArrange(); +    }  }  void LLFolderViewFolder::toggleOpen() diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index ca31931e19..a9b0201236 100755 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -316,7 +316,6 @@ protected:  	F32			mAutoOpenCountdown;  	S32			mLastArrangeGeneration;  	S32			mLastCalculatedWidth; -	S32			mMostFilteredDescendantGeneration;  	bool		mNeedsSort;  public: diff --git a/indra/llui/llfolderviewmodel.cpp b/indra/llui/llfolderviewmodel.cpp index 3593804554..3363dc5316 100755 --- a/indra/llui/llfolderviewmodel.cpp +++ b/indra/llui/llfolderviewmodel.cpp @@ -48,7 +48,7 @@ std::string LLFolderViewModelCommon::getStatusText()  void LLFolderViewModelCommon::filter()  { -	getFilter().setFilterCount(llclamp(LLUI::sSettingGroups["config"]->getS32("FilterItemsPerFrame"), 1, 5000)); +    getFilter().resetTime(llclamp(LLUI::sSettingGroups["config"]->getS32("FilterItemsMaxTimePerFrameVisible"), 1, 100));  	mFolderView->getViewModelItem()->filter(getFilter());  } diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index 1b61212c0e..b1bcc8bbb4 100755 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -87,12 +87,11 @@ public:  	virtual void 				setModified(EFilterModified behavior = FILTER_RESTART) = 0;  	// +-------------------------------------------------------------------+ -	// + Count +	// + Time  	// +-------------------------------------------------------------------+ -	virtual void 				setFilterCount(S32 count) = 0; -	virtual S32 				getFilterCount() const = 0; -	virtual void 				decrementFilterCount() = 0; - +	virtual void 				resetTime(S32 timeout) = 0; +    virtual bool                isTimedOut() = 0; +      	// +-------------------------------------------------------------------+  	// + Default  	// +-------------------------------------------------------------------+ @@ -308,26 +307,28 @@ public:  	virtual bool potentiallyVisible()  	{  		return passedFilter() // we've passed the filter -			|| getLastFilterGeneration() < mRootViewModel.getFilter().getFirstSuccessGeneration() // or we don't know yet +			|| (getLastFilterGeneration() < mRootViewModel.getFilter().getFirstSuccessGeneration()) // or we don't know yet  			|| descendantsPassedFilter();  	}  	virtual bool passedFilter(S32 filter_generation = -1)   	{  -		if (filter_generation < 0)  +		if (filter_generation < 0) +        {  			filter_generation = mRootViewModel.getFilter().getFirstSuccessGeneration(); - -		bool passed_folder_filter = mPassedFolderFilter && mLastFolderFilterGeneration >= filter_generation; -		bool passed_filter = mPassedFilter && mLastFilterGeneration >= filter_generation; -		return passed_folder_filter -				&& (descendantsPassedFilter(filter_generation) -					|| passed_filter); +        } +		bool passed_folder_filter = mPassedFolderFilter && (mLastFolderFilterGeneration >= filter_generation); +		bool passed_filter = mPassedFilter && (mLastFilterGeneration >= filter_generation); +		return passed_folder_filter && (passed_filter || descendantsPassedFilter(filter_generation));  	}  	virtual bool descendantsPassedFilter(S32 filter_generation = -1)  	{  -		if (filter_generation < 0) filter_generation = mRootViewModel.getFilter().getFirstSuccessGeneration(); -		return mMostFilteredDescendantGeneration >= filter_generation;  +		if (filter_generation < 0) +        { +            filter_generation = mRootViewModel.getFilter().getFirstSuccessGeneration(); +        } +		return mMostFilteredDescendantGeneration >= filter_generation;  	} diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index e33ac1d5c2..c89c0203b4 100755 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -214,8 +214,15 @@ LLLayoutStack::Params::Params()  	open_time_constant("open_time_constant", 0.02f),  	close_time_constant("close_time_constant", 0.03f),  	resize_bar_overlap("resize_bar_overlap", 1), -	border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0)) -{} +	border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0)), +	show_drag_handle("show_drag_handle", false), +	drag_handle_first_indent("drag_handle_first_indent", 0), +	drag_handle_second_indent("drag_handle_second_indent", 0), +	drag_handle_thickness("drag_handle_thickness", 5), +	drag_handle_shift("drag_handle_shift", 2) +{ +	addSynonym(border_size, "drag_handle_gap"); +}  LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)   :	LLView(p), @@ -227,8 +234,14 @@ LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)  	mClip(p.clip),  	mOpenTimeConstant(p.open_time_constant),  	mCloseTimeConstant(p.close_time_constant), -	mResizeBarOverlap(p.resize_bar_overlap) -{} +	mResizeBarOverlap(p.resize_bar_overlap), +	mShowDragHandle(p.show_drag_handle), +	mDragHandleFirstIndent(p.drag_handle_first_indent), +	mDragHandleSecondIndent(p.drag_handle_second_indent), +	mDragHandleThickness(p.drag_handle_thickness), +	mDragHandleShift(p.drag_handle_shift) +{ +}  LLLayoutStack::~LLLayoutStack()  { @@ -262,6 +275,26 @@ void LLLayoutStack::draw()  			drawChild(panelp, 0, 0, !clip_rect.isEmpty());  		}  	} + +	const LLView::child_list_t * child_listp = getChildList(); +	BOOST_FOREACH(LLView * childp, * child_listp) +	{ +		LLResizeBar * resize_barp = dynamic_cast<LLResizeBar*>(childp); +		if (resize_barp && resize_barp->isShowDragHandle() && resize_barp->getVisible() && resize_barp->getRect().isValid()) +		{ +			LLRect screen_rect = resize_barp->calcScreenRect(); +			if (LLUI::getRootView()->getLocalRect().overlaps(screen_rect) && LLUI::sDirtyRect.overlaps(screen_rect)) +			{ +				LLUI::pushMatrix(); +				{ +					const LLRect& rb_rect(resize_barp->getRect()); +					LLUI::translate(rb_rect.mLeft, rb_rect.mBottom); +					resize_barp->draw(); +				} +				LLUI::popMatrix(); +			} +		} +	}  }  void LLLayoutStack::removeChild(LLView* view) @@ -390,7 +423,6 @@ void LLLayoutStack::updateLayout()  	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)  	{  		F32 panel_dim = llmax(panelp->getExpandedMinDim(), panelp->mTargetDim); -		F32 panel_visible_dim = panelp->getVisibleDim();  		LLRect panel_rect;  		if (mOrientation == HORIZONTAL) @@ -407,27 +439,61 @@ void LLLayoutStack::updateLayout()  										getRect().getWidth(),  										llround(panel_dim));  		} -		panelp->setIgnoreReshape(true); -		panelp->setShape(panel_rect); -		panelp->setIgnoreReshape(false);  		LLRect resize_bar_rect(panel_rect); - +		LLResizeBar * resize_barp = panelp->getResizeBar(); +		bool show_drag_handle = resize_barp->isShowDragHandle();  		F32 panel_spacing = (F32)mPanelSpacing * panelp->getVisibleAmount(); +		F32 panel_visible_dim = panelp->getVisibleDim(); +		S32 panel_spacing_round = (S32)(llround(panel_spacing)); +  		if (mOrientation == HORIZONTAL)  		{ -			resize_bar_rect.mLeft = panel_rect.mRight - mResizeBarOverlap; -			resize_bar_rect.mRight = panel_rect.mRight + (S32)(llround(panel_spacing)) + mResizeBarOverlap; -  			cur_pos += panel_visible_dim + panel_spacing; + +			if (show_drag_handle && panel_spacing_round > mDragHandleThickness) +			{ +				resize_bar_rect.mLeft = panel_rect.mRight + mDragHandleShift; +				resize_bar_rect.mRight = resize_bar_rect.mLeft + mDragHandleThickness; +			} +			else +			{ +				resize_bar_rect.mLeft = panel_rect.mRight - mResizeBarOverlap; +				resize_bar_rect.mRight = panel_rect.mRight + panel_spacing_round + mResizeBarOverlap; +			} + +			if (show_drag_handle) +			{ +				resize_bar_rect.mBottom += mDragHandleSecondIndent; +				resize_bar_rect.mTop -= mDragHandleFirstIndent; +			} +  		}  		else //VERTICAL  		{ -			resize_bar_rect.mTop = panel_rect.mBottom + mResizeBarOverlap; -			resize_bar_rect.mBottom = panel_rect.mBottom - (S32)(llround(panel_spacing)) - mResizeBarOverlap; -  			cur_pos -= panel_visible_dim + panel_spacing; + +			if (show_drag_handle && panel_spacing_round > mDragHandleThickness) +			{ +				resize_bar_rect.mTop = panel_rect.mBottom - mDragHandleShift; +				resize_bar_rect.mBottom = resize_bar_rect.mTop - mDragHandleThickness; +			} +			else +			{ +				resize_bar_rect.mTop = panel_rect.mBottom + mResizeBarOverlap; +				resize_bar_rect.mBottom = panel_rect.mBottom - panel_spacing_round - mResizeBarOverlap; +			} + +			if (show_drag_handle) +			{ +				resize_bar_rect.mLeft += mDragHandleFirstIndent; +				resize_bar_rect.mRight -= mDragHandleSecondIndent; +			}  		} + +		panelp->setIgnoreReshape(true); +		panelp->setShape(panel_rect); +		panelp->setIgnoreReshape(false);  		panelp->mResizeBar->setShape(resize_bar_rect);  	} @@ -475,14 +541,13 @@ void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp)  	{  		if (lp->mResizeBar == NULL)  		{ -			LLResizeBar::Side side = (mOrientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM; -  			LLResizeBar::Params resize_params;  			resize_params.name("resize");  			resize_params.resizing_view(lp);  			resize_params.min_size(lp->getRelevantMinDim()); -			resize_params.side(side); +			resize_params.side((mOrientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM);  			resize_params.snapping_enabled(false); +			resize_params.show_drag_handle(mShowDragHandle);  			LLResizeBar* resize_bar = LLUICtrlFactory::create<LLResizeBar>(resize_params);  			lp->mResizeBar = resize_bar;  			LLView::addChild(resize_bar, 0); @@ -864,3 +929,4 @@ void LLLayoutStack::updateResizeBarLimits()  		previous_visible_panelp = visible_panelp;  	}  } + diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index 02c664f1a0..b570974bd6 100755 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -62,6 +62,11 @@ public:  		Optional<F32>			open_time_constant,  								close_time_constant;  		Optional<S32>			resize_bar_overlap; +		Optional<bool>			show_drag_handle; +		Optional<S32>			drag_handle_first_indent; +		Optional<S32>			drag_handle_second_indent; +		Optional<S32>			drag_handle_thickness; +		Optional<S32>			drag_handle_shift;  		Params();  	}; @@ -126,6 +131,11 @@ private:  	F32  mCloseTimeConstant;  	bool mNeedsLayout;  	S32  mResizeBarOverlap; +	bool mShowDragHandle; +	S32  mDragHandleFirstIndent; +	S32  mDragHandleSecondIndent; +	S32  mDragHandleThickness; +	S32  mDragHandleShift;  }; // end class LLLayoutStack diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index f7bf39c897..f854e1785d 100755 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -3146,6 +3146,13 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)  	const S32 CURSOR_HEIGHT = 22;		// Approximate "normal" cursor size  	const S32 CURSOR_WIDTH = 12; +	if (menu->getChildList()->empty()) +	{ +		return; +	} + +	menu->setVisible( TRUE ); +  	//Do not show menu if all menu items are disabled  	BOOL item_enabled = false;  	for (LLView::child_list_t::const_iterator itor = menu->getChildList()->begin(); @@ -3156,8 +3163,9 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)  		item_enabled = item_enabled || menu_item->getEnabled();  	} -	if(menu->getChildList()->empty() || !item_enabled) +	if(!item_enabled)  	{ +		menu->setVisible( FALSE );  		return;  	} @@ -3173,8 +3181,6 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)  		menu->mFirstVisibleItem = NULL;  	} -	menu->setVisible( TRUE ); -  	// Fix menu rect if needed.  	menu->needsArrange();  	menu->arrangeAndClear(); diff --git a/indra/llui/llresizebar.cpp b/indra/llui/llresizebar.cpp index 15e56cbfe5..e67b22c977 100755 --- a/indra/llui/llresizebar.cpp +++ b/indra/llui/llresizebar.cpp @@ -28,14 +28,53 @@  #include "llresizebar.h" +#include "lllocalcliprect.h"  #include "llmath.h"  #include "llui.h"  #include "llmenugl.h"  #include "llfocusmgr.h"  #include "llwindow.h" +class LLImagePanel : public LLPanel +{ +public: +	struct Params :	public LLInitParam::Block<Params, LLPanel::Params> +	{ +		Optional<bool> horizontal; +		Params() : horizontal("horizontal", false) {} +	}; +	LLImagePanel(const Params& p) : LLPanel(p), mHorizontal(p.horizontal) {} +	virtual ~LLImagePanel() {} + +	void draw() +	{ +		const LLRect& parent_rect = getParent()->getRect(); +		const LLRect& rect = getRect(); +		LLRect clip_rect( -rect.mLeft, parent_rect.getHeight() - rect.mBottom - 2 +						 , parent_rect.getWidth() - rect.mLeft - (mHorizontal ? 2 : 0), -rect.mBottom); +		LLLocalClipRect clip(clip_rect); +		LLPanel::draw(); +	} + +private: +	bool mHorizontal; +}; + +static LLDefaultChildRegistry::Register<LLImagePanel> t1("resize_bar_image_panel"); + +LLResizeBar::Params::Params() +:	max_size("max_size", S32_MAX), +	snapping_enabled("snapping_enabled", true), +	resizing_view("resizing_view"), +	side("side"), +	allow_double_click_snapping("allow_double_click_snapping", true), +	show_drag_handle("show_drag_handle", false) +{ +	name = "resize_bar"; +} +  LLResizeBar::LLResizeBar(const LLResizeBar::Params& p) -:	LLView(p), +:	LLPanel(p),  	mDragLastScreenX( 0 ),  	mDragLastScreenY( 0 ),  	mLastMouseScreenX( 0 ), @@ -46,7 +85,9 @@ LLResizeBar::LLResizeBar(const LLResizeBar::Params& p)  	mSnappingEnabled(p.snapping_enabled),  	mAllowDoubleClickSnapping(p.allow_double_click_snapping),  	mResizingView(p.resizing_view), -	mResizeListener(NULL) +	mResizeListener(NULL), +	mShowDragHandle(p.show_drag_handle), +	mImagePanel(NULL)  {  	setFollowsNone();  	// set up some generically good follow code. @@ -75,8 +116,37 @@ LLResizeBar::LLResizeBar(const LLResizeBar::Params& p)  	default:  		break;  	} + +	if (mShowDragHandle) +	{ +		LLViewBorder::Params border_params; +		border_params.border_thickness = 1; +		border_params.highlight_light_color = LLUIColorTable::instance().getColor("ResizebarBorderLight"); +		border_params.shadow_dark_color = LLUIColorTable::instance().getColor("ResizebarBorderDark"); + +		addBorder(border_params); +		setBorderVisible(TRUE); + +		LLImagePanel::Params image_panel; +		mDragHandleImage = LLUI::getUIImage(LLResizeBar::RIGHT == mSide ? "Vertical Drag Handle" : "Horizontal Drag Handle"); +		image_panel.bg_alpha_image = mDragHandleImage; +		image_panel.background_visible = true; +		image_panel.horizontal = (LLResizeBar::BOTTOM == mSide); +		mImagePanel = LLUICtrlFactory::create<LLImagePanel>(image_panel); +		setImagePanel(mImagePanel); +	}  } +BOOL LLResizeBar::postBuild() +{ +	if (mShowDragHandle) +	{ +		setBackgroundVisible(TRUE); +		setTransparentColor(LLUIColorTable::instance().getColor("ResizebarBody")); +	} + +	return LLPanel::postBuild(); +}  BOOL LLResizeBar::handleMouseDown(S32 x, S32 y, MASK mask)  { @@ -342,3 +412,39 @@ BOOL LLResizeBar::handleDoubleClick(S32 x, S32 y, MASK mask)  	return TRUE;  } +void LLResizeBar::setImagePanel(LLPanel * panelp) +{ +	const LLView::child_list_t * children = getChildList(); +	if (getChildCount() == 2) +	{ +		LLPanel * image_panelp = dynamic_cast<LLPanel*>(children->back()); +		if (image_panelp) +		{ +			removeChild(image_panelp); +			delete image_panelp; +		} +	} + +	addChild(panelp); +	sendChildToBack(panelp); +} + +LLPanel * LLResizeBar::getImagePanel() const +{ +	return getChildCount() > 0 ? (LLPanel *)getChildList()->back() : NULL; +} + +void LLResizeBar::draw() +{ +	if (mShowDragHandle) +	{ +		S32 image_width = mDragHandleImage->getTextureWidth(); +		S32 image_height = mDragHandleImage->getTextureHeight(); +		const LLRect& panel_rect = getRect(); +		S32 image_left = (panel_rect.getWidth() - image_width) / 2 - 1; +		S32 image_bottom = (panel_rect.getHeight() - image_height) / 2; +		mImagePanel->setRect(LLRect(image_left, image_bottom + image_height, image_left + image_width, image_bottom)); +	} + +	LLPanel::draw(); +} diff --git a/indra/llui/llresizebar.h b/indra/llui/llresizebar.h index 8190a95a71..bcf8ea0b40 100755 --- a/indra/llui/llresizebar.h +++ b/indra/llui/llresizebar.h @@ -27,15 +27,14 @@  #ifndef LL_RESIZEBAR_H  #define LL_RESIZEBAR_H -#include "llview.h" -#include "llcoord.h" +#include "llpanel.h" -class LLResizeBar : public LLView +class LLResizeBar : public LLPanel  {  public:  	enum Side { LEFT, TOP, RIGHT, BOTTOM }; -	struct Params : public LLInitParam::Block<Params, LLView::Params> +	struct Params : public LLInitParam::Block<Params, LLPanel::Params>  	{  		Mandatory<LLView*> resizing_view;  		Mandatory<Side>	side; @@ -44,24 +43,19 @@ public:  		Optional<S32>	max_size;  		Optional<bool>	snapping_enabled;  		Optional<bool>	allow_double_click_snapping; +		Optional<bool>	show_drag_handle; -		Params() -		:	max_size("max_size", S32_MAX), -			snapping_enabled("snapping_enabled", true), -			resizing_view("resizing_view"), -			side("side"), -			allow_double_click_snapping("allow_double_click_snapping", true) -		{ -			name = "resize_bar"; -		} +		Params();  	};  protected:  	LLResizeBar(const LLResizeBar::Params& p);  	friend class LLUICtrlFactory; + +	/*virtual*/ BOOL postBuild();  public: -//	virtual void	draw();  No appearance +	virtual void	draw();  	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);  	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);  	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask); @@ -72,20 +66,26 @@ public:  	void			setAllowDoubleClickSnapping(BOOL allow) { mAllowDoubleClickSnapping = allow; }  	bool			canResize() { return getEnabled() && mMaxSize > mMinSize; }  	void            setResizeListener(boost::function<void(void*)> listener) {mResizeListener = listener;} +	BOOL			isShowDragHandle() const { return mShowDragHandle; } +	void			setImagePanel(LLPanel * panelp); +	LLPanel *		getImagePanel() const;  private: -	S32				mDragLastScreenX; -	S32				mDragLastScreenY; -	S32				mLastMouseScreenX; -	S32				mLastMouseScreenY; -	LLCoordGL		mLastMouseDir; -	S32				mMinSize; -	S32				mMaxSize; -	const Side		mSide; -	BOOL			mSnappingEnabled; -	BOOL			mAllowDoubleClickSnapping; -	LLView*			mResizingView; -	boost::function<void(void*)>  mResizeListener; +	S32								mDragLastScreenX; +	S32								mDragLastScreenY; +	S32								mLastMouseScreenX; +	S32								mLastMouseScreenY; +	LLCoordGL						mLastMouseDir; +	S32								mMinSize; +	S32								mMaxSize; +	const Side						mSide; +	BOOL							mSnappingEnabled; +	BOOL							mAllowDoubleClickSnapping; +	BOOL							mShowDragHandle; +	LLView*							mResizingView; +	boost::function<void(void*)>	mResizeListener; +	LLPointer<LLUIImage>			mDragHandleImage; +	LLPanel *						mImagePanel;  };  #endif  // LL_RESIZEBAR_H diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 7f04c92b27..40f828ed47 100755 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1179,10 +1179,10 @@ LLScrollListItem* LLScrollListCtrl::addSeparator(EAddPosition pos)  // Selects first enabled item of the given name.  // Returns false if item not found.  // Calls getItemByLabel in order to combine functionality -BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sensitive) +BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sensitive, S32 column/* = 0*/)  {  	deselectAllItems(TRUE); 	// ensure that no stale items are selected, even if we don't find a match -	LLScrollListItem* item = getItemByLabel(label, case_sensitive); +	LLScrollListItem* item = getItemByLabel(label, case_sensitive, column);  	bool found = NULL != item;  	if(found) diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 8fa06cc499..9b361c39d7 100755 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -241,7 +241,7 @@ public:  	// one of which can be selected at a time.  	virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos = ADD_BOTTOM, const LLSD& id = LLSD()); -	BOOL			selectItemByLabel( const std::string& item, BOOL case_sensitive = TRUE );		// FALSE if item not found +	BOOL			selectItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 );		// FALSE if item not found  	BOOL			selectItemByPrefix(const std::string& target, BOOL case_sensitive = TRUE);  	BOOL			selectItemByPrefix(const LLWString& target, BOOL case_sensitive = TRUE);  	LLScrollListItem*  getItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 ); diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index a45c4ced2e..0276ade3e1 100755 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -180,6 +180,7 @@ LLTextBase::Params::Params()  LLTextBase::LLTextBase(const LLTextBase::Params &p)   :	LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)),  	mURLClickSignal(NULL), +	mIsFriendSignal(NULL),  	mMaxTextByteLength( p.max_text_length ),  	mFont(p.font),  	mFontShadow(p.font_shadow), @@ -653,6 +654,10 @@ void LLTextBase::drawText()  			mSpellCheckEnd = end;  		}  	} +	else +	{ +		mMisspellRanges.clear(); +	}  	LLTextSegmentPtr cur_segment = *seg_iter; @@ -1850,7 +1855,17 @@ LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index)  	static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment(); -	if (index > getLength()) { return mSegments.end(); } +	S32 text_len = 0; +	if (!useLabel()) +	{ +		text_len = getLength(); +	} +	else +	{ +		text_len = mLabel.getWString().length(); +	} + +	if (index > text_len) { return mSegments.end(); }  	// when there are no segments, we return the end iterator, which must be checked by caller  	if (mSegments.size() <= 1) { return mSegments.begin(); } @@ -1866,7 +1881,17 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 i  {  	static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment(); -	if (index > getLength()) { return mSegments.end(); } +	S32 text_len = 0; +	if (!useLabel()) +	{ +		text_len = getLength(); +	} +	else +	{ +		text_len = mLabel.getWString().length(); +	} + +	if (index > text_len) { return mSegments.end(); }  	// when there are no segments, we return the end iterator, which must be checked by caller  	if (mSegments.size() <= 1) { return mSegments.begin(); } @@ -1916,9 +1941,12 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)  	registrar.add("Url.OpenInternal", boost::bind(&LLUrlAction::openURLInternal, url));  	registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url));  	registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url)); +	registrar.add("Url.Block", boost::bind(&LLUrlAction::blockObject, url));  	registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url));  	registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url));  	registrar.add("Url.AddFriend", boost::bind(&LLUrlAction::addFriend, url)); +	registrar.add("Url.RemoveFriend", boost::bind(&LLUrlAction::removeFriend, url)); +	registrar.add("Url.SendIM", boost::bind(&LLUrlAction::sendIM, url));  	registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url));  	registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url));  	registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url)); @@ -1927,6 +1955,19 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)  	delete mPopupMenu;  	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(xui_file, LLMenuGL::sMenuContainer,  																		 LLMenuHolderGL::child_registry_t::instance());	 +	if (mIsFriendSignal) +	{ +		bool isFriend = *(*mIsFriendSignal)(LLUUID(LLUrlAction::getUserID(url))); +		LLView* addFriendButton = mPopupMenu->getChild<LLView>("add_friend"); +		LLView* removeFriendButton = mPopupMenu->getChild<LLView>("remove_friend"); + +		if (addFriendButton && removeFriendButton) +		{ +			addFriendButton->setEnabled(!isFriend); +			removeFriendButton->setEnabled(isFriend); +		} +	} +	  	if (mPopupMenu)  	{  		mPopupMenu->show(x, y); @@ -2096,7 +2137,7 @@ void LLTextBase::resetLabel()  	}  } -bool LLTextBase::useLabel() +bool LLTextBase::useLabel() const  {      return !getLength() && !mLabel.empty() && !hasFocus();  } @@ -2602,21 +2643,18 @@ void LLTextBase::setCursorAtLocalPos( S32 local_x, S32 local_y, bool round, bool  void LLTextBase::changeLine( S32 delta )  {  	S32 line = getLineNumFromDocIndex(mCursorPos); +	S32 max_line_nb = getLineCount() - 1; +	max_line_nb = (max_line_nb < 0 ? 0 : max_line_nb); +     +	S32 new_line = llclamp(line + delta, 0, max_line_nb); -	S32 new_line = line; -	if( (delta < 0) && (line > 0 ) ) -	{ -		new_line = line - 1; -	} -	else if( (delta > 0) && (line < (getLineCount() - 1)) ) -	{ -		new_line = line + 1; -	} - -	LLRect visible_region = getVisibleDocumentRect(); - -	S32 new_cursor_pos = getDocIndexFromLocalCoord(mDesiredXPixel, mLineInfoList[new_line].mRect.mBottom + mVisibleTextRect.mBottom - visible_region.mBottom, TRUE); -	setCursorPos(new_cursor_pos, true); +    if (new_line != line) +    { +        LLRect visible_region = getVisibleDocumentRect(); +        S32 new_cursor_pos = getDocIndexFromLocalCoord(mDesiredXPixel, +                                                       mLineInfoList[new_line].mRect.mBottom + mVisibleTextRect.mBottom - visible_region.mBottom, TRUE); +        setCursorPos(new_cursor_pos, true); +    }  }  bool LLTextBase::scrolledToStart() @@ -2910,6 +2948,15 @@ boost::signals2::connection LLTextBase::setURLClickedCallback(const commit_signa  	return mURLClickSignal->connect(cb);  } +boost::signals2::connection LLTextBase::setIsFriendCallback(const is_friend_signal_t::slot_type& cb) +{ +	if (!mIsFriendSignal) +	{ +		mIsFriendSignal = new is_friend_signal_t(); +	} +	return mIsFriendSignal->connect(cb); +} +  //  // LLTextSegment  // diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 20a73387b5..a74e97cac8 100755 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -258,6 +258,8 @@ public:  	friend class LLNormalTextSegment;  	friend class LLUICtrlFactory; +	typedef boost::signals2::signal<bool (const LLUUID& user_id)> is_friend_signal_t; +  	struct LineSpacingParams : public LLInitParam::ChoiceBlock<LineSpacingParams>  	{  		Alternative<F32>	multiple; @@ -434,6 +436,7 @@ public:  	virtual void			appendImageSegment(const LLStyle::Params& style_params);  	virtual void			appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo);  	boost::signals2::connection setURLClickedCallback(const commit_signal_t::slot_type& cb); +	boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb);  	void					setWordWrap(bool wrap);  	LLScrollContainer*		getScrollContainer() const { return mScroller; } @@ -507,7 +510,7 @@ protected:  	void							initFromParams(const Params& p);      virtual void					beforeValueChange();  	virtual void					onValueChange(S32 start, S32 end); -    virtual bool                    useLabel(); +    virtual bool                    useLabel() const;  	// draw methods  	void							drawSelectionBackground(); // draws the black box behind the selected text @@ -648,6 +651,9 @@ protected:  	// Fired when a URL link is clicked  	commit_signal_t*			mURLClickSignal; +	// Used to check if user with given ID is avatar's friend +	is_friend_signal_t*         mIsFriendSignal; +  	LLUIString					mLabel;	// text label that is visible when no user text provided  }; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 834f213097..d1c4bcb24b 100755 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1964,8 +1964,7 @@ void LLTextEditor::onFocusReceived()  	updateAllowingLanguageInput();  } -// virtual, from LLView -void LLTextEditor::onFocusLost() +void LLTextEditor::focusLostHelper()  {  	updateAllowingLanguageInput(); @@ -1982,7 +1981,11 @@ void LLTextEditor::onFocusLost()  	// Make sure cursor is shown again  	getWindow()->showCursorFromMouseMove(); +} +void LLTextEditor::onFocusLost() +{ +	focusLostHelper();  	LLTextBase::onFocusLost();  } @@ -2128,12 +2131,17 @@ void LLTextEditor::drawPreeditMarker()  					continue;  				} -				S32 preedit_left = mVisibleTextRect.mLeft; +				line_info& line = mLineInfoList[cur_line]; +				LLRect text_rect(line.mRect); +				text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents +				text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position + +				S32 preedit_left = text_rect.mLeft;  				if (left > line_start)  				{  					preedit_left += mFont->getWidth(text, line_start, left - line_start);  				} -				S32 preedit_right = mVisibleTextRect.mLeft; +				S32 preedit_right = text_rect.mLeft;  				if (right < line_end)  				{  					preedit_right += mFont->getWidth(text, line_start, right - line_start); @@ -2146,18 +2154,18 @@ void LLTextEditor::drawPreeditMarker()  				if (mPreeditStandouts[i])  				{  					gl_rect_2d(preedit_left + preedit_standout_gap, -							line_y + preedit_standout_position, -							preedit_right - preedit_standout_gap - 1, -							line_y + preedit_standout_position - preedit_standout_thickness, -							(mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); +							   text_rect.mBottom + mFont->getDescenderHeight() - 1, +							   preedit_right - preedit_standout_gap - 1, +							   text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, +							   (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f));  				}  				else  				{  					gl_rect_2d(preedit_left + preedit_marker_gap, -							line_y + preedit_marker_position, -							preedit_right - preedit_marker_gap - 1, -							line_y + preedit_marker_position - preedit_marker_thickness, -							(mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); +							   text_rect.mBottom + mFont->getDescenderHeight() - 1, +							   preedit_right - preedit_marker_gap - 1, +							   text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, +							   (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f));  				}  			}  		} @@ -2240,12 +2248,13 @@ void LLTextEditor::draw()  		LLRect clip_rect(mVisibleTextRect);  		clip_rect.stretch(1);  		LLLocalClipRect clip(clip_rect); -		drawPreeditMarker();  	}  	LLTextBase::draw();  	drawLineNumbers(); +    drawPreeditMarker(); +  	//RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret  	// when in readonly mode  	mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly); @@ -2695,14 +2704,20 @@ BOOL LLTextEditor::hasPreeditString() const  void LLTextEditor::resetPreedit()  { +    if (hasSelection()) +    { +		if (hasPreeditString()) +        { +            llwarns << "Preedit and selection!" << llendl; +            deselect(); +        } +        else +        { +            deleteSelection(TRUE); +        } +    }  	if (hasPreeditString())  	{ -		if (hasSelection()) -		{ -			llwarns << "Preedit and selection!" << llendl; -			deselect(); -		} -  		setCursorPos(mPreeditPositions.front());  		removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos);  		insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); @@ -2750,7 +2765,10 @@ void LLTextEditor::updatePreedit(const LLWString &preedit_string,  	{  		mPreeditOverwrittenWString.clear();  	} -	insertStringNoUndo(insert_preedit_at, mPreeditWString); +     +	segment_vec_t segments; +	//pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. +	insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments);   	mPreeditStandouts = preedit_standouts; diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 969e072704..13f63a17ef 100755 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -255,6 +255,7 @@ protected:  	S32				insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment);  	S32				remove(S32 pos, S32 length, bool group_with_next_op); +	void			focusLostHelper();  	void			updateAllowingLanguageInput();  	BOOL			hasPreeditString() const; diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index 3d9f5cbbc2..928e82cb8c 100755 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -381,7 +381,7 @@ bool LLToolBar::stopCommandInProgress(const LLCommandId& commandId)  	return (command_button != NULL);  } -bool LLToolBar::flashCommand(const LLCommandId& commandId, bool flash) +bool LLToolBar::flashCommand(const LLCommandId& commandId, bool flash, bool force_flashing/* = false */)  {  	LLButton * command_button = NULL; @@ -391,7 +391,7 @@ bool LLToolBar::flashCommand(const LLCommandId& commandId, bool flash)  		if (it != mButtonMap.end())  		{  			command_button = it->second; -			command_button->setFlashing(flash ? TRUE : FALSE); +			command_button->setFlashing((BOOL)(flash),(BOOL)(force_flashing));  		}  	} diff --git a/indra/llui/lltoolbar.h b/indra/llui/lltoolbar.h index 31424a36d4..743951a41f 100755 --- a/indra/llui/lltoolbar.h +++ b/indra/llui/lltoolbar.h @@ -192,7 +192,7 @@ public:  	bool hasCommand(const LLCommandId& commandId) const;	// is this command bound to a button in this toolbar  	bool enableCommand(const LLCommandId& commandId, bool enabled);	// enable/disable button bound to the specified command, if it exists in this toolbar  	bool stopCommandInProgress(const LLCommandId& commandId);	// stop command if it is currently active -	bool flashCommand(const LLCommandId& commandId, bool flash); // flash button associated with given command, if in this toolbar +	bool flashCommand(const LLCommandId& commandId, bool flash, bool force_flashing = false); // flash button associated with given command, if in this toolbar  	void setStartDragCallback(tool_startdrag_callback_t cb)   { mStartDragItemCallback  = cb; } // connects drag and drop behavior to external logic  	void setHandleDragCallback(tool_handledrag_callback_t cb) { mHandleDragItemCallback = cb; } diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index f51aeaec13..23e574cb74 100755 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -170,6 +170,30 @@ std::string LLUrlAction::getUserID(std::string url)  	return id_str;  } +std::string LLUrlAction::getObjectId(std::string url) +{ +	LLURI uri(url); +	LLSD path_array = uri.pathArray(); +	std::string id_str; +	if (path_array.size() >= 3) +	{ +		id_str = path_array.get(2).asString(); +	} +	return id_str; +} + +std::string LLUrlAction::getObjectName(std::string url) +{ +	LLURI uri(url); +	LLSD query_map = uri.queryMap(); +	std::string name; +	if (query_map.has("name")) +	{ +		name = query_map["name"].asString(); +	} +	return name; +} +  void LLUrlAction::sendIM(std::string url)  {  	std::string id_str = getUserID(url); @@ -188,3 +212,21 @@ void LLUrlAction::addFriend(std::string url)  	}  } +void LLUrlAction::removeFriend(std::string url) +{ +	std::string id_str = getUserID(url); +	if (LLUUID::validate(id_str)) +	{ +		executeSLURL("secondlife:///app/agent/" + id_str + "/removefriend"); +	} +} + +void LLUrlAction::blockObject(std::string url) +{ +	std::string object_id = getObjectId(url); +	std::string object_name = getObjectName(url); +	if (LLUUID::validate(object_id)) +	{ +		executeSLURL("secondlife:///app/agent/" + object_id + "/block/" + object_name); +	} +} diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index e31cd71a20..e731376b95 100755 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -77,8 +77,12 @@ public:  	/// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile  	static void showProfile(std::string url);  	static std::string getUserID(std::string url); +	static std::string getObjectName(std::string url); +	static std::string getObjectId(std::string url);  	static void sendIM(std::string url);  	static void addFriend(std::string url); +	static void removeFriend(std::string url); +	static void blockObject(std::string url);  	/// specify the callbacks to enable this class's functionality  	typedef boost::function<void (const std::string&)> url_callback_t; diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 99ee688888..b1cc502c4b 100755 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -504,6 +504,10 @@ std::string localize_slapp_label(const std::string& url, const std::string& full  	{  		return LLTrans::getString("SLappAgentRequestFriend") + " " + full_name;  	} +	if (LLStringUtil::endsWith(url, "/removefriend")) +	{ +		return LLTrans::getString("SLappAgentRemoveFriend") + " " + full_name; +	}  	return full_name;  } diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 43c0090993..30f5526500 100755 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -159,9 +159,8 @@ LLWinImm LLWinImm::sTheInstance;  LLWinImm::LLWinImm() : mHImmDll(NULL)  {  	// Check system metrics  -	if ( !GetSystemMetrics( SM_DBCSENABLED ) ) +	if ( !GetSystemMetrics( SM_IMMENABLED ) )  		return; -	  	mHImmDll = LoadLibraryA("Imm32");  	if (mHImmDll != NULL) @@ -3500,19 +3499,11 @@ void LLWindowWin32::updateLanguageTextInputArea()  void LLWindowWin32::interruptLanguageTextInput()  { -	if (mPreeditor) +	if (mPreeditor && LLWinImm::isAvailable())  	{ -		if (LLWinImm::isAvailable()) -		{ -			HIMC himc = LLWinImm::getContext(mWindowHandle); -			LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); -			LLWinImm::releaseContext(mWindowHandle, himc); -		} - -		// Win32 document says there will be no composition string -		// after NI_COMPOSITIONSTR returns.  The following call to -		// resetPreedit should be a NOP unless IME goes mad... -		mPreeditor->resetPreedit(); +		HIMC himc = LLWinImm::getContext(mWindowHandle); +		LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); +		LLWinImm::releaseContext(mWindowHandle, himc);  	}  } diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 344079b640..515199604b 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3489,16 +3489,27 @@          <key>Value</key>              <real>10.0</real>          </map> -    <key>FilterItemsPerFrame</key> +    <key>FilterItemsMaxTimePerFrameVisible</key>      <map> -      <key>Comment</key> -      <string>Maximum number of inventory items to match against search filter every frame (lower to increase framerate while searching, higher to improve search speed)</string> -      <key>Persist</key> -      <integer>1</integer> -      <key>Type</key> -      <string>S32</string> -      <key>Value</key> -      <integer>500</integer> +        <key>Comment</key> +        <string>Max time devoted to items filtering per frame for visible inventory listings (in milliseconds)</string> +        <key>Persist</key> +        <integer>1</integer> +        <key>Type</key> +        <string>S32</string> +        <key>Value</key> +        <integer>10</integer> +    </map> +    <key>FilterItemsMaxTimePerFrameUnvisible</key> +    <map> +        <key>Comment</key> +        <string>Max time devoted to items filtering per frame for non visible inventory listings (in milliseconds)</string> +        <key>Persist</key> +        <integer>1</integer> +        <key>Type</key> +        <string>S32</string> +        <key>Value</key> +        <integer>1</integer>      </map>      <key>FindLandArea</key>      <map> @@ -6430,7 +6441,10 @@      <key>NotificationConferenceIMOptions</key>      <map>        <key>Comment</key> -      <string>Specifies how the UI responds to Conference IM Notifications.</string> +      <string> +        Specifies how the UI responds to Conference IM Notifications. +        Allowed values: [openconversations,toast,flash,noaction] +      </string>        <key>Persist</key>        <integer>1</integer>        <key>Type</key> @@ -6441,7 +6455,10 @@      <key>NotificationFriendIMOptions</key>      <map>        <key>Comment</key> -      <string>Specifies how the UI responds to Friend IM Notifications.</string> +      <string> +        Specifies how the UI responds to Friend IM Notifications. +        Allowed values: [openconversations,toast,flash,noaction] +      </string>        <key>Persist</key>        <integer>1</integer>        <key>Type</key> @@ -6452,7 +6469,10 @@      <key>NotificationGroupChatOptions</key>      <map>        <key>Comment</key> -      <string>Specifies how the UI responds to Group Chat Notifications.</string> +      <string> +        Specifies how the UI responds to Group Chat Notifications. +        Allowed values: [openconversations,toast,flash,noaction] +      </string>        <key>Persist</key>        <integer>1</integer>        <key>Type</key> @@ -6463,7 +6483,10 @@      <key>NotificationNearbyChatOptions</key>      <map>        <key>Comment</key> -      <string>Specifies how the UI responds to Nearby Chat Notifications.</string> +      <string> +        Specifies how the UI responds to Nearby Chat Notifications. +        Allowed values: [openconversations,toast,flash,noaction] +      </string>        <key>Persist</key>        <integer>1</integer>        <key>Type</key> @@ -6474,7 +6497,24 @@      <key>NotificationNonFriendIMOptions</key>      <map>        <key>Comment</key> -      <string>Specifies how the UI responds to Non Friend IM Notifications.</string> +      <string> +        Specifies how the UI responds to Non Friend IM Notifications. +        Allowed values: [openconversations,toast,flash,noaction] +      </string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string>toast</string> +    </map>   +    <key>NotificationObjectIMOptions</key> +    <map> +      <key>Comment</key> +      <string> +        Specifies how the UI responds to Object IM Notifications. +        Allowed values: [openconversations,toast,flash,noaction] +      </string>        <key>Persist</key>        <integer>1</integer>        <key>Type</key> @@ -7020,6 +7060,72 @@        <key>Value</key>        <integer>0</integer>      </map>   +    <key>PlaySoundFriendIM</key> +    <map> +      <key>Comment</key> +      <string>Plays a sound when friend's IM received.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map> +    <key>PlaySoundNonFriendIM</key> +    <map> +      <key>Comment</key> +      <string>Plays a sound when non-friend's IM received.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map> +    <key>PlaySoundConferenceIM</key> +    <map> +      <key>Comment</key> +      <string>Plays a sound when conference IM received.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map> +    <key>PlaySoundGroupChatIM</key> +    <map> +      <key>Comment</key> +      <string>Plays a sound when group chat IM received.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map> +    <key>PlaySoundNearbyChatIM</key> +    <map> +      <key>Comment</key> +      <string>Plays a sound when nearby chat IM received.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map> +    <key>PlaySoundObjectIM</key> +    <map> +      <key>Comment</key> +      <string>Plays a sound when IM fom an object received.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map>      <key>PlaySoundNewConversation</key>      <map>        <key>Comment</key> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 3e94c5edf7..f960b31cc7 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -46,6 +46,7 @@  #include "llenvmanager.h"  #include "llfirstuse.h"  #include "llfloatercamera.h" +#include "llfloaterimcontainer.h"  #include "llfloaterreg.h"  #include "llfloatertools.h"  #include "llgroupactions.h" @@ -91,6 +92,7 @@  #include "llworld.h"  #include "llworldmap.h"  #include "stringize.h" +#include "boost/foreach.hpp"  using namespace LLAvatarAppearanceDefines; @@ -2037,7 +2039,16 @@ void LLAgent::endAnimationUpdateUI()  			{  				skip_list.insert(LLFloaterReg::findInstance("mini_map"));  			} -		 + +			LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container"); +			LLFloaterIMContainer::floater_list_t conversations; +			im_box->getDetachedConversationFloaters(conversations); +			BOOST_FOREACH(LLFloater* conversation, conversations) +			{ +				llinfos << "skip_list.insert(session_floater): " << conversation->getTitle() << llendl; +				skip_list.insert(conversation); +			} +  			gFloaterView->popVisibleAll(skip_list);  #endif  			mViewsPushed = FALSE; diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp index 43757d0174..8b2d9e639f 100755 --- a/indra/newview/llchannelmanager.cpp +++ b/indra/newview/llchannelmanager.cpp @@ -139,8 +139,6 @@ void LLChannelManager::onLoginCompleted()  	}  	LLPersistentNotificationStorage::getInstance()->loadNotifications(); - -	LLDoNotDisturbNotificationStorage::getInstance()->initialize();  	LLDoNotDisturbNotificationStorage::getInstance()->loadNotifications();  } diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 0f138873ac..af3c6eff11 100755 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -628,6 +628,7 @@ LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)  	editor_params.enabled = false; // read only  	editor_params.show_context_menu = "true";  	mEditor = LLUICtrlFactory::create<LLTextEditor>(editor_params, this); +	mEditor->setIsFriendCallback(LLAvatarActions::isFriend);  }  LLSD LLChatHistory::getValue() const diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index a1a9463d43..fd4f17b694 100755 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -323,12 +323,11 @@ BOOL	LLFloaterIMNearbyChatToastPanel::handleMouseUp	(S32 x, S32 y, MASK mask)  			return TRUE;  		else  		{ -			(LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"))->showHistory(); +			LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat")->showHistory();  			return FALSE;  		}  	} - -	(LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"))->showHistory(); +	LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat")->showHistory();  	return LLPanel::handleMouseUp(x,y,mask);  } diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index c74ce24872..192a594c9d 100755 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -363,7 +363,10 @@ void LLConversationItemSession::buildContextMenu(LLMenuGL& menu, U32 flags)      lldebugs << "LLConversationItemParticipant::buildContextMenu()" << llendl;      menuentry_vec_t items;      menuentry_vec_t disabled_items; - +    if((flags & ITEM_IN_MULTI_SELECTION) && (this->getType() != CONV_SESSION_NEARBY)) +    { +    	items.push_back(std::string("close_selected_conversations")); +    }      if(this->getType() == CONV_SESSION_1_ON_1)      {          items.push_back(std::string("close_conversation")); @@ -386,6 +389,10 @@ void LLConversationItemSession::buildContextMenu(LLMenuGL& menu, U32 flags)          addVoiceOptions(items);          items.push_back(std::string("chat_history"));      } +    else if(this->getType() == CONV_SESSION_NEARBY) +    { +        items.push_back(std::string("chat_history")); +    }      hide_context_entries(menu, items, disabled_items);  } diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h index 8766585049..d8cdcdfc97 100755 --- a/indra/newview/llconversationmodel.h +++ b/indra/newview/llconversationmodel.h @@ -252,11 +252,10 @@ public:  	const std::string& 	getName() const { return mEmpty; }  	const std::string& 	getFilterText() { return mEmpty; }  	void 				setModified(EFilterModified behavior = FILTER_RESTART) { } -		 -	void 				setFilterCount(S32 count) { } -	S32 				getFilterCount() const { return 0; } -	void 				decrementFilterCount() { } -		 + +  	void 				resetTime(S32 timeout) { } +    bool                isTimedOut() { return false; } +     	bool 				isDefault() const { return true; }  	bool 				isNotDefault() const { return false; }  	void 				markDefault() { } diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index b6c53e5e30..9faa12b2ee 100755 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -118,9 +118,19 @@ void LLConversationViewSession::setFlashState(bool flash_state)  	mFlashTimer->stopFlashing();  } +void LLConversationViewSession::setHighlightState(bool hihglight_state) +{ +	mFlashStateOn = hihglight_state; +	mFlashStarted = true; +	mFlashTimer->stopFlashing(); +} +  void LLConversationViewSession::startFlashing()  { -	if (isInVisibleChain() && mFlashStateOn && !mFlashStarted) +	LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container"); + +	// Need to start flashing only when "Conversations" is opened or brought on top +	if (isInVisibleChain() && !im_box->isMinimized() && mFlashStateOn && !mFlashStarted)  	{  		mFlashStarted = true;  		mFlashTimer->startFlashing(); @@ -263,6 +273,29 @@ BOOL LLConversationViewSession::handleMouseDown( S32 x, S32 y, MASK mask )  	return result;  } +BOOL LLConversationViewSession::handleMouseUp( S32 x, S32 y, MASK mask ) +{ +	BOOL result = LLFolderViewFolder::handleMouseUp(x, y, mask); + +	LLFloater* volume_floater = LLFloaterReg::findInstance("floater_voice_volume"); +	LLFloater* chat_volume_floater = LLFloaterReg::findInstance("chat_voice"); +	if (result  +		&& getRoot() +		&& !(volume_floater && volume_floater->isShown() && volume_floater->hasFocus()) +		&& !(chat_volume_floater && chat_volume_floater->isShown() && chat_volume_floater->hasFocus())) +	{ +		LLConversationItem* item = dynamic_cast<LLConversationItem *>(getViewModelItem()); +		LLUUID session_id = item? item->getUUID() : LLUUID(); +		LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(session_id); +		if(!session_floater->hasFocus()) +		{ +			session_floater->setFocus(true); +		} +    } + +	return result; +} +  BOOL LLConversationViewSession::handleRightMouseDown( S32 x, S32 y, MASK mask )  {      BOOL result = LLFolderViewFolder::handleRightMouseDown(x, y, mask); @@ -340,16 +373,20 @@ void LLConversationViewSession::setVisibleIfDetached(BOOL visible)  {  	// Do this only if the conversation floater has been torn off (i.e. no multi floater host) and is not minimized  	// Note: minimized dockable floaters are brought to front hence unminimized when made visible and we don't want that here -	LLFolderViewModelItem* item = mViewModelItem; -	LLUUID session_uuid = dynamic_cast<LLConversationItem*>(item)->getUUID(); -	LLFloater* session_floater = LLFloaterIMSessionTab::getConversation(session_uuid); -	 -	if (session_floater && !session_floater->getHost() && !session_floater->isMinimized()) +	LLFloater* session_floater = getSessionFloater(); +	if (session_floater && session_floater->isDetachedAndNotMinimized())  	{  		session_floater->setVisible(visible);  	}  } +LLFloater* LLConversationViewSession::getSessionFloater() +{ +	LLFolderViewModelItem* item = mViewModelItem; +	LLUUID session_uuid = dynamic_cast<LLConversationItem*>(item)->getUUID(); +	return LLFloaterIMSessionTab::getConversation(session_uuid); +} +  LLConversationViewParticipant* LLConversationViewSession::findParticipant(const LLUUID& participant_id)  {  	// This is *not* a general tree parsing algorithm. We search only in the mItems list diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h index 3eb2e63792..5a74974302 100755 --- a/indra/newview/llconversationview.h +++ b/indra/newview/llconversationview.h @@ -69,6 +69,7 @@ public:  	/*virtual*/ void draw();  	/*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask );  	/*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); +	/*virtual*/ BOOL handleMouseUp( S32 x, S32 y, MASK mask );  	/*virtual*/ S32 arrange(S32* width, S32* height); @@ -86,6 +87,9 @@ public:  	virtual void refresh();  	/*virtual*/ void setFlashState(bool flash_state); +	void setHighlightState(bool hihglight_state); + +	LLFloater* getSessionFloater();  private: diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp index 82affcf068..495cd01349 100755 --- a/indra/newview/lldonotdisturbnotificationstorage.cpp +++ b/indra/newview/lldonotdisturbnotificationstorage.cpp @@ -70,7 +70,7 @@ BOOL LLDoNotDisturbNotificationStorageTimer::tick()  LLDoNotDisturbNotificationStorage::LLDoNotDisturbNotificationStorage()  	: LLSingleton<LLDoNotDisturbNotificationStorage>() -	, LLNotificationStorage(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "dnd_notifications.xml")) +	, LLNotificationStorage("")      , mDirty(false)  {      nameToPayloadParameterMap[toastName] = "SESSION_ID"; @@ -83,6 +83,7 @@ LLDoNotDisturbNotificationStorage::~LLDoNotDisturbNotificationStorage()  void LLDoNotDisturbNotificationStorage::initialize()  { +	setFileName(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "dnd_notifications.xml"));  	getCommunicationChannel()->connectFailedFilter(boost::bind(&LLDoNotDisturbNotificationStorage::onChannelChanged, this, _1));  } @@ -115,7 +116,8 @@ void LLDoNotDisturbNotificationStorage::saveNotifications()  	{  		LLNotificationPtr notificationPtr = historyIter->second; -		if (!notificationPtr->isRespondedTo() && !notificationPtr->isCancelled() && !notificationPtr->isExpired()) +		if (!notificationPtr->isRespondedTo() && !notificationPtr->isCancelled() && +			!notificationPtr->isExpired() && !notificationPtr->isPersistent())  		{  			data.append(notificationPtr->asLLSD(true));  		} @@ -210,12 +212,8 @@ void LLDoNotDisturbNotificationStorage::loadNotifications()  	} -    if(imToastExists) -    { -        LLFloaterReg::showInstance("im_container"); -    } - -	if(group_ad_hoc_toast_exists) +    bool isConversationLoggingAllowed = gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 0; +	if(group_ad_hoc_toast_exists && isConversationLoggingAllowed)  	{  		LLFloaterReg::showInstance("conversation");  	} @@ -266,11 +264,6 @@ void LLDoNotDisturbNotificationStorage::updateNotifications()          }      } -    if(imToastExists) -    {    -        LLFloaterReg::showInstance("im_container"); -    } -      if(imToastExists || offerExists)      {          make_ui_sound("UISndNewIncomingIMSession"); diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 6d90667194..b35ef3a961 100755 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -400,6 +400,8 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)  	mMoreTextBox->setClickedCallback(boost::bind(&LLFavoritesBarCtrl::showDropDownMenu, this));  	addChild(mMoreTextBox); +	mDropDownItemsCount = 0; +  	LLTextBox::Params label_param(p.label);  	mBarLabel = LLUICtrlFactory::create<LLTextBox> (label_param);  	addChild(mBarLabel); @@ -820,11 +822,13 @@ void LLFavoritesBarCtrl::updateButtons()  		}  		// Update overflow menu  		LLToggleableMenu* overflow_menu = static_cast <LLToggleableMenu*> (mOverflowMenuHandle.get()); -		if (overflow_menu && overflow_menu->getVisible()) +		if (overflow_menu && overflow_menu->getVisible() && (overflow_menu->getItemCount() != mDropDownItemsCount))  		{  			overflow_menu->setVisible(FALSE);  			if (mUpdateDropDownItems) +			{  				showDropDownMenu(); +			}  		}  	}  	else @@ -940,6 +944,7 @@ void LLFavoritesBarCtrl::showDropDownMenu()  		menu->updateParent(LLMenuGL::sMenuContainer);  		menu->setButtonRect(mMoreTextBox->getRect(), this);  		positionAndShowMenu(menu); +		mDropDownItemsCount = menu->getItemCount();  	}  } diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index f06e9b9b64..211d3c4ce3 100755 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -101,6 +101,7 @@ protected:  	LLUUID mFavoriteFolderId;  	const LLFontGL *mFont;  	S32 mFirstDropDownItem; +	S32 mDropDownItemsCount;  	bool mUpdateDropDownItems;  	bool mRestoreOverflowMenu; diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 113aa9a8f2..c0afb72cff 100755 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -513,6 +513,7 @@ void LLFloaterAvatarPicker::find()  			url += "/";  		}  		url += "?page_size=100&names="; +		std::replace(text.begin(), text.end(), '.', ' ');  		url += LLURI::escape(text);  		llinfos << "avatar picker " << url << llendl;  		LLHTTPClient::get(url, new LLAvatarPickerResponder(mQueryID, getKey().asString())); @@ -748,7 +749,12 @@ void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD&  		{  			getChildView("ok_btn")->setEnabled(true);  			search_results->setEnabled(true); -			search_results->selectFirstItem(); +			search_results->sortByColumnIndex(1, TRUE); +			std::string text = getChild<LLUICtrl>("Edit")->getValue().asString(); +			if (!search_results->selectItemByLabel(text, TRUE, 1)) +			{ +				search_results->selectFirstItem(); +			}			  			onList();  			search_results->setFocus(TRUE);  		} diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp index a3d715530d..1a3fa27593 100755 --- a/indra/newview/llfloaterconversationpreview.cpp +++ b/indra/newview/llfloaterconversationpreview.cpp @@ -50,6 +50,7 @@ LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_i  BOOL LLFloaterConversationPreview::postBuild()  {  	mChatHistory = getChild<LLChatHistory>("chat_history"); +	LLLoadHistoryThread::setLoadEndSignal(boost::bind(&LLFloaterConversationPreview::SetPages, this, _1, _2));  	const LLConversation* conv = LLConversationLog::instance().getConversation(mSessionID);  	std::string name; @@ -70,7 +71,7 @@ BOOL LLFloaterConversationPreview::postBuild()  		name = LLTrans::getString("NearbyChatTitle");  		file = "chat";  	} - +	mChatHistoryFileName = file;  	LLStringUtil::format_map_t args;  	args["[NAME]"] = name;  	std::string title = getString("Title", args); @@ -80,23 +81,46 @@ BOOL LLFloaterConversationPreview::postBuild()  	load_params["load_all_history"] = true;  	load_params["cut_off_todays_date"] = false; -	LLLogChat::loadChatHistory(file, mMessages, load_params); -	mCurrentPage = mMessages.size() / mPageSize; +	LLSD loading; +	loading[LL_IM_TEXT] = LLTrans::getString("loading_chat_logs"); +	mMessages.push_back(loading);  	mPageSpinner = getChild<LLSpinCtrl>("history_page_spin");  	mPageSpinner->setCommitCallback(boost::bind(&LLFloaterConversationPreview::onMoreHistoryBtnClick, this));  	mPageSpinner->setMinValue(1); -	mPageSpinner->setMaxValue(mCurrentPage + 1); -	mPageSpinner->set(mCurrentPage + 1); - -	std::string total_page_num = llformat("/ %d", mCurrentPage + 1); -	getChild<LLTextBox>("page_num_label")->setValue(total_page_num); - +	mPageSpinner->set(1); +	mPageSpinner->setEnabled(false); +	mChatHistoryLoaded = false; +	LLLogChat::startChatHistoryThread(file, load_params);  	return LLFloater::postBuild();  } +void LLFloaterConversationPreview::SetPages(std::list<LLSD>& messages, const std::string& file_name) +{ +	if(file_name == mChatHistoryFileName) +	{ +		mMessages = messages; + + +		mCurrentPage = mMessages.size() / mPageSize; +		mPageSpinner->setEnabled(true); +		mPageSpinner->setMaxValue(mCurrentPage+1); +		mPageSpinner->set(mCurrentPage+1); + +		std::string total_page_num = llformat("/ %d", mCurrentPage+1); +		getChild<LLTextBox>("page_num_label")->setValue(total_page_num); +		mChatHistoryLoaded = true; + +	} + +}  void LLFloaterConversationPreview::draw()  { +	if(mChatHistoryLoaded) +	{ +		showHistory(); +		mChatHistoryLoaded = false; +	}  	LLFloater::draw();  } diff --git a/indra/newview/llfloaterconversationpreview.h b/indra/newview/llfloaterconversationpreview.h index b17ae84b63..389f3dfd09 100755 --- a/indra/newview/llfloaterconversationpreview.h +++ b/indra/newview/llfloaterconversationpreview.h @@ -42,6 +42,7 @@ public:  	virtual ~LLFloaterConversationPreview(){};  	virtual BOOL postBuild(); +	void SetPages(std::list<LLSD>& messages,const std::string& file_name);  	virtual void draw();  	virtual void onOpen(const LLSD& key); @@ -59,6 +60,8 @@ private:  	std::list<LLSD> mMessages;  	std::string		mAccountName;  	std::string		mCompleteName; +	std::string     mChatHistoryFileName; +	bool			mChatHistoryLoaded;  };  #endif /* LLFLOATERCONVERSATIONPREVIEW_H_ */ diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index b40789db9c..4591b80ac4 100755 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -47,6 +47,7 @@  #include "llfloaterpreference.h"  #include "llimview.h"  #include "llnotificationsutil.h" +#include "lltoolbarview.h"  #include "lltransientfloatermgr.h"  #include "llviewercontrol.h"  #include "llconversationview.h" @@ -54,6 +55,7 @@  #include "llworld.h"  #include "llsdserialize.h"  #include "llviewerobjectlist.h" +#include "boost/foreach.hpp"  //  // LLFloaterIMContainer @@ -63,7 +65,8 @@ LLFloaterIMContainer::LLFloaterIMContainer(const LLSD& seed, const Params& param  	mExpandCollapseBtn(NULL),  	mConversationsRoot(NULL),  	mConversationsEventStream("ConversationsEvents"), -	mInitialized(false) +	mInitialized(false), +	mIsFirstLaunch(true)  {      mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLFloaterIMContainer::isActionChecked, this, _2));  	mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLFloaterIMContainer::onCustomAction,  this, _2)); @@ -113,6 +116,10 @@ void LLFloaterIMContainer::sessionAdded(const LLUUID& session_id, const std::str  void LLFloaterIMContainer::sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id)  { +	if(!isInVisibleChain()) +	{ +		setVisibleAndFrontmost(false); +	}  	selectConversationPair(session_id, true);  	collapseMessagesPane(false);  } @@ -204,6 +211,7 @@ BOOL LLFloaterIMContainer::postBuild()  	// a scroller for folder view  	LLRect scroller_view_rect = mConversationsListPanel->getRect();  	scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); +	scroller_view_rect.mBottom += getChild<LLLayoutStack>("conversations_pane_buttons_stack")->getRect().getHeight();  	LLScrollContainer::Params scroller_params(LLUICtrlFactory::getDefaultParams<LLFolderViewScrollContainer>());  	scroller_params.rect(scroller_view_rect); @@ -221,7 +229,8 @@ BOOL LLFloaterIMContainer::postBuild()  	mExpandCollapseBtn->setClickedCallback(boost::bind(&LLFloaterIMContainer::onExpandCollapseButtonClicked, this));  	mStubCollapseBtn = getChild<LLButton>("stub_collapse_btn");  	mStubCollapseBtn->setClickedCallback(boost::bind(&LLFloaterIMContainer::onStubCollapseButtonClicked, this)); -	getChild<LLButton>("speak_btn")->setClickedCallback(boost::bind(&LLFloaterIMContainer::onSpeakButtonClicked, this)); +    mSpeakBtn = getChild<LLButton>("speak_btn"); +	mSpeakBtn->setClickedCallback(boost::bind(&LLFloaterIMContainer::onSpeakButtonClicked, this));  	childSetAction("add_btn", boost::bind(&LLFloaterIMContainer::onAddButtonClicked, this)); @@ -258,7 +267,6 @@ BOOL LLFloaterIMContainer::postBuild()  void LLFloaterIMContainer::onOpen(const LLSD& key)  {  	LLMultiFloater::onOpen(key); -	openNearbyChat();  	reSelectConversation();  	assignResizeLimits();  } @@ -593,6 +601,7 @@ void LLFloaterIMContainer::setMinimized(BOOL b)  	//Switching from minimized to un-minimized  	if(was_minimized && !b)  	{ +		gToolBarView->flashCommand(LLCommandId("chat"), false);  		LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(mSelectedSession);  		if(session_floater && !session_floater->isTornOff()) @@ -621,7 +630,6 @@ void LLFloaterIMContainer::setVisible(BOOL visible)  			LLFloaterReg::toggleInstanceOrBringToFront(name);              selectConversationPair(LLUUID(NULL), false, false);  		} -		openNearbyChat();  		flashConversationItemWidget(mSelectedSession,false);  		LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(mSelectedSession); @@ -651,7 +659,11 @@ void LLFloaterIMContainer::setVisible(BOOL visible)  		LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(widget_it->second);  		if (widget)  		{ -		    widget->setVisibleIfDetached(visible); +			LLFloater* session_floater = widget->getSessionFloater(); +			if (session_floater != nearby_chat) +			{ +				widget->setVisibleIfDetached(visible); +			}  		}  	} @@ -659,10 +671,37 @@ void LLFloaterIMContainer::setVisible(BOOL visible)  	LLMultiFloater::setVisible(visible);  } +void LLFloaterIMContainer::getDetachedConversationFloaters(floater_list_t& floaters) +{ +	typedef conversations_widgets_map::value_type conv_pair; +	BOOST_FOREACH(conv_pair item, mConversationsWidgets) +	{ +		LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(item.second); +		if (widget) +		{ +			LLFloater* session_floater = widget->getSessionFloater(); +			if (session_floater && session_floater->isDetachedAndNotMinimized()) +			{ +				floaters.push_back(session_floater); +			} +		} +	} +} +  void LLFloaterIMContainer::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key)  {  	LLMultiFloater::setVisibleAndFrontmost(take_focus, key); -    selectConversationPair(getSelectedSession(), false, take_focus); +	// Do not select "Nearby Chat" conversation, since it will bring its window to front +	// Only select other sessions +	if (!getSelectedSession().isNull()) +	{ +		selectConversationPair(getSelectedSession(), false, take_focus); +	} +	if (mInitialized && mIsFirstLaunch) +	{ +		collapseMessagesPane(gSavedPerAccountSettings.getBOOL("ConversationsMessagePaneCollapsed")); +		mIsFirstLaunch = false; +	}  }  void LLFloaterIMContainer::updateResizeLimits() @@ -779,13 +818,6 @@ void LLFloaterIMContainer::reshapeFloaterAndSetResizeLimits(bool collapse, S32 d  	setCanMinimize(at_least_one_panel_is_expanded);      assignResizeLimits(); - -    // force set correct size for the title after show/hide minimize button -	LLRect cur_rect = getRect(); -	LLRect force_rect = cur_rect; -	force_rect.mRight = cur_rect.mRight + 1; -    setRect(force_rect); -    setRect(cur_rect);  }  void LLFloaterIMContainer::assignResizeLimits() @@ -793,15 +825,12 @@ void LLFloaterIMContainer::assignResizeLimits()  	bool is_conv_pane_expanded = !mConversationsPane->isCollapsed();  	bool is_msg_pane_expanded = !mMessagesPane->isCollapsed(); -	// With two panels visible number of borders is three, because the borders -	// between the panels are merged into one -    S32 number_of_visible_borders = llmin((is_conv_pane_expanded? 2 : 0) + (is_msg_pane_expanded? 2 : 0), 3); -    S32 summary_width_of_visible_borders = number_of_visible_borders * LLPANEL_BORDER_WIDTH; -	S32 conv_pane_target_width = is_conv_pane_expanded? -			(is_msg_pane_expanded? -					mConversationsPane->getRect().getWidth() -					: mConversationsPane->getExpandedMinDim()) -			: mConversationsPane->getMinDim(); +    S32 summary_width_of_visible_borders = (is_msg_pane_expanded ? mConversationsStack->getPanelSpacing() : 0) + 1; + +	S32 conv_pane_target_width = is_conv_pane_expanded +		? ( is_msg_pane_expanded?mConversationsPane->getRect().getWidth():mConversationsPane->getExpandedMinDim() ) +		: mConversationsPane->getMinDim(); +  	S32 msg_pane_min_width  = is_msg_pane_expanded ? mMessagesPane->getExpandedMinDim() : 0;  	S32 new_min_width = conv_pane_target_width + msg_pane_min_width + summary_width_of_visible_borders; @@ -961,11 +990,11 @@ void LLFloaterIMContainer::setSortOrder(const LLConversationSort& order)  			conversation_floater->setSortOrder(order);  		}  	} -	 +  	gSavedSettings.setU32("ConversationSortOrder", (U32)order);  } -void LLFloaterIMContainer::getSelectedUUIDs(uuid_vec_t& selected_uuids) +void LLFloaterIMContainer::getSelectedUUIDs(uuid_vec_t& selected_uuids, bool participant_uuids/* = true*/)  {      const std::set<LLFolderViewItem*> selectedItems = mConversationsRoot->getSelectionList(); @@ -978,7 +1007,7 @@ void LLFloaterIMContainer::getSelectedUUIDs(uuid_vec_t& selected_uuids)          conversationItem = static_cast<LLConversationItem *>((*it)->getViewModelItem());  		//When a one-on-one conversation exists, retrieve the participant id from the conversation floater -		if(conversationItem->getType() == LLConversationItem::CONV_SESSION_1_ON_1) +		if(conversationItem->getType() == LLConversationItem::CONV_SESSION_1_ON_1 && participant_uuids)  		{  			LLFloaterIMSession * conversation_floaterp = LLFloaterIMSession::findInstance(conversationItem->getUUID());  			LLUUID participant_id = conversation_floaterp->getOtherParticipantUUID(); @@ -1133,6 +1162,11 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,          {              LLFloater::onClickClose(conversationFloater);          } +        else if("close_selected_conversations" == command) +        { +        	getSelectedUUIDs(selectedIDS,false); +        	closeSelectedConversations(selectedIDS); +        }          else if("open_voice_conversation" == command)          {              gIMMgr->startCall(conversationItem->getUUID()); @@ -1143,7 +1177,7 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,          }          else if("chat_history" == command)          { -			if (selectedIDS.size() > 0) +        	if (selectedIDS.size() > 0)  			{  				LLAvatarActions::viewChatHistory(selectedIDS.front());  			} @@ -1156,6 +1190,17 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,          	}          }      } +    //if there is no LLFloaterIMSession* instance for selected conversation it might be Nearby chat +    else +    { +    	if(conversationItem->getType() == LLConversationItem::CONV_SESSION_NEARBY) +    	{ +    		if("chat_history" == command) +    	    { +    	      	LLFloaterReg::showInstance("preview_conversation", LLSD(LLUUID::null), true); +    	    } +    	} +    }  }  void LLFloaterIMContainer::doToSelected(const LLSD& userdata) @@ -1185,7 +1230,7 @@ void LLFloaterIMContainer::doToSelectedGroup(const LLSD& userdata)      if (action == "group_profile")      { -        LLGroupActions::show(mSelectedSession); +    	LLGroupActions::show(mSelectedSession);      }      else if (action == "activate_group")      { @@ -1211,7 +1256,19 @@ bool LLFloaterIMContainer::enableContextMenuItem(const LLSD& userdata)  	//Enable Chat history item for ad-hoc and group conversations  	if ("can_chat_history" == item && uuids.size() > 0)  	{ -		return LLLogChat::isTranscriptExist(uuids.front()); +		//Disable menu item if selected participant is user agent +		if(uuids.front() != gAgentID) +		{ +			if (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_NEARBY) +			{ +				return LLLogChat::isNearbyTranscriptExist(); +			} +			else +			{ +				bool is_group = (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_GROUP); +				return LLLogChat::isTranscriptExist(uuids.front(),is_group); +			} +		}  	}  	// If nothing is selected(and selected item is not group chat), everything needs to be disabled @@ -1886,13 +1943,6 @@ void LLFloaterIMContainer::openNearbyChat()  	}  } -void LLFloaterIMContainer::onNearbyChatClosed() -{ -	// If nearby chat is the only remaining conversation and it is closed, close whole conversation floater as well -	if (mConversationsItems.size() == 1) -		closeFloater(); -} -  void LLFloaterIMContainer::reSelectConversation()  {  	LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(mSelectedSession); @@ -1904,7 +1954,6 @@ void LLFloaterIMContainer::reSelectConversation()  void LLFloaterIMContainer::updateSpeakBtnState()  { -	LLButton* mSpeakBtn = getChild<LLButton>("speak_btn");  	mSpeakBtn->setToggleState(LLVoiceClient::getInstance()->getUserPTTState());  	mSpeakBtn->setEnabled(LLAgent::isActionAllowed("speak"));  } @@ -1925,6 +1974,17 @@ void LLFloaterIMContainer::flashConversationItemWidget(const LLUUID& session_id,  	}  } +void LLFloaterIMContainer::highlightConversationItemWidget(const LLUUID& session_id, bool is_highlighted) +{ +	//Finds the conversation line item to highlight using the session_id +	LLConversationViewSession * widget = dynamic_cast<LLConversationViewSession *>(get_ptr_in_map(mConversationsWidgets,session_id)); + +	if (widget) +	{ +		widget->setHighlightState(is_highlighted); +	} +} +  bool LLFloaterIMContainer::isScrolledOutOfSight(LLConversationViewSession* conversation_item_widget)  {  	llassert(conversation_item_widget != NULL); @@ -1940,23 +2000,28 @@ bool LLFloaterIMContainer::isScrolledOutOfSight(LLConversationViewSession* conve  BOOL LLFloaterIMContainer::handleKeyHere(KEY key, MASK mask )  { +	BOOL handled = FALSE; +  	if(mask == MASK_ALT)  	{  		if (KEY_RETURN == key )  		{  			expandConversation(); +			handled = TRUE;  		}  		if ((KEY_DOWN == key ) || (KEY_RIGHT == key))  		{  			selectNextorPreviousConversation(true); +			handled = TRUE;  		}  		if ((KEY_UP == key) || (KEY_LEFT == key))  		{  			selectNextorPreviousConversation(false); +			handled = TRUE;  		}  	} -	return TRUE; +	return handled;  }  bool LLFloaterIMContainer::selectAdjacentConversation(bool focus_selected) @@ -2013,7 +2078,22 @@ void LLFloaterIMContainer::expandConversation()  	}  } -void LLFloaterIMContainer::closeFloater(bool app_quitting/* = false*/) +// By default, if torn off session is currently frontmost, LLFloater::isFrontmost() will return FALSE, which can lead to some bugs +// So LLFloater::isFrontmost() is overriden here to check both selected session and the IM floater itself +// Exclude "Nearby Chat" session from the check, as "Nearby Chat" window and "Conversations" floater can be brought +// to front independently +/*virtual*/ +BOOL LLFloaterIMContainer::isFrontmost() +{ +	LLFloaterIMSessionTab* selected_session = LLFloaterIMSessionTab::getConversation(mSelectedSession); +	LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); +	return (selected_session && selected_session->isFrontmost() && (selected_session != nearby_chat)) +		|| LLFloater::isFrontmost(); +} + +// For conversations, closeFloater() (linked to Ctrl-W) does not actually close the floater but the active conversation. +// This is intentional so it doesn't confuse the user. onClickCloseBtn() closes the whole floater. +void LLFloaterIMContainer::onClickCloseBtn()  {  	// Always unminimize before trying to close.  	// Most of the time the user will never see this state. @@ -2022,7 +2102,80 @@ void LLFloaterIMContainer::closeFloater(bool app_quitting/* = false*/)  		LLMultiFloater::setMinimized(FALSE);  	} -	LLFloater::closeFloater(app_quitting); +	LLFloater::closeFloater(); +} + +void LLFloaterIMContainer::closeHostedFloater() +{ +	onClickCloseBtn(); +} + +void LLFloaterIMContainer::closeAllConversations() +{ +	LLDynamicArray<LLUUID> ids; +	for (conversations_items_map::iterator it_session = mConversationsItems.begin(); it_session != mConversationsItems.end(); it_session++) +	{ +		LLUUID session_id = it_session->first; +		if (session_id != LLUUID()) +		{ +			ids.push_back(session_id); +		} +	} + +	for (LLDynamicArray<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); 	++it) +	{ +		LLFloaterIMSession *conversationFloater = LLFloaterIMSession::findInstance(*it); +		LLFloater::onClickClose(conversationFloater); +	} +} + +void LLFloaterIMContainer::closeSelectedConversations(const uuid_vec_t& ids) +{ +	for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) +	{ +		//We don't need to close Nearby chat, so skip it +		if (*it != LLUUID()) +		{ +			LLFloaterIMSession *conversationFloater = LLFloaterIMSession::findInstance(*it); +			if(conversationFloater) +			{ +				LLFloater::onClickClose(conversationFloater); +			} +		} +	} +} +void LLFloaterIMContainer::closeFloater(bool app_quitting/* = false*/) +{ +	if(app_quitting) +	{ +		closeAllConversations(); +		onClickCloseBtn(); +	} +	else +	{ +		// Check for currently active session +		LLUUID session_id = getSelectedSession(); +		// If current session is Nearby Chat or there is only one session remaining, close the floater +		if (mConversationsItems.size() == 1 || session_id == LLUUID() || app_quitting) +		{ +			onClickCloseBtn(); +		} +		else +		{ +			// Otherwise, close current conversation +			LLFloaterIMSessionTab* active_conversation = LLFloaterIMSessionTab::getConversation(session_id); +			if (active_conversation) +			{ +				active_conversation->closeFloater(); +			} +		} +	} +} + +void LLFloaterIMContainer::handleReshape(const LLRect& rect, bool by_user) +{ +	LLMultiFloater::handleReshape(rect, by_user); +	storeRectControl();  }  // EOF diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h index e39d20ec35..36da457cac 100755 --- a/indra/newview/llfloaterimcontainer.h +++ b/indra/newview/llfloaterimcontainer.h @@ -63,6 +63,8 @@ public:  	/*virtual*/ void setVisible(BOOL visible);  	/*virtual*/ void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());  	/*virtual*/ void updateResizeLimits(); +	/*virtual*/ void handleReshape(const LLRect& rect, bool by_user); +  	void onCloseFloater(LLUUID& id);  	/*virtual*/ void addFloater(LLFloater* floaterp,  @@ -105,8 +107,6 @@ public:  	LLConversationItem* getSessionModel(const LLUUID& session_id) { return get_ptr_in_map(mConversationsItems,session_id); }  	LLConversationSort& getSortOrder() { return mConversationViewModel.getSorter(); } -	void onNearbyChatClosed(); -  	// Handling of lists of participants is public so to be common with llfloatersessiontab  	// *TODO : Find a better place for this.      bool checkContextMenuItem(const std::string& item, uuid_vec_t& selectedIDS); @@ -116,6 +116,10 @@ public:  	void assignResizeLimits();  	virtual BOOL handleKeyHere(KEY key, MASK mask );  	/*virtual*/ void closeFloater(bool app_quitting = false); +    void closeAllConversations(); +    void closeSelectedConversations(const uuid_vec_t& ids); +	/*virtual*/ BOOL isFrontmost(); +  private:  	typedef std::map<LLUUID,LLFloater*> avatarID_panel_map_t; @@ -130,6 +134,8 @@ private:  	void onStubCollapseButtonClicked();  	void processParticipantsStyleUpdate();  	void onSpeakButtonClicked(); +	/*virtual*/ void onClickCloseBtn(); +	/*virtual*/ void closeHostedFloater();  	void collapseConversationsPane(bool collapse, bool save_is_allowed=true); @@ -144,7 +150,7 @@ private:  	void setSortOrderParticipants(const LLConversationFilter::ESortOrderType order);  	void setSortOrder(const LLConversationSort& order); -    void getSelectedUUIDs(uuid_vec_t& selected_uuids); +    void getSelectedUUIDs(uuid_vec_t& selected_uuids, bool participant_uuids = true);      const LLConversationItem * getCurSelectedViewModelItem();      void getParticipantUUIDs(uuid_vec_t& selected_uuids);      void doToSelected(const LLSD& userdata); @@ -169,6 +175,7 @@ private:  	LLButton* mExpandCollapseBtn;  	LLButton* mStubCollapseBtn; +    LLButton* mSpeakBtn;  	LLPanel* mStubPanel;  	LLTextBox* mStubTextBox;  	LLLayoutPanel* mMessagesPane; @@ -176,6 +183,7 @@ private:  	LLLayoutStack* mConversationsStack;  	bool mInitialized; +	bool mIsFirstLaunch;  	LLUUID mSelectedSession;  	std::string mGeneralTitle; @@ -190,9 +198,12 @@ public:  	void updateSpeakBtnState();  	static bool isConversationLoggingAllowed();  	void flashConversationItemWidget(const LLUUID& session_id, bool is_flashes); +	void highlightConversationItemWidget(const LLUUID& session_id, bool is_highlighted);  	bool isScrolledOutOfSight(LLConversationViewSession* conversation_item_widget);  	boost::signals2::connection mMicroChangedSignal;  	S32 getConversationListItemSize() { return mConversationsWidgets.size(); } +	typedef std::list<LLFloater*> floater_list_t; +	void getDetachedConversationFloaters(floater_list_t& floaters);  private:  	LLConversationViewSession* createConversationItemWidget(LLConversationItem* item); diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index 56b0c15cb9..5999c74d51 100755 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -138,19 +138,28 @@ BOOL LLFloaterIMNearbyChat::postBuild()  // virtual  void LLFloaterIMNearbyChat::closeHostedFloater()  { -	// Should check how many conversations are ongoing. Close all if 1 only (the Nearby Chat), select next one otherwise +	// If detached from conversations window close anyway +	if (!getHost()) +	{ +		setVisible(FALSE); +	} + +	// Should check how many conversations are ongoing. Select next to "Nearby Chat" in case there are some other besides. +	// Close conversations window in case "Nearby Chat" is attached and the only conversation  	LLFloaterIMContainer* floater_container = LLFloaterIMContainer::getInstance();  	if (floater_container->getConversationListItemSize() == 1)  	{ -		floater_container->closeFloater(); +		if (getHost()) +		{ +			floater_container->closeFloater(); +		}  	}  	else  	{  		if (!getHost())  		{ -			setVisible(FALSE); +			floater_container->selectNextConversationByID(LLUUID());  		} -		floater_container->selectNextConversationByID(LLUUID());  	}  } @@ -262,7 +271,7 @@ void LLFloaterIMNearbyChat::setVisibleAndFrontmost(BOOL take_focus, const LLSD&  {  	LLFloaterIMSessionTab::setVisibleAndFrontmost(take_focus, key); -	if(!isTornOff() && matchesKey(key)) +	if(matchesKey(key))  	{  		LLFloaterIMContainer::getInstance()->selectConversationPair(mSessionID, true, take_focus);  	} @@ -296,7 +305,6 @@ void LLFloaterIMNearbyChat::onClose(bool app_quitting)  {  	// Override LLFloaterIMSessionTab::onClose() so that Nearby Chat is not removed from the conversation floater  	LLFloaterIMSessionTab::restoreFloater(); -	onClickCloseBtn();  }  // virtual @@ -306,13 +314,7 @@ void LLFloaterIMNearbyChat::onClickCloseBtn()  	{  		return;  	} -	LLFloaterIMSessionTab::onTearOffClicked(); -	 -	LLFloaterIMContainer *im_box = LLFloaterIMContainer::findInstance(); -	if (im_box) -	{ -		im_box->onNearbyChatClosed(); -	} +	closeHostedFloater();  }  void LLFloaterIMNearbyChat::onChatFontChange(LLFontGL* fontp) @@ -350,11 +352,17 @@ bool LLFloaterIMNearbyChat::isChatVisible() const  void LLFloaterIMNearbyChat::showHistory()  {  	openFloater(); +	LLFloaterIMContainer::getInstance()->selectConversation(LLUUID(NULL)); +  	if(!isMessagePaneExpanded())  	{  		restoreFloater();  		setFocus(true);  	} +	else +	{ +		LLFloaterIMContainer::getInstance()->setFocus(TRUE); +	}  	setResizeLimits(getMinWidth(), EXPANDED_MIN_HEIGHT);  } @@ -568,7 +576,10 @@ void LLFloaterIMNearbyChat::sendChat( EChatType type )  			if (0 == channel)  			{  				// discard returned "found" boolean -				LLGestureMgr::instance().triggerAndReviseString(utf8text, &utf8_revised_text); +				if(!LLGestureMgr::instance().triggerAndReviseString(utf8text, &utf8_revised_text)) +				{ +					utf8_revised_text = utf8text; +				}  			}  			else  			{ @@ -636,10 +647,7 @@ void LLFloaterIMNearbyChat::addMessage(const LLChat& chat,bool archive,const LLS  void LLFloaterIMNearbyChat::onChatBoxCommit()  { -	if (mInputEditor->getText().length() > 0) -	{ -		sendChat(CHAT_TYPE_NORMAL); -	} +	sendChat(CHAT_TYPE_NORMAL);  	gAgent.stopTyping();  } diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 9ce5e12897..cc00b6fd10 100755 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -606,6 +606,7 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,  		//Don't show nearby toast, if conversation is visible and selected  		if ((nearby_chat->hasFocus()) || +			(LLFloater::isVisible(nearby_chat) && nearby_chat->isTornOff() && !nearby_chat->isMinimized()) ||  		    ((im_box->getSelectedSession().isNull() &&  				((LLFloater::isVisible(im_box) && !im_box->isMinimized() && im_box->isFrontmost())  						|| (LLFloater::isVisible(nearby_chat) && !nearby_chat->isMinimized() && nearby_chat->isFrontmost()))))) diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index 8ec85e1160..5cb9df5625 100755 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -109,18 +109,6 @@ void LLFloaterIMSession::refresh()  void LLFloaterIMSession::onTearOffClicked()  {      LLFloaterIMSessionTab::onTearOffClicked(); - -    if(mIsP2PChat) -    { -        if(isTornOff()) -        { -            mSpeakingIndicator->setSpeakerId(mOtherParticipantUUID, mSessionID); -        } -        else -        { -            mSpeakingIndicator->setSpeakerId(LLUUID::null); -        } -    }  }  // virtual @@ -442,8 +430,11 @@ void LLFloaterIMSession::addSessionParticipants(const uuid_vec_t& uuids)  	}  	else  	{ -		// remember whom we have invited, to notify others later, when the invited ones actually join -		mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end()); +		if(findInstance(mSessionID)) +		{ +			// remember whom we have invited, to notify others later, when the invited ones actually join +			mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end()); +		}  		inviteToSession(uuids);  	} @@ -469,13 +460,18 @@ void LLFloaterIMSession::addP2PSessionParticipants(const LLSD& notification, con  	temp_ids.insert(temp_ids.end(), uuids.begin(), uuids.end());  	// then we can close the current session -	onClose(false); +	if(findInstance(mSessionID)) +	{ +		onClose(false); + +		// remember whom we have invited, to notify others later, when the invited ones actually join +		mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end()); +	}  	// we start a new session so reset the initialization flag  	mSessionInitialized = false; -	// remember whom we have invited, to notify others later, when the invited ones actually join -	mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end()); +  	// Start a new ad hoc voice call if we invite new participants to a P2P call,  	// or start a text chat otherwise. diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index ce6e639305..0ccfdb9a7b 100755 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -55,7 +55,6 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)    ,  mSessionID(session_id.asUUID())    , mConversationsRoot(NULL)    , mScroller(NULL) -  , mSpeakingIndicator(NULL)    , mChatHistory(NULL)    , mInputEditor(NULL)    , mInputEditorPad(0) @@ -212,7 +211,7 @@ void LLFloaterIMSessionTab::assignResizeLimits()  	mRightPartPanel->setIgnoreReshape(is_participants_pane_collapsed);      S32 participants_pane_target_width = is_participants_pane_collapsed? -    		0 : (mParticipantListPanel->getRect().getWidth() + LLPANEL_BORDER_WIDTH); +    		0 : (mParticipantListPanel->getRect().getWidth() + mParticipantListAndHistoryStack->getPanelSpacing());      S32 new_min_width = participants_pane_target_width + mRightPartPanel->getExpandedMinDim() + mFloaterExtraWidth; @@ -241,7 +240,10 @@ BOOL LLFloaterIMSessionTab::postBuild()  	mTearOffBtn->setCommitCallback(boost::bind(&LLFloaterIMSessionTab::onTearOffClicked, this));  	mGearBtn = getChild<LLButton>("gear_btn"); - +    mAddBtn = getChild<LLButton>("add_btn"); +	mVoiceButton = getChild<LLButton>("voice_call_btn"); +    mTranslationCheckBox = getChild<LLUICtrl>("translate_chat_checkbox_lp"); +      	mParticipantListPanel = getChild<LLLayoutPanel>("speakers_list_panel");  	mRightPartPanel = getChild<LLLayoutPanel>("right_part_holder"); @@ -256,8 +258,6 @@ BOOL LLFloaterIMSessionTab::postBuild()  	scroller_params.rect(scroller_view_rect);  	mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);  	mScroller->setFollowsAll(); -	 -    mSpeakingIndicator = getChild<LLOutputMonitorCtrl>("speaking_indicator");  	// Insert that scroller into the panel widgets hierarchy  	mParticipantListPanel->addChild(mScroller);	 @@ -270,6 +270,7 @@ BOOL LLFloaterIMSessionTab::postBuild()  	mInputPanels = getChild<LLLayoutStack>("input_panels");  	mInputEditor->setTextExpandedCallback(boost::bind(&LLFloaterIMSessionTab::reshapeChatLayoutPanel, this)); +	mInputEditor->setMouseUpCallback(boost::bind(&LLFloaterIMSessionTab::onInputEditorClicked, this));  	mInputEditor->setCommitOnFocusLost( FALSE );  	mInputEditor->setPassDelete(TRUE);  	mInputEditor->setFont(LLViewerChat::getChatFont()); @@ -372,7 +373,7 @@ void LLFloaterIMSessionTab::draw()  void LLFloaterIMSessionTab::enableDisableCallBtn()  { -    getChildView("voice_call_btn")->setEnabled( +    mVoiceButton->setEnabled(      		mSessionID.notNull()      		&& mSession      		&& mSession->mSessionInitialized @@ -399,6 +400,16 @@ void LLFloaterIMSessionTab::onFocusLost()  	LLTransientDockableFloater::onFocusLost();  } +void LLFloaterIMSessionTab::onInputEditorClicked() +{ +	LLFloaterIMContainer* im_box = LLFloaterIMContainer::findInstance(); +	if (im_box) +	{ +		im_box->flashConversationItemWidget(mSessionID,false); +	} +	gToolBarView->flashCommand(LLCommandId("chat"), false); +} +  std::string LLFloaterIMSessionTab::appendTime()  {  	time_t utc_time; @@ -758,7 +769,7 @@ void LLFloaterIMSessionTab::reshapeChatLayoutPanel()  void LLFloaterIMSessionTab::showTranslationCheckbox(BOOL show)  { -	getChild<LLUICtrl>("translate_chat_checkbox_lp")->setVisible(mIsNearbyChat? show : FALSE); +	mTranslationCheckBox->setVisible(mIsNearbyChat && show);  }  // static @@ -805,15 +816,10 @@ void LLFloaterIMSessionTab::reloadEmptyFloaters()  void LLFloaterIMSessionTab::updateCallBtnState(bool callIsActive)  { -	LLButton* voiceButton = getChild<LLButton>("voice_call_btn"); -	voiceButton->setImageOverlay( -			callIsActive? getString("call_btn_stop") : getString("call_btn_start")); - -	voiceButton->setToolTip( -			callIsActive? getString("end_call_button_tooltip") : getString("start_call_button_tooltip")); +	mVoiceButton->setImageOverlay(callIsActive? getString("call_btn_stop") : getString("call_btn_start")); +	mVoiceButton->setToolTip(callIsActive? getString("end_call_button_tooltip") : getString("start_call_button_tooltip"));  	enableDisableCallBtn(); -  }  void LLFloaterIMSessionTab::onSlide(LLFloaterIMSessionTab* self) @@ -898,6 +904,7 @@ void LLFloaterIMSessionTab::restoreFloater()  		mExpandCollapseLineBtn->setImageOverlay(getString("expandline_icon"));  		setMessagePaneExpanded(true);  		saveCollapsedState(); +		mInputEditor->enableSingleLineMode(false);  		enableResizeCtrls(true, true, true);  	}  } @@ -953,8 +960,8 @@ void LLFloaterIMSessionTab::updateGearBtn()  	if(prevVisibility != mGearBtn->getVisible())  	{  		LLRect gear_btn_rect =  mGearBtn->getRect(); -		LLRect add_btn_rect = getChild<LLButton>("add_btn")->getRect(); -		LLRect call_btn_rect = getChild<LLButton>("voice_call_btn")->getRect(); +		LLRect add_btn_rect = mAddBtn->getRect(); +		LLRect call_btn_rect = mVoiceButton->getRect();  		S32 gap_width = call_btn_rect.mLeft - add_btn_rect.mRight;  		S32 right_shift = gear_btn_rect.getWidth() + gap_width;  		if(mGearBtn->getVisible()) @@ -968,24 +975,24 @@ void LLFloaterIMSessionTab::updateGearBtn()  			add_btn_rect.translate(-right_shift,0);  			call_btn_rect.translate(-right_shift,0);  		} -		getChild<LLButton>("add_btn")->setRect(add_btn_rect); -		getChild<LLButton>("voice_call_btn")->setRect(call_btn_rect); +		mAddBtn->setRect(add_btn_rect); +		mVoiceButton->setRect(call_btn_rect);  	}  }  void LLFloaterIMSessionTab::initBtns()  {  	LLRect gear_btn_rect =  mGearBtn->getRect(); -	LLRect add_btn_rect = getChild<LLButton>("add_btn")->getRect(); -	LLRect call_btn_rect = getChild<LLButton>("voice_call_btn")->getRect(); +	LLRect add_btn_rect = mAddBtn->getRect(); +	LLRect call_btn_rect = mVoiceButton->getRect();  	S32 gap_width = call_btn_rect.mLeft - add_btn_rect.mRight;  	S32 right_shift = gear_btn_rect.getWidth() + gap_width;  	add_btn_rect.translate(-right_shift,0);  	call_btn_rect.translate(-right_shift,0); -	getChild<LLButton>("add_btn")->setRect(add_btn_rect); -	getChild<LLButton>("voice_call_btn")->setRect(call_btn_rect); +	mAddBtn->setRect(add_btn_rect); +	mVoiceButton->setRect(call_btn_rect);  }  // static @@ -1083,21 +1090,26 @@ void LLFloaterIMSessionTab::saveCollapsedState()  }  BOOL LLFloaterIMSessionTab::handleKeyHere(KEY key, MASK mask )  { +	BOOL handled = FALSE; +  	if(mask == MASK_ALT)  	{  		LLFloaterIMContainer* floater_container = LLFloaterIMContainer::getInstance();  		if (KEY_RETURN == key && !isTornOff())  		{  			floater_container->expandConversation(); +			handled = TRUE;  		}  		if ((KEY_UP == key) || (KEY_LEFT == key))  		{  			floater_container->selectNextorPreviousConversation(false); +			handled = TRUE;  		}  		if ((KEY_DOWN == key ) || (KEY_RIGHT == key))  		{  			floater_container->selectNextorPreviousConversation(true); +			handled = TRUE;  		}  	} -	return TRUE; +	return handled;  } diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h index 302d5a8066..e7b05a584b 100755 --- a/indra/newview/llfloaterimsessiontab.h +++ b/indra/newview/llfloaterimsessiontab.h @@ -171,8 +171,7 @@ protected:  	LLFolderView* mConversationsRoot;  	LLScrollContainer* mScroller; -    LLOutputMonitorCtrl* mSpeakingIndicator; -	LLChatHistory* mChatHistory; +    LLChatHistory* mChatHistory;  	LLChatEntry* mInputEditor;  	LLLayoutPanel * mChatLayoutPanel;  	LLLayoutStack * mInputPanels; @@ -182,6 +181,9 @@ protected:  	LLButton* mTearOffBtn;  	LLButton* mCloseBtn;  	LLButton* mGearBtn; +	LLButton* mAddBtn; +    LLButton* mVoiceButton; +    LLUICtrl* mTranslationCheckBox;  private:  	// Handling selection and contextual menu @@ -201,6 +203,8 @@ private:  	 */  	void reshapeChatLayoutPanel(); +	void onInputEditorClicked(); +  	bool checkIfTornOff();      bool mIsHostAttached;      bool mHasVisibleBeenInitialized; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 55b03986d0..4ebe813be6 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -452,6 +452,7 @@ BOOL LLFloaterPreference::postBuild()  	getChild<LLComboBox>("ConferenceIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"ConferenceIMOptions"));  	getChild<LLComboBox>("GroupChatOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"GroupChatOptions"));  	getChild<LLComboBox>("NearbyChatOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"NearbyChatOptions")); +	getChild<LLComboBox>("ObjectIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"ObjectIMOptions"));  	// if floater is opened before login set default localized do not disturb message  	if (LLStartUp::getStartupState() < STATE_STARTED) @@ -721,6 +722,7 @@ void LLFloaterPreference::onOpen(const LLSD& key)  	onNotificationsChange("ConferenceIMOptions");  	onNotificationsChange("GroupChatOptions");  	onNotificationsChange("NearbyChatOptions"); +	onNotificationsChange("ObjectIMOptions");  	LLPanelLogin::setAlwaysRefresh(true);  	refresh(); @@ -928,7 +930,7 @@ void LLFloaterPreference::onNotificationsChange(const std::string& OptionName)  	bool show_notifications_alert = true;  	for (notifications_map::iterator it_notification = mNotificationOptions.begin(); it_notification != mNotificationOptions.end(); it_notification++)  	{ -		if(it_notification->second != "None") +		if(it_notification->second != "No action")  		{  			show_notifications_alert = false;  			break; diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index 586965e5a0..c28657dbcd 100755 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -74,6 +74,7 @@ void LLFolderViewModelInventory::sort( LLFolderViewFolder* folder )  		it != end_it;  		++it)  	{ +        // Recursive call to sort() on child (CHUI-849)  		LLFolderViewFolder* child_folderp = *it;  		sort(child_folderp); @@ -129,12 +130,12 @@ void LLFolderViewModelItemInventory::requestSort()  void LLFolderViewModelItemInventory::setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset, std::string::size_type string_size)  {  	LLFolderViewModelItemCommon::setPassedFilter(passed, filter_generation, string_offset, string_size); - -	bool passed_filter_before = mPrevPassedAllFilters; +	bool before = mPrevPassedAllFilters;  	mPrevPassedAllFilters = passedFilter(filter_generation); -	if (passed_filter_before != mPrevPassedAllFilters) +    if (before != mPrevPassedAllFilters)  	{ +        // Need to rearrange the folder if the filtered state of the item changed  		LLFolderViewFolder* parent_folder = mFolderViewItem->getParentFolder();  		if (parent_folder)  		{ @@ -150,11 +151,11 @@ bool LLFolderViewModelItemInventory::filterChildItem( LLFolderViewModelItem* ite  	bool continue_filtering = true;  	if (item->getLastFilterGeneration() < filter_generation)  	{ -		// recursive application of the filter for child items +		// Recursive application of the filter for child items (CHUI-849)  		continue_filtering = item->filter( filter );  	} -	// track latest generation to pass any child items, for each folder up to root +	// Update latest generation to pass filter in parent and propagate up to root  	if (item->passedFilter())  	{  		LLFolderViewModelItemInventory* view_model = this; @@ -174,53 +175,61 @@ bool LLFolderViewModelItemInventory::filter( LLFolderViewFilter& filter)  	const S32 filter_generation = filter.getCurrentGeneration();  	const S32 must_pass_generation = filter.getFirstRequiredGeneration(); -	if (getLastFilterGeneration() >= must_pass_generation  +    if (getLastFilterGeneration() >= must_pass_generation  		&& getLastFolderFilterGeneration() >= must_pass_generation  		&& !passedFilter(must_pass_generation))  	{  		// failed to pass an earlier filter that was a subset of the current one -		// go ahead and flag this item as done +		// go ahead and flag this item as not pass  		setPassedFilter(false, filter_generation);  		setPassedFolderFilter(false, filter_generation);  		return true;  	} -	const bool passed_filter_folder = (getInventoryType() == LLInventoryType::IT_CATEGORY)  -		? filter.checkFolder(this) -		: true; +    // *TODO : Revise the logic for fast pass on less restrictive filter case +    /* +     const S32 sufficient_pass_generation = filter.getFirstSuccessGeneration(); +    if (getLastFilterGeneration() >= sufficient_pass_generation +		&& getLastFolderFilterGeneration() >= sufficient_pass_generation +		&& passedFilter(sufficient_pass_generation)) +	{ +		// passed an earlier filter that was a superset of the current one +		// go ahead and flag this item as pass +		setPassedFilter(true, filter_generation); +		setPassedFolderFilter(true, filter_generation); +		return true; +	} +     */ +     +	const bool passed_filter_folder = (getInventoryType() == LLInventoryType::IT_CATEGORY) ? filter.checkFolder(this) : true;  	setPassedFolderFilter(passed_filter_folder, filter_generation); -	if(!mChildren.empty() +	bool continue_filtering = true; + +	if (!mChildren.empty()  		&& (getLastFilterGeneration() < must_pass_generation // haven't checked descendants against minimum required generation to pass -			|| descendantsPassedFilter(must_pass_generation))) // or at least one descendant has passed the minimum requirement +            || descendantsPassedFilter(must_pass_generation))) // or at least one descendant has passed the minimum requirement  	{  		// now query children -		for (child_list_t::iterator iter = mChildren.begin(), end_iter = mChildren.end(); -			iter != end_iter && filter.getFilterCount() > 0; -			++iter) +		for (child_list_t::iterator iter = mChildren.begin(), end_iter = mChildren.end(); iter != end_iter; ++iter)  		{ -			if (!filterChildItem((*iter), filter)) +			continue_filtering = filterChildItem((*iter), filter); +            if (!continue_filtering)  			{  				break;  			}  		}  	} -	// if we didn't use all filter iterations -	// that means we filtered all of our descendants -	// so filter ourselves now -	if (filter.getFilterCount() > 0) +	// If we didn't use all the filter time that means we filtered all of our descendants so we can filter ourselves now +    if (continue_filtering)  	{ -		filter.decrementFilterCount(); - +        // This is where filter check on the item done (CHUI-849)  		const bool passed_filter = filter.check(this);  		setPassedFilter(passed_filter, filter_generation, filter.getStringMatchOffset(this), filter.getFilterStringSize()); -		return true; -	} -	else -	{ -		return false; +        continue_filtering = !filter.isTimedOut();  	} +    return continue_filtering;  }  LLFolderViewModelInventory* LLInventoryPanel::getFolderViewModel() @@ -307,8 +316,8 @@ bool LLInventorySort::operator()(const LLFolderViewModelItemInventory* const& a,  	}  } -LLFolderViewModelItemInventory::LLFolderViewModelItemInventory( class LLFolderViewModelInventory& root_view_model )  -	:	LLFolderViewModelItemCommon(root_view_model), -	mPrevPassedAllFilters(false) +LLFolderViewModelItemInventory::LLFolderViewModelItemInventory( class LLFolderViewModelInventory& root_view_model ) : +    LLFolderViewModelItemCommon(root_view_model), +    mPrevPassedAllFilters(false)  {  } diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h index 890d03d1c9..9dcfdfa185 100755 --- a/indra/newview/llfolderviewmodelinventory.h +++ b/indra/newview/llfolderviewmodelinventory.h @@ -59,9 +59,8 @@ public:  	virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const = 0;  	virtual LLToolDragAndDrop::ESource getDragSource() const = 0; -  protected: -	bool								mPrevPassedAllFilters; +    bool mPrevPassedAllFilters;  };  class LLInventorySort diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index a0f2918bd7..302d21c2e4 100755 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -116,6 +116,80 @@ public:  };  LLGroupHandler gGroupHandler; +// This object represents a pending request for specified group member information +// which is needed to check whether avatar can leave group +class LLFetchGroupMemberData : public LLGroupMgrObserver +{ +public: +	LLFetchGroupMemberData(const LLUUID& group_id) :  +		mGroupId(group_id), +		mRequestProcessed(false), +		LLGroupMgrObserver(group_id)  +	{ +		llinfos << "Sending new group member request for group_id: "<< group_id << llendl; +		LLGroupMgr* mgr = LLGroupMgr::getInstance(); +		// register ourselves as an observer +		mgr->addObserver(this); +		// send a request +		mgr->sendGroupPropertiesRequest(group_id); +		mgr->sendCapGroupMembersRequest(group_id); +	} + +	~LLFetchGroupMemberData() +	{ +		if (!mRequestProcessed) +		{ +			// Request is pending +			llwarns << "Destroying pending group member request for group_id: " +				<< mGroupId << llendl; +		} +		// Remove ourselves as an observer +		LLGroupMgr::getInstance()->removeObserver(this); +	} + +	void changed(LLGroupChange gc) +	{ +		if (gc == GC_MEMBER_DATA && !mRequestProcessed) +		{ +			LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupId); +			if (!gdatap) +			{ +				llwarns << "LLGroupMgr::getInstance()->getGroupData() was NULL" << llendl; +			}  +			else if (!gdatap->isMemberDataComplete()) +			{ +				llwarns << "LLGroupMgr::getInstance()->getGroupData()->isMemberDataComplete() was FALSE" << llendl; +			} +			else +			{ +				processGroupData(); +				mRequestProcessed = true; +			} +		} +	} + +	LLUUID getGroupId() { return mGroupId; } +	virtual void processGroupData() = 0; +protected: +	LLUUID mGroupId; +private: +	bool mRequestProcessed; +}; + +class LLFetchLeaveGroupData: public LLFetchGroupMemberData +{ +public: +	 LLFetchLeaveGroupData(const LLUUID& group_id) +		 : LLFetchGroupMemberData(group_id) +	 {} +	 void processGroupData() +	 { +		 LLGroupActions::processLeaveGroupDataResponse(mGroupId); +	 } +}; + +LLFetchLeaveGroupData* gFetchLeaveGroupData = NULL; +  // static  void LLGroupActions::search()  { @@ -208,23 +282,52 @@ bool LLGroupActions::onJoinGroup(const LLSD& notification, const LLSD& response)  void LLGroupActions::leave(const LLUUID& group_id)  {  	if (group_id.isNull()) +	{  		return; +	} -	S32 count = gAgent.mGroups.count(); -	S32 i; -	for (i = 0; i < count; ++i) +	LLGroupData group_data; +	if (gAgent.getGroupData(group_id, group_data))  	{ -		if(gAgent.mGroups.get(i).mID == group_id) -			break; +		LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id); +		if (!gdatap || !gdatap->isMemberDataComplete()) +		{ +			if (gFetchLeaveGroupData != NULL) +			{ +				delete gFetchLeaveGroupData; +				gFetchLeaveGroupData = NULL; +			} +			gFetchLeaveGroupData = new LLFetchLeaveGroupData(group_id); +		} +		else +		{ +			processLeaveGroupDataResponse(group_id); +		}  	} -	if (i < count) +} + +//static +void LLGroupActions::processLeaveGroupDataResponse(const LLUUID group_id) +{ +	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id); +	LLUUID agent_id = gAgent.getID(); +	LLGroupMgrGroupData::member_list_t::iterator mit = gdatap->mMembers.find(agent_id); +	//get the member data for the group +	if ( mit != gdatap->mMembers.end() )  	{ -		LLSD args; -		args["GROUP"] = gAgent.mGroups.get(i).mName; -		LLSD payload; -		payload["group_id"] = group_id; -		LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup); +		LLGroupMemberData* member_data = (*mit).second; + +		if ( member_data && member_data->isOwner() && gdatap->mMemberCount == 1) +		{ +			LLNotificationsUtil::add("OwnerCannotLeaveGroup"); +			return; +		}  	} +	LLSD args; +	args["GROUP"] = gdatap->mName; +	LLSD payload; +	payload["group_id"] = group_id; +	LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup);  }  // static diff --git a/indra/newview/llgroupactions.h b/indra/newview/llgroupactions.h index 3f9852f194..afc4686dd7 100755 --- a/indra/newview/llgroupactions.h +++ b/indra/newview/llgroupactions.h @@ -114,6 +114,14 @@ public:  private:  	static bool onJoinGroup(const LLSD& notification, const LLSD& response);  	static bool onLeaveGroup(const LLSD& notification, const LLSD& response); +	 +	/** +	 * This function is called by LLFetchLeaveGroupData upon receiving a response to a group  +	 * members data request. +	 */ +	static void processLeaveGroupDataResponse(const LLUUID group_id); + +	friend class LLFetchLeaveGroupData;  };  #endif // LL_LLGROUPACTIONS_H diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 3b72ad3cd9..9e23755d73 100755 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -103,6 +103,7 @@ BOOL LLSessionTimeoutTimer::tick()  } +void notify_of_message(const LLSD& msg, bool is_dnd_msg);  void process_dnd_im(const LLSD& notification)  { @@ -129,15 +130,9 @@ void process_dnd_im(const LLSD& notification)              fromID,               false,               false); //will need slight refactor to retrieve whether offline message or not (assume online for now) +	} -		LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container"); -		 -		if (im_box) -		{ -			im_box->flashConversationItemWidget(sessionID, true); -		} - -    } +	notify_of_message(data, true);  } @@ -158,75 +153,106 @@ static void on_avatar_name_cache_toast(const LLUUID& agent_id,  	LLNotificationsUtil::add("IMToast", args, args, boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID()));  } -void on_new_message(const LLSD& msg) +void notify_of_message(const LLSD& msg, bool is_dnd_msg)  { -    std::string user_preferences; -    LLUUID participant_id = msg["from_id"].asUUID(); -    LLUUID session_id = msg["session_id"].asUUID(); -    LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id); - -    // do not show notification which goes from agent -    if (gAgent.getID() == participant_id) -    { -        return; -    } +	std::string user_preferences; +	LLUUID participant_id = msg[is_dnd_msg ? "FROM_ID" : "from_id"].asUUID(); +	LLUUID session_id = msg[is_dnd_msg ? "SESSION_ID" : "session_id"].asUUID(); +	LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id); -    // determine state of conversations floater -    enum {CLOSED, NOT_ON_TOP, ON_TOP, ON_TOP_AND_ITEM_IS_SELECTED} conversations_floater_status; +	// do not show notification which goes from agent +	if (gAgent.getID() == participant_id) +	{ +		return; +	} +	// determine state of conversations floater +	enum {CLOSED, NOT_ON_TOP, ON_TOP, ON_TOP_AND_ITEM_IS_SELECTED} conversations_floater_status; -    LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container"); +	LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");  	LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id); - +	bool store_dnd_message = false; // flag storage of a dnd message +	bool is_session_focused = session_floater->isTornOff() && session_floater->hasFocus();  	if (!LLFloater::isVisible(im_box) || im_box->isMinimized())  	{  		conversations_floater_status = CLOSED;  	}  	else if (!im_box->hasFocus() && -			    !(session_floater && LLFloater::isVisible(session_floater) -	            && !session_floater->isMinimized() && session_floater->hasFocus())) +		!(session_floater && LLFloater::isVisible(session_floater) +		&& !session_floater->isMinimized() && session_floater->hasFocus()))  	{  		conversations_floater_status = NOT_ON_TOP;  	}  	else if (im_box->getSelectedSession() != session_id)  	{  		conversations_floater_status = ON_TOP; -    } +	}  	else  	{  		conversations_floater_status = ON_TOP_AND_ITEM_IS_SELECTED;  	} -    //  determine user prefs for this session -    if (session_id.isNull()) -    { -    	user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions"); -    } -    else if(session->isP2PSessionType()) -    { -        if (LLAvatarTracker::instance().isBuddy(participant_id)) -        { -        	user_preferences = gSavedSettings.getString("NotificationFriendIMOptions"); -        } -        else -        { -        	user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions"); -        } -    } -    else if(session->isAdHocSessionType()) -    { -    	user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions"); -    } -    else if(session->isGroupSessionType()) -    { -    	user_preferences = gSavedSettings.getString("NotificationGroupChatOptions"); -    } +	//  determine user prefs for this session +	if (session_id.isNull()) +	{ +		if (msg["source_type"].asInteger() == CHAT_SOURCE_OBJECT) +		{ +			user_preferences = gSavedSettings.getString("NotificationObjectIMOptions"); +			if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundObjectIM") == TRUE)) +			{ +				make_ui_sound("UISndNewIncomingIMSession"); +			} +		} +		else +		{ +			user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions"); +			if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM") == TRUE)) +			{ +				make_ui_sound("UISndNewIncomingIMSession"); +			} +		} +	} +	else if(session->isP2PSessionType()) +	{ +		if (LLAvatarTracker::instance().isBuddy(participant_id)) +		{ +			user_preferences = gSavedSettings.getString("NotificationFriendIMOptions"); +			if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM") == TRUE)) +			{ +				make_ui_sound("UISndNewIncomingIMSession"); +			} +		} +		else +		{ +			user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions"); +			if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM") == TRUE)) +			{ +				make_ui_sound("UISndNewIncomingIMSession"); +			} +		} +	} +	else if(session->isAdHocSessionType()) +	{ +		user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions"); +		if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM") == TRUE)) +		{ +			make_ui_sound("UISndNewIncomingIMSession"); +		} +	} +	else if(session->isGroupSessionType()) +	{ +		user_preferences = gSavedSettings.getString("NotificationGroupChatOptions"); +		if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM") == TRUE)) +		{ +			make_ui_sound("UISndNewIncomingIMSession"); +		} +	} -    // actions: +	// actions:      // 0. nothing - exit -    if (("none" == user_preferences || +    if (("noaction" == user_preferences ||      		ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status)      	&& session_floater->isMessagePaneExpanded())      { @@ -261,57 +287,103 @@ void on_new_message(const LLSD& msg)  				}  			}  		} -        else -        { -            //If in DND mode, allow notification to be stored so upon DND exit -            //useMostItrusiveIMNotification will be called to notify user a message exists -            if(session_id.notNull() -               && participant_id.notNull() -		       && !session_floater->isShown()) -            { -                LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); -	        } -        } -    } +		else +		{ +			store_dnd_message = true; +		} -    // 2. Flash line item -    if ("openconversations" == user_preferences -    		|| ON_TOP == conversations_floater_status -    		|| ("toast" == user_preferences && ON_TOP != conversations_floater_status) -    		|| ("flash" == user_preferences && CLOSED == conversations_floater_status)) -    { -    	if(!LLMuteList::getInstance()->isMuted(participant_id)) -    	{ -    		im_box->flashConversationItemWidget(session_id, true); -    	} -    } +	} -    // 3. Flash FUI button -    if (("toast" == user_preferences || "flash" == user_preferences) && -    		(CLOSED == conversations_floater_status -    		    || NOT_ON_TOP == conversations_floater_status)) -    { -    	if(!LLMuteList::getInstance()->isMuted(participant_id) -            && !gAgent.isDoNotDisturb()) -    	{ -    		gToolBarView->flashCommand(LLCommandId("chat"), true); -    	} -    } +	// 2. Flash line item +	if ("openconversations" == user_preferences +		|| ON_TOP == conversations_floater_status +		|| ("toast" == user_preferences && ON_TOP != conversations_floater_status) +		|| ("flash" == user_preferences && (CLOSED == conversations_floater_status +				 	 	 	 	 	 	|| NOT_ON_TOP == conversations_floater_status)) +		|| is_dnd_msg) +	{ +		if(!LLMuteList::getInstance()->isMuted(participant_id)) +		{ +			if(gAgent.isDoNotDisturb()) +			{ +				store_dnd_message = true; +			} +			else +			{ +				if (is_dnd_msg && (ON_TOP == conversations_floater_status ||  +									NOT_ON_TOP == conversations_floater_status ||  +									CLOSED == conversations_floater_status)) +				{ +					im_box->highlightConversationItemWidget(session_id, true); +				} +				else +				{ +					im_box->flashConversationItemWidget(session_id, true); +				} +			} +		} +	} -    // 4. Toast -    if ((("toast" == user_preferences) && -    		(CLOSED == conversations_floater_status -    		    || NOT_ON_TOP == conversations_floater_status)) -    		    || !session_floater->isMessagePaneExpanded()) +	// 3. Flash FUI button +	if (("toast" == user_preferences || "flash" == user_preferences) && +		(CLOSED == conversations_floater_status +		|| NOT_ON_TOP == conversations_floater_status) +		&& !is_session_focused +		&& !is_dnd_msg) //prevent flashing FUI button because the conversation floater will have already opened +	{ +		if(!LLMuteList::getInstance()->isMuted(participant_id)) +		{ +			if(!gAgent.isDoNotDisturb()) +			{ +				gToolBarView->flashCommand(LLCommandId("chat"), true, im_box->isMinimized()); +			} +			else +			{ +				store_dnd_message = true; +			} +		} +	} -    { -        //Show IM toasts (upper right toasts) -        // Skip toasting for system messages and for nearby chat -        if(session_id.notNull() && participant_id.notNull()) -        { -            LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); -        } -    } +	// 4. Toast +	if ((("toast" == user_preferences) && +		(ON_TOP_AND_ITEM_IS_SELECTED != conversations_floater_status) && +		(!session_floater->isTornOff() || !LLFloater::isVisible(session_floater))) +		|| !session_floater->isMessagePaneExpanded()) + +	{ +		//Show IM toasts (upper right toasts) +		// Skip toasting for system messages and for nearby chat +		if(session_id.notNull() && participant_id.notNull()) +		{ +			if(!is_dnd_msg) +			{ +				if(gAgent.isDoNotDisturb()) +				{ +					store_dnd_message = true; +				} +				else +				{ +					LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); +				} +			} +		} +	} +	if (store_dnd_message) +	{ +		// If in DND mode, allow notification to be stored so upon DND exit  +		// the user will be notified with some limitations (see 'is_dnd_msg' flag checks) +		if(session_id.notNull() +			&& participant_id.notNull() +			&& !session_floater->isShown()) +		{ +			LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); +		} +	} +} + +void on_new_message(const LLSD& msg) +{ +	notify_of_message(msg, false);  }  LLIMModel::LLIMModel()  @@ -2597,6 +2669,13 @@ void LLIMMgr::addMessage(  		fixed_session_name = session_name;  		name_is_setted = true;  	} +	bool skip_message = false; +	if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly")) +	{ +		// Evaluate if we need to skip this message when that setting is true (default is false) +		skip_message = (LLAvatarTracker::instance().getBuddyInfo(other_participant_id) == NULL);	// Skip non friends... +		skip_message &= !(other_participant_id == gAgentID);	// You are your best friend... Don't skip yourself +	}  	bool new_session = !hasSession(new_session_id);  	if (new_session) @@ -2608,6 +2687,12 @@ void LLIMMgr::addMessage(  		}  		LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id, false, is_offline_msg); +		LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(new_session_id); +		skip_message &= !session->isGroupSessionType();			// Do not skip group chats... +		if(skip_message) +		{ +			gIMMgr->leaveSession(new_session_id); +		}  		// 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. @@ -2648,23 +2733,13 @@ void LLIMMgr::addMessage(          }  	} -	bool skip_message = false; -	if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly")) -	{ -		// Evaluate if we need to skip this message when that setting is true (default is false) -		LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(new_session_id); -		skip_message = (LLAvatarTracker::instance().getBuddyInfo(other_participant_id) == NULL);	// Skip non friends... -		skip_message &= !session->isGroupSessionType();			// Do not skip group chats... -		skip_message &= !(other_participant_id == gAgentID);	// You are your best friend... Don't skip yourself -	} -  	if (!LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !skip_message)  	{  		LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg);  	}  	// Open conversation floater if offline messages are present -	if (is_offline_msg) +	if (is_offline_msg && !skip_message)      {          LLFloaterReg::showInstance("im_container");  	    LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container")-> @@ -2971,10 +3046,9 @@ void LLIMMgr::inviteToSession(  	{  		bool isRejectGroupCall = (gSavedSettings.getBOOL("VoiceCallsRejectGroup") && (notify_box_type == "VoiceInviteGroup"));  		bool isRejectNonFriendCall = (gSavedSettings.getBOOL("VoiceCallsFriendsOnly") && (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL)); -		bool isRejectDoNotDisturb = (gAgent.isDoNotDisturb() && !hasSession(session_id)); -		if	(isRejectGroupCall || isRejectNonFriendCall || isRejectDoNotDisturb) +		if	(isRejectGroupCall || isRejectNonFriendCall || gAgent.isDoNotDisturb())  		{ -			if (isRejectDoNotDisturb && !isRejectGroupCall && !isRejectNonFriendCall) +			if (gAgent.isDoNotDisturb() && !isRejectGroupCall && !isRejectNonFriendCall)  			{  				LLSD args;  				addSystemMessage(session_id, "you_auto_rejected_call", args); diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 92f2d33073..3c6974cf6d 100755 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -70,11 +70,8 @@ LLInventoryFilter::LLInventoryFilter(const Params& p)  	mFilterSubString(p.substring),  	mCurrentGeneration(0),  	mFirstRequiredGeneration(0), -	mFirstSuccessGeneration(0), -	mFilterCount(0) +	mFirstSuccessGeneration(0)  { -	mNextFilterGeneration = mCurrentGeneration + 1; -  	// copy mFilterOps into mDefaultFilterOps  	markDefault();  } @@ -92,9 +89,7 @@ bool LLInventoryFilter::check(const LLFolderViewModelItem* item)  		return passed_clipboard;  	} -	std::string::size_type string_offset = mFilterSubString.size() ? listener->getSearchableName().find(mFilterSubString) : std::string::npos; - -	BOOL passed = (mFilterSubString.size() == 0 || string_offset != std::string::npos); +	bool passed = (mFilterSubString.size() ? listener->getSearchableName().find(mFilterSubString) != std::string::npos : true);  	passed = passed && checkAgainstFilterType(listener);  	passed = passed && checkAgainstPermissions(listener);  	passed = passed && checkAgainstFilterLinks(listener); @@ -105,17 +100,12 @@ bool LLInventoryFilter::check(const LLFolderViewModelItem* item)  bool LLInventoryFilter::check(const LLInventoryItem* item)  { -	std::string::size_type string_offset = mFilterSubString.size() ? item->getName().find(mFilterSubString) : std::string::npos; - +	const bool passed_string = (mFilterSubString.size() ? item->getName().find(mFilterSubString) != std::string::npos : true);  	const bool passed_filtertype = checkAgainstFilterType(item);  	const bool passed_permissions = checkAgainstPermissions(item); -	const BOOL passed_clipboard = checkAgainstClipboard(item->getUUID()); -	const bool passed = (passed_filtertype  -		&& passed_permissions -		&& passed_clipboard  -		&&	(mFilterSubString.size() == 0 || string_offset != std::string::npos)); +	const bool passed_clipboard = checkAgainstClipboard(item->getUUID()); -	return passed; +	return passed_filtertype && passed_permissions && passed_clipboard && passed_string;  }  bool LLInventoryFilter::checkFolder(const LLFolderViewModelItem* item) const @@ -439,7 +429,7 @@ void LLInventoryFilter::updateFilterTypes(U64 types, U64& current_types)  		current_types = types;  		if (more_bits_set && fewer_bits_set)  		{ -			// neither less or more restrive, both simultaneously +			// neither less or more restrictive, both simultaneously  			// so we need to filter from scratch  			setModified(FILTER_RESTART);  		} @@ -714,7 +704,7 @@ void LLInventoryFilter::resetDefault()  void LLInventoryFilter::setModified(EFilterModified behavior)  {  	mFilterText.clear(); -	mCurrentGeneration = mNextFilterGeneration++; +	mCurrentGeneration++;  	if (mFilterModified == FILTER_NONE)  	{ @@ -1021,21 +1011,19 @@ LLInventoryFilter::EFolderShow LLInventoryFilter::getShowFolderState() const  	return mFilterOps.mShowFolderState;   } -void LLInventoryFilter::setFilterCount(S32 count)  -{  -	mFilterCount = count;  -} -S32 LLInventoryFilter::getFilterCount() const +bool LLInventoryFilter::isTimedOut()  { -	return mFilterCount; +	return mFilterTime.hasExpired();  } -void LLInventoryFilter::decrementFilterCount()  -{  -	mFilterCount--;  +void LLInventoryFilter::resetTime(S32 timeout) +{ +	mFilterTime.reset(); +    F32 time_in_sec = (F32)(timeout)/1000.0; +	mFilterTime.setTimerExpirySec(time_in_sec);  } -S32 LLInventoryFilter::getCurrentGeneration() const  +S32 LLInventoryFilter::getCurrentGeneration() const  {   	return mCurrentGeneration;  } diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h index 4912b5ca91..ce516af0b9 100755 --- a/indra/newview/llinventoryfilter.h +++ b/indra/newview/llinventoryfilter.h @@ -215,12 +215,11 @@ public:  	void 				setModified(EFilterModified behavior = FILTER_RESTART);  	// +-------------------------------------------------------------------+ -	// + Count +	// + Time  	// +-------------------------------------------------------------------+ -	void 				setFilterCount(S32 count); -	S32 				getFilterCount() const; -	void 				decrementFilterCount(); - +	void 				resetTime(S32 timeout); +    bool                isTimedOut(); +      	// +-------------------------------------------------------------------+  	// + Default  	// +-------------------------------------------------------------------+ @@ -262,13 +261,15 @@ private:  	const std::string		mName;  	S32						mCurrentGeneration; +    // The following makes checking for pass/no pass possible even if the item is not checked against the current generation +    // Any item that *did not pass* the "required generation" will *not pass* the current one +    // Any item that *passes* the "success generation" will *pass* the current one  	S32						mFirstRequiredGeneration;  	S32						mFirstSuccessGeneration; -	S32						mNextFilterGeneration; -	S32						mFilterCount;  	EFilterModified 		mFilterModified; - +	LLTimer                 mFilterTime; +      	std::string 			mFilterText;  	std::string 			mEmptyLookupMessage;  }; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index cf1fd4c0d0..e5b9e11d48 100755 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -192,7 +192,7 @@ LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )      p.show_item_link_overlays = mShowItemLinkOverlays;      p.root = NULL;      p.options_menu = "menu_inventory.xml"; -	 +      return LLUICtrlFactory::create<LLFolderView>(p);  } @@ -396,6 +396,7 @@ LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState()  	return getFilter().getShowFolderState();  } +// Called when something changed in the global model (new item, item coming through the wire, rename, move, etc...) (CHUI-849)  void LLInventoryPanel::modelChanged(U32 mask)  {  	static LLFastTimer::DeclareTimer FTM_REFRESH("Inventory Refresh"); diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 2d7454b636..90b169ecd3 100755 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -25,7 +25,7 @@   */  #include "llviewerprecompiledheaders.h" - +#include "llfloaterconversationpreview.h"  #include "llagent.h"  #include "llagentui.h"  #include "llavatarnamecache.h" @@ -206,6 +206,7 @@ private:  };  LLLogChat::save_history_signal_t * LLLogChat::sSaveHistorySignal = NULL; +LLLoadHistoryThread::load_end_signal_t * LLLoadHistoryThread::mLoadEndSignal = NULL;  //static  std::string LLLogChat::makeLogFileName(std::string filename) @@ -336,75 +337,83 @@ void LLLogChat::saveHistory(const std::string& filename,  void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params)  {  	if (file_name.empty()) -	{ -		llwarns << "Session name is Empty!" << llendl; -		return ; -	} - -	bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false; +				{ +					LL_WARNS("LLLogChat::loadChatHistory") << "Session name is Empty!" << LL_ENDL; +					return ; +				} -	LLFILE* fptr = LLFile::fopen(makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ -	if (!fptr) -	{ -		fptr = LLFile::fopen(oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ -		if (!fptr) -		{ -			return;						//No previous conversation with this name. -		} -	} -  -	char buffer[LOG_RECALL_SIZE];		/*Flawfinder: ignore*/ -	char *bptr; -	S32 len; -	bool firstline = TRUE; +				bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false; -	if (load_all_history || fseek(fptr, (LOG_RECALL_SIZE - 1) * -1  , SEEK_END)) -	{	//We need to load the whole historyFile or it's smaller than recall size, so get it all. -		firstline = FALSE; -		if (fseek(fptr, 0, SEEK_SET)) -		{ -			fclose(fptr); -			return; -		} -	} +				LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ +				if (!fptr) +				{ +					fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ +					if (!fptr) +					{ +						return;						//No previous conversation with this name. +					} +				} -	while (fgets(buffer, LOG_RECALL_SIZE, fptr)  && !feof(fptr))  -	{ -		len = strlen(buffer) - 1;		/*Flawfinder: ignore*/ -		for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--)	*bptr='\0'; -		 -		if (firstline) -		{ -			firstline = FALSE; -			continue; -		} +				char buffer[LOG_RECALL_SIZE];		/*Flawfinder: ignore*/ +				char *bptr; +				S32 len; +				bool firstline = TRUE; + +				if (load_all_history || fseek(fptr, (LOG_RECALL_SIZE - 1) * -1  , SEEK_END)) +				{	//We need to load the whole historyFile or it's smaller than recall size, so get it all. +					firstline = FALSE; +					if (fseek(fptr, 0, SEEK_SET)) +					{ +						fclose(fptr); +						return; +					} +				} +			while (fgets(buffer, LOG_RECALL_SIZE, fptr)  && !feof(fptr)) +				{ +					len = strlen(buffer) - 1;		/*Flawfinder: ignore*/ +					for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--)	*bptr='\0'; + +					if (firstline) +					{ +						firstline = FALSE; +						continue; +					} + +					std::string line(buffer); + +					//updated 1.23 plain text log format requires a space added before subsequent lines in a multilined message +					if (' ' == line[0]) +					{ +						line.erase(0, MULTI_LINE_PREFIX.length()); +						append_to_last_message(messages, '\n' + line); +					} +					else if (0 == len && ('\n' == line[0] || '\r' == line[0])) +					{ +						//to support old format's multilined messages with new lines used to divide paragraphs +						append_to_last_message(messages, line); +					} +					else +					{ +						LLSD item; +						if (!LLChatLogParser::parse(line, item, load_params)) +						{ +							item[LL_IM_TEXT] = line; +						} +						messages.push_back(item); +					} +				} +				fclose(fptr); -		std::string line(buffer); -		//updated 1.23 plaint text log format requires a space added before subsequent lines in a multilined message -		if (' ' == line[0]) -		{ -			line.erase(0, MULTI_LINE_PREFIX.length()); -			append_to_last_message(messages, '\n' + line); -		} -		else if (0 == len && ('\n' == line[0] || '\r' == line[0])) -		{ -			//to support old format's multilined messages with new lines used to divide paragraphs -			append_to_last_message(messages, line); -		} -		else -		{ -			LLSD item; -			if (!LLChatLogParser::parse(line, item, load_params)) -			{ -				item[LL_IM_TEXT] = line; -			} -			messages.push_back(item); -		} -	} -	fclose(fptr);  } +void LLLogChat::startChatHistoryThread(const std::string& file_name, const LLSD& load_params) +{ + +	LLLoadHistoryThread* mThread = new LLLoadHistoryThread(); +	mThread->start(); +	mThread->setHistoryParams(file_name, load_params); +}  // static  std::string LLLogChat::oldLogFileName(std::string filename)  { @@ -461,6 +470,13 @@ void LLLogChat::findTranscriptFiles(std::string pattern, std::vector<std::string  		LLFILE * filep = LLFile::fopen(fullname, "rb");  		if (NULL != filep)  		{ +			if(makeLogFileName("chat")== fullname) +			{ +				//Add Nearby chat history to the list of transcriptions +				list_of_transcriptions.push_back(gDirUtilp->add(dirname, filename)); +				LLFile::close(filep); +				return; +			}  			char buffer[LOG_RECALL_SIZE];  			fseek(filep, 0, SEEK_END);			// seek to end of file @@ -631,7 +647,7 @@ void LLLogChat::deleteTranscripts()  }  // static -bool LLLogChat::isTranscriptExist(const LLUUID& avatar_id) +bool LLLogChat::isTranscriptExist(const LLUUID& avatar_id, bool is_group)  {  	std::vector<std::string> list_of_transcriptions;  	LLLogChat::getListOfTranscriptFiles(list_of_transcriptions); @@ -641,20 +657,53 @@ bool LLLogChat::isTranscriptExist(const LLUUID& avatar_id)  		LLAvatarName avatar_name;  		LLAvatarNameCache::get(avatar_id, &avatar_name);  		std::string avatar_user_name = avatar_name.getAccountName(); -		std::replace(avatar_user_name.begin(), avatar_user_name.end(), '.', '_'); - -		BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions) +		if(!is_group)  		{ -			if (std::string::npos != transcript_file_name.find(avatar_user_name)) +			std::replace(avatar_user_name.begin(), avatar_user_name.end(), '.', '_'); +			BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)  			{ -				return true; +				if (std::string::npos != transcript_file_name.find(avatar_user_name)) +				{ +					return true; +				}  			}  		} +		else +		{ +			std::string file_name; +			gCacheName->getGroupName(avatar_id, file_name); +			file_name = makeLogFileName(file_name); +			BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions) +			{ +				if (transcript_file_name == file_name) +				{ +					return true; +				} +			} +		} +  	}  	return false;  } +bool LLLogChat::isNearbyTranscriptExist() +{ +	std::vector<std::string> list_of_transcriptions; +	LLLogChat::getListOfTranscriptFiles(list_of_transcriptions); + +	std::string file_name; +	file_name = makeLogFileName("chat"); +	BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions) +	{ +	   	if (transcript_file_name == file_name) +	   	{ +			return true; +		 } +	} +	return false; +} +  //*TODO mark object's names in a special way so that they will be distinguishable form avatar name   //which are more strict by its nature (only firstname and secondname)  //Example, an object's name can be written like "Object <actual_object's_name>" @@ -795,3 +844,116 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params  	im[LL_IM_TEXT] = name_and_text[IDX_TEXT];  	return true;  //parsed name and message text, maybe have a timestamp too  } + + + +	LLLoadHistoryThread::LLLoadHistoryThread() : LLThread("load chat history") + 	{ +		mNewLoad = false; +	} + +	void LLLoadHistoryThread::run() +	{ +		while (!LLApp::isQuitting()) +			{ +			    if(mNewLoad) +				{ +					loadHistory(mFileName,mMessages,mLoadParams); +					shutdown(); +				} +			} +	} +	void LLLoadHistoryThread::setHistoryParams(const std::string& file_name, const LLSD& load_params) +	{ +		mFileName = file_name; +		mLoadParams = load_params; +		mNewLoad = true; +	} +	void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params) +	{ + +		if (file_name.empty()) +			{ +			LL_WARNS("LLLogChat::loadHistory") << "Session name is Empty!" << LL_ENDL; +				return ; +			} + +			bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false; + +			LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ +			if (!fptr) +			{ +				fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ +				if (!fptr) +				{ +					mNewLoad = false; +					(*mLoadEndSignal)(messages, file_name); +					return;						//No previous conversation with this name. +				} +			} + +			char buffer[LOG_RECALL_SIZE];		/*Flawfinder: ignore*/ +			char *bptr; +			S32 len; +			bool firstline = TRUE; + +			if (load_all_history || fseek(fptr, (LOG_RECALL_SIZE - 1) * -1  , SEEK_END)) +			{	//We need to load the whole historyFile or it's smaller than recall size, so get it all. +				firstline = FALSE; +				if (fseek(fptr, 0, SEEK_SET)) +				{ +					fclose(fptr); +					mNewLoad = false; +					(*mLoadEndSignal)(messages, file_name); +					return; +				} +			} +		while (fgets(buffer, LOG_RECALL_SIZE, fptr)  && !feof(fptr)) +			{ +				len = strlen(buffer) - 1;		/*Flawfinder: ignore*/ +				for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--)	*bptr='\0'; + +				if (firstline) +				{ +					firstline = FALSE; +					continue; +				} + +				std::string line(buffer); + +				//updated 1.23 plaint text log format requires a space added before subsequent lines in a multilined message +				if (' ' == line[0]) +				{ +					line.erase(0, MULTI_LINE_PREFIX.length()); +					append_to_last_message(messages, '\n' + line); +				} +				else if (0 == len && ('\n' == line[0] || '\r' == line[0])) +				{ +					//to support old format's multilined messages with new lines used to divide paragraphs +					append_to_last_message(messages, line); +				} +				else +				{ +					LLSD item; +					if (!LLChatLogParser::parse(line, item, load_params)) +					{ +						item[LL_IM_TEXT] = line; +					} +					messages.push_back(item); +				} +			} +			fclose(fptr); +			mNewLoad = false; +			(*mLoadEndSignal)(messages, file_name); +	} + +	//static +	boost::signals2::connection LLLoadHistoryThread::setLoadEndSignal(const load_end_signal_t::slot_type& cb) +	{ +		if (NULL == mLoadEndSignal) +		{ +			mLoadEndSignal = new load_end_signal_t(); +		} + +		return mLoadEndSignal->connect(cb); +	} diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index e819f00dd9..acee99afa2 100755 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -28,6 +28,24 @@  #define LL_LLLOGCHAT_H  class LLChat; +class LLLoadHistoryThread : public LLThread +{ +private: +	std::string mFileName; +	std::list<LLSD> mMessages; +	LLSD mLoadParams; +	bool mNewLoad; +public: +	LLLoadHistoryThread(); + +	void setHistoryParams(const std::string& file_name, const LLSD& load_params); +	virtual void loadHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params); +    virtual void run(); + +   typedef boost::signals2::signal<void (std::list<LLSD>& messages,const std::string& file_name)> load_end_signal_t; +   static load_end_signal_t * mLoadEndSignal; +   static boost::signals2::connection setLoadEndSignal(const load_end_signal_t::slot_type& cb); +};  class LLLogChat  { @@ -39,6 +57,7 @@ public:  		LOG_LLSD,  		LOG_END  	}; +  	static std::string timestamp(bool withdate = false);  	static std::string makeLogFileName(std::string(filename));  	/** @@ -54,6 +73,7 @@ public:  	static void getListOfTranscriptBackupFiles(std::vector<std::string>& list_of_transcriptions);  	static void loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params = LLSD()); +	static void startChatHistoryThread(const std::string& file_name, const LLSD& load_params);  	typedef boost::signals2::signal<void ()> save_history_signal_t;  	static boost::signals2::connection setSaveHistorySignal(const save_history_signal_t::slot_type& cb); @@ -67,7 +87,8 @@ public:  		std::vector<std::string>& listOfFilesToMove);  	static void deleteTranscripts(); -	static bool isTranscriptExist(const LLUUID& avatar_id); +	static bool isTranscriptExist(const LLUUID& avatar_id, bool is_group=false); +	static bool isNearbyTranscriptExist();  private:  	static std::string cleanFileName(std::string filename); @@ -126,6 +147,7 @@ protected:  	virtual ~LLChatLogParser() {};  }; +  // LLSD map lookup constants  extern const std::string LL_IM_TIME; //("time");  extern const std::string LL_IM_TEXT; //("message"); diff --git a/indra/newview/llnotificationstorage.h b/indra/newview/llnotificationstorage.h index 7aabf7d09e..53fd898ea4 100755 --- a/indra/newview/llnotificationstorage.h +++ b/indra/newview/llnotificationstorage.h @@ -44,6 +44,7 @@ public:  protected:  	bool writeNotifications(const LLSD& pNotificationData) const;  	bool readNotifications(LLSD& pNotificationData) const; +	void setFileName(std::string pFileName) {mFileName = pFileName;}  	LLNotificationResponderInterface* createResponder(const std::string& pNotificationName, const LLSD& pParams) const; diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp index a85335f1ba..4ca961c1f9 100755 --- a/indra/newview/llnotificationtiphandler.cpp +++ b/indra/newview/llnotificationtiphandler.cpp @@ -83,13 +83,6 @@ bool LLTipHandler::processNotification(const LLNotificationPtr& notification)  	if (notification->canLogToChat())  	{  		LLHandlerUtil::logToNearbyChat(notification, CHAT_SOURCE_SYSTEM); - -		// don't show toast if Nearby Chat is opened -		LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); -		if (nearby_chat->isChatVisible()) -		{ -			return false; -		}  	}  	std::string session_name = notification->getPayload()["SESSION_NAME"]; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index bcb90bcb56..911ecaad9d 100755 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -82,10 +82,6 @@ const S32 MAX_PASSWORD = 16;  LLPanelLogin *LLPanelLogin::sInstance = NULL;  BOOL LLPanelLogin::sCapslockDidNotification = FALSE; -// Helper for converting a user name into the canonical "Firstname Lastname" form. -// For new accounts without a last name "Resident" is added as a last name. -static std::string canonicalize_username(const std::string& name); -  class LLLoginRefreshHandler : public LLCommandHandler  {  public: @@ -266,7 +262,6 @@ void LLPanelLogin::addFavoritesToStartLocation()  	// Load favorites into the combo.  	std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple(); -	std::string canonical_user_name = canonicalize_username(user_defined_name);  	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");  	LLSD fav_llsd;  	llifstream file; @@ -279,7 +274,7 @@ void LLPanelLogin::addFavoritesToStartLocation()  		// The account name in stored_favorites.xml has Resident last name even if user has  		// a single word account name, so it can be compared case-insensitive with the  		// user defined "firstname lastname". -		S32 res = LLStringUtil::compareInsensitive(canonical_user_name, iter->first); +		S32 res = LLStringUtil::compareInsensitive(user_defined_name, iter->first);  		if (res != 0)  		{  			lldebugs << "Skipping favorites for " << iter->first << llendl; @@ -1012,29 +1007,3 @@ void LLPanelLogin::onLocationSLURL()  	LLStartUp::setStartSLURL(location); // calls onUpdateStartSLURL, above   } - - -std::string canonicalize_username(const std::string& name) -{ -	std::string cname = name; -	LLStringUtil::trim(cname); - -	// determine if the username is a first/last form or not. -	size_t separator_index = cname.find_first_of(" ._"); -	std::string first = cname.substr(0, separator_index); -	std::string last; -	if (separator_index != cname.npos) -	{ -		last = cname.substr(separator_index+1, cname.npos); -		LLStringUtil::trim(last); -	} -	else -	{ -		// ...on Linden grids, single username users as considered to have -		// last name "Resident" -		last = "Resident"; -	} - -	// Username in traditional "firstname lastname" form. -	return first + ' ' + last; -} diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index d6535c88e9..53deded2f2 100755 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -130,6 +130,8 @@ BOOL LLPanelMainInventory::postBuild()  	mFilterTabs = getChild<LLTabContainer>("inventory filter tabs");  	mFilterTabs->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterSelected, this)); +    mCounterCtrl = getChild<LLUICtrl>("ItemcountText"); +      	//panel->getFilter().markDefault();  	// Set up the default inv. panel/filter settings. @@ -566,7 +568,7 @@ void LLPanelMainInventory::draw()  void LLPanelMainInventory::updateItemcountText()  {  	// *TODO: Calling setlocale() on each frame may be inefficient. -	LLLocale locale(LLStringUtil::getLocale()); +	//LLLocale locale(LLStringUtil::getLocale());  	std::string item_count_string;  	LLResMgr::getInstance()->getIntegerString(item_count_string, gInventory.getItemCount()); @@ -589,8 +591,7 @@ void LLPanelMainInventory::updateItemcountText()  		text = getString("ItemcountUnknown");  	} -	// *TODO: Cache the LLUICtrl* for the ItemcountText control -	getChild<LLUICtrl>("ItemcountText")->setValue(text); +    mCounterCtrl->setValue(text);  }  void LLPanelMainInventory::onFocusReceived() diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index 899931aa89..394b004e20 100755 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -121,6 +121,7 @@ private:  	LLFilterEditor*				mFilterEditor;  	LLTabContainer*				mFilterTabs; +    LLUICtrl*                   mCounterCtrl;  	LLHandle<LLFloater>			mFinderHandle;  	LLInventoryPanel*			mActivePanel;  	bool						mResortActivePanel; diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index e2e7006773..5acc98904b 100755 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -36,6 +36,8 @@  #include "lltabcontainer.h"  #include "llviewercontrol.h"  #include "llviewernetwork.h" +#include "llmutelist.h" +#include "llpanelblockedlist.h"  static const std::string PANEL_PICKS = "panel_picks"; @@ -137,6 +139,12 @@ public:  			return true;  		} +		if (verb == "removefriend") +		{ +			LLAvatarActions::removeFriendDialog(avatar_id); +			return true; +		} +  		if (verb == "mute")  		{  			if (! LLAvatarActions::isBlocked(avatar_id)) @@ -155,6 +163,18 @@ public:  			return true;  		} +		if (verb == "block") +		{ +			if (params.size() > 2) +			{ +				const std::string object_name = params[2].asString(); +				LLMute mute(avatar_id, object_name, LLMute::OBJECT); +				LLMuteList::getInstance()->add(mute); +				LLPanelBlockedList::showPanelAndSelect(mute.mID); +			} +			return true; +		} +  		return false;  	}  }; diff --git a/indra/newview/llpersistentnotificationstorage.cpp b/indra/newview/llpersistentnotificationstorage.cpp index 666f10df96..076c3e0235 100755 --- a/indra/newview/llpersistentnotificationstorage.cpp +++ b/indra/newview/llpersistentnotificationstorage.cpp @@ -38,7 +38,8 @@  LLPersistentNotificationStorage::LLPersistentNotificationStorage()  	: LLSingleton<LLPersistentNotificationStorage>() -	, LLNotificationStorage(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml")) +	, LLNotificationStorage("") +	, mLoaded(false)  {  } @@ -89,8 +90,13 @@ void LLPersistentNotificationStorage::loadNotifications()  	LL_INFOS("LLPersistentNotificationStorage") << "start loading notifications" << LL_ENDL; -	LLNotifications::instance().getChannel("Persistent")-> -		connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1)); +	if (mLoaded) +	{ +		LL_INFOS("LLPersistentNotificationStorage") << "notifications already loaded, exiting" << LL_ENDL; +		return; +	} + +	mLoaded = true;  	LLSD input;  	if (!readNotifications(input) ||input.isUndefined()) @@ -135,8 +141,20 @@ void LLPersistentNotificationStorage::loadNotifications()  	LL_INFOS("LLPersistentNotificationStorage") << "finished loading notifications" << LL_ENDL;  } +void LLPersistentNotificationStorage::initialize() +{ +	setFileName(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml")); +	LLNotifications::instance().getChannel("Persistent")-> +		connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1)); +} +  bool LLPersistentNotificationStorage::onPersistentChannelChanged(const LLSD& payload)  { +	// In case we received channel changed signal but haven't yet loaded notifications, do it +	if (!mLoaded) +	{ +		loadNotifications(); +	}  	// we ignore "load" messages, but rewrite the persistence file on any other  	const std::string sigtype = payload["sigtype"].asString();  	if ("load" != sigtype) diff --git a/indra/newview/llpersistentnotificationstorage.h b/indra/newview/llpersistentnotificationstorage.h index 98a825d2c1..bf0306380e 100755 --- a/indra/newview/llpersistentnotificationstorage.h +++ b/indra/newview/llpersistentnotificationstorage.h @@ -53,10 +53,13 @@ public:  	void saveNotifications();  	void loadNotifications(); +	void initialize(); +  protected:  private:  	bool onPersistentChannelChanged(const LLSD& payload); +	bool mLoaded;  };  #endif // LL_LLPERSISTENTNOTIFICATIONSTORAGE_H diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index cff3a7e02a..67a76460a7 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -51,6 +51,7 @@  #include "lllandmark.h"  #include "llcachename.h"  #include "lldir.h" +#include "lldonotdisturbnotificationstorage.h"  #include "llerrorcontrol.h"  #include "llfloaterreg.h"  #include "llfocusmgr.h" @@ -68,6 +69,7 @@  #include "llfloaterimnearbychat.h"  #include "llnotifications.h"  #include "llnotificationsutil.h" +#include "llpersistentnotificationstorage.h"  #include "llteleporthistory.h"  #include "llregionhandle.h"  #include "llsd.h" @@ -900,6 +902,10 @@ bool idle_startup()  		gDirUtilp->setLindenUserDir(userid);  		LLFile::mkdir(gDirUtilp->getLindenUserDir()); +		// As soon as directories are ready initialize notification storages +		LLPersistentNotificationStorage::getInstance()->initialize(); +		LLDoNotDisturbNotificationStorage::getInstance()->initialize(); +  		// Set PerAccountSettingsFile to the default value.  		gSavedSettings.setString("PerAccountSettingsFile",  			gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,  diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index e92bd766ca..1a3add2bfb 100755 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -423,9 +423,18 @@ void LLNotificationWellWindow::onItemClick(LLSysWellItem* item)  void LLNotificationWellWindow::onItemClose(LLSysWellItem* item)  {  	LLUUID id = item->getID(); -	removeItemByID(id); +	  	if(mChannel) +	{ +		// removeItemByID() is invoked from killToastByNotificationID() and item will removed;  		mChannel->killToastByNotificationID(id); +	} +	else +	{ +		// removeItemByID() should be called one time for each item to remove it from notification well +		removeItemByID(id); +	} +  }  void LLNotificationWellWindow::onAdd( LLNotificationPtr notify ) diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp index 75e6e3d13a..025ef3945d 100755 --- a/indra/newview/lltoastimpanel.cpp +++ b/indra/newview/lltoastimpanel.cpp @@ -28,6 +28,7 @@  #include "lltoastimpanel.h"  #include "llagent.h" +#include "llavatarnamecache.h"  #include "llfloaterreg.h"  #include "llgroupactions.h"  #include "llgroupiconctrl.h" @@ -61,6 +62,15 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) :	LLToastPanel(p.notif  	style_params.font.name(font_name);  	style_params.font.size(font_size); +	LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(p.session_id); +	mIsGroupMsg = (im_session->mSessionType == LLIMModel::LLIMSession::GROUP_SESSION); +	if(mIsGroupMsg) +	{ +		mAvatarName->setValue(im_session->mName); +		LLAvatarName avatar_name; +		LLAvatarNameCache::get(p.avatar_id, &avatar_name); +		p.message = "[From " + avatar_name.getDisplayName() + "]\n" + p.message; +	}  	//Handle IRC styled /me messages.  	std::string prefix = p.message.substr(0, 4); @@ -81,12 +91,17 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) :	LLToastPanel(p.notif  		mMessage->setText(p.message, style_params);  	} -	mAvatarName->setValue(p.from); +	if(!mIsGroupMsg) +	{ +		mAvatarName->setValue(p.from); +	}  	mTime->setValue(p.time);  	mSessionID = p.session_id;  	mAvatarID = p.avatar_id;  	mNotification = p.notification; + +  	initIcon();  	S32 maxLinesCount; @@ -147,7 +162,14 @@ void LLToastIMPanel::spawnNameToolTip()  	LLToolTip::Params params;  	params.background_visible(false); -	params.click_callback(boost::bind(&LLFloaterReg::showInstance, "inspect_avatar", LLSD().with("avatar_id", mAvatarID), FALSE)); +	if(!mIsGroupMsg) +	{ +		params.click_callback(boost::bind(&LLFloaterReg::showInstance, "inspect_avatar", LLSD().with("avatar_id", mAvatarID), FALSE)); +	} +	else +	{ +		params.click_callback(boost::bind(&LLFloaterReg::showInstance, "inspect_group", LLSD().with("group_id", mSessionID), FALSE)); +	}  	params.delay_time(0.0f);		// spawn instantly on hover  	params.image(LLUI::getUIImage("Info_Small"));  	params.message(""); diff --git a/indra/newview/lltoastimpanel.h b/indra/newview/lltoastimpanel.h index 3eb11fb3bc..767617dabc 100755 --- a/indra/newview/lltoastimpanel.h +++ b/indra/newview/lltoastimpanel.h @@ -73,6 +73,8 @@ private:  	LLTextBox*			mAvatarName;  	LLTextBox*			mTime;  	LLTextBox*			mMessage; + +	bool                mIsGroupMsg;  };  #endif // LLTOASTIMPANEL_H_ diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp index b2318f9158..4f2c99fba8 100755 --- a/indra/newview/lltoolbarview.cpp +++ b/indra/newview/lltoolbarview.cpp @@ -180,13 +180,13 @@ S32 LLToolBarView::stopCommandInProgress(const LLCommandId& commandId)  	return command_location;  } -S32 LLToolBarView::flashCommand(const LLCommandId& commandId, bool flash) +S32 LLToolBarView::flashCommand(const LLCommandId& commandId, bool flash, bool force_flashing/* = false */)  {  	S32 command_location = hasCommand(commandId);  	if (command_location != TOOLBAR_NONE)  	{ -		mToolbars[command_location]->flashCommand(commandId, flash); +		mToolbars[command_location]->flashCommand(commandId, flash, force_flashing);  	}  	return command_location; diff --git a/indra/newview/lltoolbarview.h b/indra/newview/lltoolbarview.h index 7125dd9990..dcc3862074 100755 --- a/indra/newview/lltoolbarview.h +++ b/indra/newview/lltoolbarview.h @@ -90,7 +90,7 @@ public:  	S32 removeCommand(const LLCommandId& commandId, int& rank);	// Sets the rank the removed command was at, RANK_NONE if not found  	S32 enableCommand(const LLCommandId& commandId, bool enabled);  	S32 stopCommandInProgress(const LLCommandId& commandId); -	S32 flashCommand(const LLCommandId& commandId, bool flash); +	S32 flashCommand(const LLCommandId& commandId, bool flash, bool force_flashing = false);  	// Loads the toolbars from the existing user or default settings  	bool loadToolbars(bool force_default = false);	// return false if load fails diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index ace16396db..61353dba7d 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -259,11 +259,15 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response)  		    break;  	    } -	    LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); -	    modified_form->setElementEnabled("Accept", false); -	    modified_form->setElementEnabled("Decline", false); -	    notification_ptr->updateForm(modified_form); -	    notification_ptr->repost(); +		// TODO: this set of calls has undesirable behavior under Windows OS (CHUI-985): +		// here appears three additional toasts instead one modified +		// need investigation and fix + +	    // LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); +	    // modified_form->setElementEnabled("Accept", false); +	    // modified_form->setElementEnabled("Decline", false); +	    // notification_ptr->updateForm(modified_form); +	    // notification_ptr->repost();      }  	return false; @@ -2649,7 +2653,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  			{  				send_do_not_disturb_message(msg, from_id);  			} -			else +			 +			if (!is_muted)  			{  				LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL;  				// Read the binary bucket for more information. @@ -3673,6 +3678,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)  		LLSD msg_notify = LLSD(LLSD::emptyMap());  		msg_notify["session_id"] = LLUUID();          msg_notify["from_id"] = chat.mFromID; +		msg_notify["source_type"] = chat.mSourceType;          on_new_message(msg_notify);  	}  } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 65a906d3c0..4c1d19f2f2 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1811,7 +1811,6 @@ void LLViewerWindow::initBase()  	gFloaterView = main_view->getChild<LLFloaterView>("Floater View");  	gFloaterView->setFloaterSnapView(main_view->getChild<LLView>("floater_snap_region")->getHandle());  	gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View"); -	  	// Console  	llassert( !gConsole ); diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index a9176595c7..f53995732f 100755 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -884,4 +884,19 @@    <color      name="blue"      value="0 0 1 1"/> + +  <!--Resize bar colors --> + +  <color +    name="ResizebarBorderLight" +    value="0.231 0.231 0.231 1"/> + +  <color +    name="ResizebarBorderDark" +    value="0.133 0.133 0.133 1"/> + +  <color +    name="ResizebarBody" +    value="0.208 0.208 0.208 1"/> +      </colors> diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index b0e4b71d21..54f60f4441 100755 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -774,4 +774,7 @@ with the same filename but different name    <texture name="Popup_Caution" file_name="icons/pop_up_caution.png"/>    <texture name="Camera_Drag_Dot" file_name="world/CameraDragDot.png"/>    <texture name="NavBar Separator" file_name="navbar/separator.png"/> + +  <texture name="Horizontal Drag Handle" file_name="widgets/horizontal_drag_handle.png"/> +  <texture name="Vertical Drag Handle" file_name="widgets/vertical_drag_handle.png"/>  </textures> diff --git a/indra/newview/skins/default/textures/widgets/horizontal_drag_handle.png b/indra/newview/skins/default/textures/widgets/horizontal_drag_handle.pngBinary files differ new file mode 100644 index 0000000000..642eac4065 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/horizontal_drag_handle.png diff --git a/indra/newview/skins/default/textures/widgets/vertical_drag_handle.png b/indra/newview/skins/default/textures/widgets/vertical_drag_handle.pngBinary files differ new file mode 100644 index 0000000000..b06b70cf36 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/vertical_drag_handle.png diff --git a/indra/newview/skins/default/xui/en/floater_im_container.xml b/indra/newview/skins/default/xui/en/floater_im_container.xml index 65f623a47e..1215efb7f9 100755 --- a/indra/newview/skins/default/xui/en/floater_im_container.xml +++ b/indra/newview/skins/default/xui/en/floater_im_container.xml @@ -4,6 +4,7 @@   can_minimize="true"   can_resize="true"   height="210" + min_height="210"   layout="topleft"   name="floater_im_box"   help_topic="floater_im_box" @@ -24,24 +25,28 @@       value="Conv_toolbar_expand"/>      <layout_stack       animate="true"  -     bottom="-1" +     bottom="-5" +     drag_handle_gap="6" +     drag_handle_first_indent="27" +     drag_handle_second_indent="10"       follows="all"       layout="topleft"       left="0"       name="conversations_stack"       orientation="horizontal"       right="-1" +     show_drag_handle="true"       top="0">          <layout_panel           auto_resize="false"           user_resize="true"                   name="conversations_layout_panel"           min_dim="38" -         expanded_min_dim="156"> +         expanded_min_dim="136">              <layout_stack               animate="false"                follows="left|top|right" -             height="35" +             height="27"               layout="topleft"               left="0"               name="conversations_pane_buttons_stack" @@ -50,7 +55,6 @@               top="0">                  <layout_panel                   auto_resize="true" -                 height="35"                   name="conversations_pane_buttons_expanded">                      <menu_button                       follows="top|left" @@ -64,7 +68,7 @@                       left="5"                       name="sort_btn"                       tool_tip="View/sort options" -                     top="5" +                     top="1"                       width="31" />                      <button                       follows="top|left" @@ -74,7 +78,7 @@                       image_selected="Toolbar_Middle_Selected"                       image_unselected="Toolbar_Middle_Off"                       layout="topleft" -                     top="5" +                     top="1"                       left_pad="2"                       name="add_btn"                       tool_tip="Start a new conversation" @@ -87,7 +91,7 @@                       image_selected="Toolbar_Middle_Selected"                       image_unselected="Toolbar_Middle_Off"                       layout="topleft" -                     top="5" +                     top="1"                       left_pad="2"                       name="speak_btn"                       tool_tip="Speak with people using your microphone" @@ -95,9 +99,8 @@                  </layout_panel>                  <layout_panel                   auto_resize="false" -                 height="35"                   name="conversations_pane_buttons_collapsed" -                 width="41"> +                 width="31">                      <button                       follows="right|top"                       height="25" @@ -106,8 +109,8 @@                       image_selected="Toolbar_Middle_Selected"                       image_unselected="Toolbar_Middle_Off"                       layout="topleft" -                     top="5" -                     left="1" +                     top="1" +                     left="0"                       name="expand_collapse_btn"                       tool_tip="Collapse/Expand this list"                       width="31" /> @@ -119,7 +122,7 @@               layout="topleft"               name="conversations_list_panel"               opaque="true" -             top="35" +             top_pad="0"               left="5"               right="-1"/>          </layout_panel> @@ -127,7 +130,7 @@           auto_resize="true"           user_resize="true"           name="messages_layout_panel" -         expanded_min_dim="222"> +         expanded_min_dim="212">              <panel_container               bottom="-1"               follows="all" @@ -136,44 +139,44 @@               name="im_box_tab_container"               right="-1"               top="0"> -             <panel -               bottom="-1" -               follows="all" -               layout="topleft" -               name="stub_panel" -               opaque="true" -               top_pad="0" -               left="0" -               right="-1"> -                 <button -                 follows="right|top" -                 height="25" -                 image_hover_unselected="Toolbar_Middle_Over" -                 image_overlay="Conv_toolbar_collapse" -                 image_selected="Toolbar_Middle_Selected" -                 image_unselected="Toolbar_Middle_Off" +                <panel +                 bottom="-1" +                 follows="all"                   layout="topleft" -                 top="5" -                 right="-10" -                 name="stub_collapse_btn" -                 tool_tip="Collapse this pane" -                 width="31" /> -                 <text -                   type="string" -                   clip_partial="false" -                   follows="left|top|right" -                   layout="topleft" -                   left="15" -                   right="-15" -                   name="stub_textbox" -                   top="25" -                   height="40" -                   valign="center" -                   parse_urls="true" -                   wrap="true"> -                   This conversation is in a separate window.   [secondlife:/// Bring it back.] -                 </text> -             </panel> +                 name="stub_panel" +                 opaque="true" +                 top_pad="0" +                 left="0" +                 right="-1"> +                    <button +                     follows="right|top" +                     height="25" +                     image_hover_unselected="Toolbar_Middle_Over" +                     image_overlay="Conv_toolbar_collapse" +                     image_selected="Toolbar_Middle_Selected" +                     image_unselected="Toolbar_Middle_Off" +                     layout="topleft" +                     top="1" +                     right="-10" +                     name="stub_collapse_btn" +                     tool_tip="Collapse this pane" +                     width="31" /> +                    <text +                     type="string" +                     clip_partial="false" +                     follows="left|top|right" +                     layout="topleft" +                     left="15" +                     right="-15" +                     name="stub_textbox" +                     top="25" +                     height="40" +                     valign="center" +                     parse_urls="true" +                     wrap="true"> +                         This conversation is in a separate window.   [secondlife:/// Bring it back.] +                    </text> +                </panel>              </panel_container>          </layout_panel>      </layout_stack> diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml index 2152a9f6e9..43d0f2fb18 100755 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -70,26 +70,23 @@       top="0"       left="0"       right="-1" -     bottom="-3"> +     bottom="-1">          <layout_stack           animate="false"  +         bottom="-1"           default_tab_group="2"           follows="all" -         right="-5" -         bottom="-1" -         top="0" -         left="5" -         border_size="0" +         left="3"           layout="topleft" -         orientation="vertical"           name="main_stack" -         tab_group="1"> +         right="-3" +         orientation="vertical" +         tab_group="1" +         top="0">              <layout_panel               auto_resize="false"               name="toolbar_panel" -             height="35" -             right="-1" -             left="1"> +             height="25">                  <menu_button                   menu_filename="menu_im_session_showmodes.xml"                   follows="top|left" @@ -102,7 +99,7 @@                   left="5"                   name="view_options_btn"                   tool_tip="View/sort options" -                 top="5" +                 top="1"                   width="31" />                  <menu_button                   menu_filename="menu_im_conversation.xml" @@ -113,7 +110,7 @@                   image_selected="Toolbar_Middle_Selected"                   image_unselected="Toolbar_Middle_Off"                   layout="topleft" -                 top="5" +                 top="1"                   left_pad="2"                   name="gear_btn"                   visible="false" @@ -128,7 +125,7 @@                   image_selected="Toolbar_Middle_Selected"                   image_unselected="Toolbar_Middle_Off"                   layout="topleft" -                 top="5" +                 top="1"                   left_pad="2"                   name="add_btn"                   tool_tip="Add someone to this conversation" @@ -141,23 +138,11 @@                   image_selected="Toolbar_Middle_Selected"                   image_unselected="Toolbar_Middle_Off"                   layout="topleft" -                 top="5" +                 top="1"                   left_pad="2"                   name="voice_call_btn"                   tool_tip="Open voice connection" -                 width="31"/> -                <output_monitor -                 auto_update="true" -                 follows="top|left" -                 draw_border="false" -                 height="16" -                 layout="topleft" -                 top="10" -                 left_pad="10" -                 mouse_opaque="true" -                 name="speaking_indicator" -                 visible="false" -                 width="20" /> +                 width="31"/>                                  <button                   follows="right|top"                   height="25" @@ -166,8 +151,8 @@                   image_selected="Toolbar_Middle_Selected"                   image_unselected="Toolbar_Middle_Off"                   layout="topleft" -                 top="5" -                 right="-67" +                 top="1" +                 right="-70"                   name="close_btn"                   tool_tip="End this conversation"                   width="31" /> @@ -179,7 +164,7 @@                   image_selected="Toolbar_Middle_Selected"                   image_unselected="Toolbar_Middle_Off"                   layout="topleft" -                 top="5" +                 top="1"                   left_pad="2"                   name="expand_collapse_btn"                   tool_tip="Collapse/Expand this pane" @@ -194,18 +179,21 @@                   layout="topleft"                   left_pad="2"                   name="tear_off_btn" -                 top="5" +                 top="1"                   width="31" />              </layout_panel>              <layout_panel               name="body_panel" -             top="1" -             bottom="-1"> +             height="235">                  <layout_stack                   default_tab_group="2" +                 drag_handle_gap="6" +                 drag_handle_first_indent="0" +                 drag_handle_second_indent="1"                   follows="all"                   orientation="horizontal"                   name="im_panels" +                 show_drag_handle="true"                   tab_group="1"                   top="0"                   right="-1" @@ -217,14 +205,12 @@                       min_dim="0"                       width="150"                        user_resize="true" -                     auto_resize="false"  -                     bottom="-1" /> +                     auto_resize="false" />                      <layout_panel                       default_tab_group="3"                       tab_group="2"                       name="right_part_holder" -                     min_width="221" -                     bottom="-1"> +                     min_width="172">                          <layout_stack                           animate="true"                            default_tab_group="2" @@ -233,7 +219,7 @@                           name="translate_and_chat_stack"                           tab_group="1"                           top="0" -                         left="0" +                         left="1"                           right="-1"                           bottom="-1">                              <layout_panel @@ -259,7 +245,7 @@                                   parse_highlights="true"                                   parse_urls="true"                                   right="-1" -                                 left="5" +                                 left="0"                                   top="0"                                   bottom="-1" />                              </layout_panel> @@ -268,10 +254,7 @@                  </layout_stack>              </layout_panel>              <layout_panel -             top_delta="0" -             top="0" -             height="26" -             bottom="-1" +             height="35"               auto_resize="false"               name="chat_layout_panel">                  <layout_stack @@ -281,15 +264,11 @@                   orientation="horizontal"                   name="input_panels"                   top="0" -                 bottom="-2" +                 bottom="-1"                   left="0"                   right="-1">                      <layout_panel -                     name="input_editor_layout_panel" -                     auto_resize="true" -                     user_resize="false" -                     top="0" -                     bottom="-1"> +                     name="input_editor_layout_panel">                          <chat_editor                           layout="topleft"                           expand_lines_count="5" @@ -302,32 +281,27 @@                           max_length="1023"                           spellcheck="true"                           tab_group="3" -                         top="1" -                         bottom="-2" -                         left="4" -                         right="-4" +                         bottom="-8" +                         left="5" +                         right="-5"                           wrap="true" />                      </layout_panel>                      <layout_panel                       auto_resize="false" -                     user_resize="false"                       name="input_button_layout_panel" -                     width="30" -                     top="0" -                     bottom="-1"> +                     width="32">                          <button -                         layout="topleft"                           left="1" -                         right="-1" -                         top="1" -                         height="22" +                         top="4" +                         height="25"                           follows="left|right|top"                           image_hover_unselected="Toolbar_Middle_Over"                           image_overlay="Conv_expand_one_line"                           image_selected="Toolbar_Middle_Selected"                           image_unselected="Toolbar_Middle_Off"                           name="minz_btn" -                         tool_tip="Shows/hides message panel" /> +                         tool_tip="Shows/hides message panel" +                         width="28" />                      </layout_panel>                  </layout_stack>              </layout_panel> diff --git a/indra/newview/skins/default/xui/en/menu_conversation.xml b/indra/newview/skins/default/xui/en/menu_conversation.xml index 5a13ef0a59..b3d28788da 100755 --- a/indra/newview/skins/default/xui/en/menu_conversation.xml +++ b/indra/newview/skins/default/xui/en/menu_conversation.xml @@ -11,7 +11,7 @@       layout="topleft"       name="close_conversation">          <on_click function="Avatar.DoToSelected" parameter="close_conversation"/> -	 </menu_item_call> +	 </menu_item_call>	        <menu_item_call       label="Open voice conversation"       layout="topleft" @@ -25,6 +25,12 @@          <on_click function="Avatar.DoToSelected" parameter="disconnect_from_voice"/>      </menu_item_call>	  	<menu_item_separator layout="topleft" name="separator_disconnect_from_voice"/>	 +	<menu_item_call +     label="Close Selected" +     layout="topleft" +     name="close_selected_conversations"> +        <on_click function="Avatar.DoToSelected" parameter="close_selected_conversations"/> +	 </menu_item_call>      <menu_item_call       label="View Profile"       layout="topleft" diff --git a/indra/newview/skins/default/xui/en/menu_people_friends_view.xml b/indra/newview/skins/default/xui/en/menu_people_friends_view.xml index dde9432867..8790fde7c5 100755 --- a/indra/newview/skins/default/xui/en/menu_people_friends_view.xml +++ b/indra/newview/skins/default/xui/en/menu_people_friends_view.xml @@ -44,6 +44,8 @@      <menu_item_check.on_check       function="Floater.Visible"       parameter="conversation" /> +    <menu_item_check.on_enable +     function="Conversation.IsConversationLoggingAllowed" />      <menu_item_check.on_click       function="Floater.Toggle"       parameter="conversation" /> diff --git a/indra/newview/skins/default/xui/en/menu_url_agent.xml b/indra/newview/skins/default/xui/en/menu_url_agent.xml index 7cd56f257a..e8b6116026 100755 --- a/indra/newview/skins/default/xui/en/menu_url_agent.xml +++ b/indra/newview/skins/default/xui/en/menu_url_agent.xml @@ -21,8 +21,15 @@       layout="topleft"       name="add_friend">          <menu_item_call.on_click -         function="Url.AddFriend" />         +         function="Url.AddFriend" />      </menu_item_call> +    <menu_item_call +     label="Remove Friend..." +     layout="topleft" +     name="remove_friend"> +        <menu_item_call.on_click +         function="Url.RemoveFriend" /> +        </menu_item_call>      <menu_item_separator       layout="topleft" />      <menu_item_call diff --git a/indra/newview/skins/default/xui/en/menu_url_objectim.xml b/indra/newview/skins/default/xui/en/menu_url_objectim.xml index 87ab58e622..b9d003b841 100755 --- a/indra/newview/skins/default/xui/en/menu_url_objectim.xml +++ b/indra/newview/skins/default/xui/en/menu_url_objectim.xml @@ -9,6 +9,13 @@          <menu_item_call.on_click           function="Url.Execute" />      </menu_item_call> +    <menu_item_call +     label="Block..." +     layout="topleft" +     name="block_object"> +        <menu_item_call.on_click +         function="Url.Block" /> +    </menu_item_call>      <menu_item_separator       layout="topleft" />      <menu_item_call diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index b01c3067ff..f253ed3e06 100755 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -874,6 +874,15 @@                   function="Tools.EnableSelectNextPart" />              </menu_item_call>          </menu> +        <menu_item_call +            label="Linksets..." +            name="pathfinding_linkset_menu_item"> +          <menu_item_call.on_click +              function="Floater.ToggleOrBringToFront" +              parameter="pathfinding_linksets" /> +          <menu_item_call.on_enable +              function="Tools.EnablePathfinding" /> +        </menu_item_call>           <menu_item_separator/>          <menu_item_call @@ -896,7 +905,7 @@            <menu_item_call.on_enable               function="Tools.SomethingSelectedNoHUD" />          </menu_item_call> - +		           <menu_item_separator/>          <menu diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 9e582cf0de..597f57eb0a 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -3709,6 +3709,17 @@ Leave Group?    </notification>    <notification +   icon="alertmodal.tga" +   name="OwnerCannotLeaveGroup" +   type="alertmodal"> +    Unable to leave group. You cannot leave the group because you are the last owner of the group. Please assign another member to the owner role first. +    <tag>group</tag> +    <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification     icon="alert.tga"     name="ConfirmKick"     type="alert"> @@ -5943,9 +5954,7 @@ Your calling card was declined.     icon="notifytip.tga"     name="TeleportToPerson"     type="notifytip"> -    To contact Residents like '[NAME]', click on the "People" button , select a Resident from the window that opens, then click 'IM' at the -    bottom of the window. -    (You can also double-click on their name in the list, or right-click and choose 'IM'). +    To open a private conversation with someone, right-click on their avatar and choose 'IM' from the menu.    </notification>    <notification @@ -6573,7 +6582,7 @@ Your object named <nolink>[OBJECTFROMNAME]</nolink> has given you th     icon="notify.tga"     name="JoinGroup"     persist="true" -   type="notify"> +   type="offer">      <tag>group</tag>  [MESSAGE]      <form name="form"> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml index bd096ebb88..8e867259c5 100755 --- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml @@ -14,6 +14,7 @@        border="false"        height="60"        layout="topleft" +      name="general_chat_settings"         top="10"        left="13"        width="517"> @@ -97,20 +98,13 @@        border="false"        height="165"        layout="topleft" +      name="im_notification_settings" 	        left="13"        width="517">      <text          layout="topleft"          height="12" -        name="notifications" -        left="0" -        width="120"> -      Notifications -    </text> -    <text -        layout="topleft" -        height="12"          name="friend_ims"          width="145"          left="0" @@ -138,17 +132,27 @@            name="FlashToolbarButton"            value="flash"/>        <item -          label="None" -          name="None" -          value="none"/> +          label="No action" +          name="NoAction" +          value="noaction"/>      </combo_box> +    <check_box +        control_name="PlaySoundFriendIM" +        height="23" +        label="Play sound" +        layout="topleft" +        name="play_sound_friend_im" +        left_pad="7" +        top_delta="-3" +        width="28"> +    </check_box>      <text          layout="topleft"          height="12"          name="non_friend_ims"          width="145"          left="0" -        top_pad="9"> +        top_pad="11">        Non-friend IMs:      </text>      <combo_box @@ -172,17 +176,27 @@            name="FlashToolbarButton"            value="flash"/>        <item -          label="None" -          name="None" -          value="none"/> +          label="No action" +          name="NoAction" +          value="noaction"/>      </combo_box> +    <check_box +        control_name="PlaySoundNonFriendIM" +        height="23" +        label="Play sound" +        layout="topleft" +        name="play_sound_non_friend_im" +        left_pad="7" +        top_delta="-3" +        width="28"> +    </check_box>      <text          layout="topleft"          left="0"          height="13"          name="conference_ims"          width="145" -        top_pad="9"> +        top_pad="11">        Conference IMs:      </text>      <combo_box @@ -206,17 +220,27 @@            name="FlashToolbarButton"            value="flash"/>        <item -          label="None" -          name="None" -          value="none"/> +          label="No action" +          name="NoAction" +          value="noaction"/>      </combo_box> +    <check_box +        control_name="PlaySoundConferenceIM" +        height="23" +        label="Play sound" +        layout="topleft" +        name="play_sound_conference_im" +        left_pad="7" +        top_delta="-3" +        width="28"> +    </check_box>      <text          layout="topleft"          left="0"          height="13"          name="group_chat"          width="145" -        top_pad="9"> +        top_pad="11">        Group chat:      </text>      <combo_box @@ -240,17 +264,27 @@            name="FlashToolbarButton"            value="flash"/>        <item -          label="None" -          name="None" -          value="none"/> +          label="No action" +          name="NoAction" +          value="noaction"/>      </combo_box> +    <check_box +        control_name="PlaySoundGroupChatIM" +        height="23" +        label="Play sound" +        layout="topleft" +        name="play_sound_group_chat_im" +        left_pad="7" +        top_delta="-3" +        width="28"> +    </check_box>      <text          layout="topleft"          left="0"          height="12"          name="nearby_chat"          width="145" -        top_pad="9"> +        top_pad="11">        Nearby chat:      </text>      <combo_box @@ -274,10 +308,64 @@            name="FlashToolBarButton"            value="flash"/>        <item -          label="None" -          name="None" -          value="none"/> +          label="No action" +          name="NoAction" +          value="noaction"/>      </combo_box> +    <check_box +        control_name="PlaySoundNearbyChatIM" +        height="23" +        label="Play sound" +        layout="topleft" +        name="play_sound_nearby_chat_im" +        left_pad="7" +        top_delta="-3" +        width="28"> +    </check_box> +    <text +        layout="topleft" +        left="0" +        height="12" +        name="object_ims" +        width="145" +        top_pad="11"> +      Object IMs: +    </text> +    <combo_box +        control_name="NotificationObjectIMOptions" +        height="23" +        layout="topleft" +        left_pad="5" +        top_delta="-6" +        name="ObjectIMOptions" +        width="223"> +      <item +          label="Open Conversations window" +          name="OpenConversationsWindow" +          value="openconversations"/> +      <item +          label="Pop up the message" +          name="PopUpMessage" +          value="toast"/> +      <item +          label="Flash toolbar button" +          name="FlashToolBarButton" +          value="flash"/> +      <item +          label="No action" +          name="NoAction" +          value="noaction"/> +    </combo_box> +    <check_box +        control_name="PlaySoundObjectIM" +        height="23" +        label="Play sound" +        layout="topleft" +        name="play_sound_object_im" +        left_pad="7" +        top_delta="-3" +        width="28"> +    </check_box>      <text          layout="topleft"          left="0" @@ -296,6 +384,7 @@        border="false"        height="50"        layout="topleft" +      name="play_sound_settings"  	        left="13"        top_pad="10"        width="517"> @@ -358,6 +447,7 @@    <panel        height="50"        layout="topleft" +      name="log_settings" 	        left="13"        top_pad="10"        width="505"> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index f7b33b0a4a..f1e551695f 100755 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -209,7 +209,8 @@ Please try logging in again in a minute.</string>  	<string name="SLappAgentIM">IM</string>  	<string name="SLappAgentPay">Pay</string>  	<string name="SLappAgentOfferTeleport">Offer Teleport to </string> -	<string name="SLappAgentRequestFriend">Friend Request </string> +	<string name="SLappAgentRequestFriend">Friend Request</string> +  <string name="SLappAgentRemoveFriend">Friend Removal</string>  	<!-- ButtonToolTips, llfloater.cpp -->  	<string name="BUTTON_CLOSE_DARWIN">Close (⌘W)</string> @@ -3927,5 +3928,8 @@ Try enclosing path to the editor with double quotes.    <string name="logging_calls_enabled_log_empty">      There are no logged conversations. After you contact someone, or someone contacts you, a log entry will be shown here.    </string> +  <string name="loading_chat_logs"> +    Loading... +  </string>    </strings> | 
