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