diff options
author | Tofu Linden <tofu.linden@lindenlab.com> | 2010-05-01 15:49:48 +0100 |
---|---|---|
committer | Tofu Linden <tofu.linden@lindenlab.com> | 2010-05-01 15:49:48 +0100 |
commit | 29e98032d1ad86686bee0fd58c65f95d1aeba439 (patch) | |
tree | 87b4ceb31b035cf03e08b7633289dbca92877419 /indra | |
parent | f92d7f282954d5f4601178603aa715ae74287957 (diff) | |
parent | 0cbdad70611201a94b9550598e61067faa1fac6b (diff) |
merge from viewer-trunk
Diffstat (limited to 'indra')
34 files changed, 723 insertions, 429 deletions
diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index ec247b25c3..bea2572ff8 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -297,6 +297,27 @@ void LLFlatListView::setNoItemsCommentText(const std::string& comment_text) mNoItemsCommentTextbox->setValue(comment_text); } +U32 LLFlatListView::size(const bool only_visible_items) const +{ + if (only_visible_items) + { + U32 size = 0; + for (pairs_const_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + if ((*iter)->first->getVisible()) + ++size; + } + return size; + } + else + { + return mItemPairs.size(); + } +} + void LLFlatListView::clear() { // do not use LLView::deleteAllChildren to avoid removing nonvisible items. drag-n-drop for ex. @@ -426,7 +447,7 @@ void LLFlatListView::rearrangeItems() { static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); - setNoItemsCommentVisible(mItemPairs.empty()); + setNoItemsCommentVisible(0==size()); if (mItemPairs.empty()) return; @@ -745,19 +766,43 @@ LLRect LLFlatListView::getLastSelectedItemRect() void LLFlatListView::selectFirstItem () { // No items - no actions! - if (mItemPairs.empty()) return; + if (0 == size()) return; - selectItemPair(mItemPairs.front(), true); - ensureSelectedVisible(); + // Select first visible item + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + // skip invisible items + if ( (*iter)->first->getVisible() ) + { + selectItemPair(*iter, true); + ensureSelectedVisible(); + break; + } + } } void LLFlatListView::selectLastItem () { // No items - no actions! - if (mItemPairs.empty()) return; + if (0 == size()) return; - selectItemPair(mItemPairs.back(), true); - ensureSelectedVisible(); + // Select last visible item + for (pairs_list_t::reverse_iterator + r_iter = mItemPairs.rbegin(), + r_iter_end = mItemPairs.rend(); + r_iter != r_iter_end; ++r_iter) + { + // skip invisible items + if ( (*r_iter)->first->getVisible() ) + { + selectItemPair(*r_iter, true); + ensureSelectedVisible(); + break; + } + } } void LLFlatListView::ensureSelectedVisible() @@ -775,14 +820,14 @@ void LLFlatListView::ensureSelectedVisible() bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selection) { // No items - no actions! - if ( !mItemPairs.size() ) + if ( 0 == size() ) return false; - - item_pair_t* to_sel_pair = NULL; - item_pair_t* cur_sel_pair = NULL; if ( mSelectedItemPairs.size() ) { + item_pair_t* to_sel_pair = NULL; + item_pair_t* cur_sel_pair = NULL; + // Take the last selected pair cur_sel_pair = mSelectedItemPairs.back(); // Bases on given direction choose next item to select @@ -816,42 +861,42 @@ bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selecti } } } + + if ( to_sel_pair ) + { + bool select = true; + if ( reset_selection ) + { + // Reset current selection if we were asked about it + resetSelection(); + } + else + { + // If item already selected and no reset request than we should deselect last selected item. + select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair)); + } + // Select/Deselect next item + selectItemPair(select ? to_sel_pair : cur_sel_pair, select); + return true; + } } else { // If there weren't selected items then choose the first one bases on given direction - cur_sel_pair = (is_up_direction) ? mItemPairs.back() : mItemPairs.front(); // Force selection to first item - to_sel_pair = cur_sel_pair; - } - - - if ( to_sel_pair ) - { - bool select = true; - - if ( reset_selection ) - { - // Reset current selection if we were asked about it - resetSelection(); - } + if (is_up_direction) + selectLastItem(); else - { - // If item already selected and no reset request than we should deselect last selected item. - select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair)); - } - - // Select/Deselect next item - selectItemPair(select ? to_sel_pair : cur_sel_pair, select); - + selectFirstItem(); return true; } + return false; } BOOL LLFlatListView::canSelectAll() const { - return !mItemPairs.empty() && mAllowSelection && mMultipleSelection; + return 0 != size() && mAllowSelection && mMultipleSelection; } void LLFlatListView::selectAll() @@ -1167,4 +1212,51 @@ void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string) } +void LLFlatListViewEx::setFilterSubString(const std::string& filter_str) +{ + if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString)) + { + mFilterSubString = filter_str; + updateNoItemsMessage(mFilterSubString); + filterItems(); + } +} + +void LLFlatListViewEx::filterItems() +{ + typedef std::vector <LLPanel*> item_panel_list_t; + + std::string cur_filter = mFilterSubString; + LLStringUtil::toUpper(cur_filter); + + LLSD action; + action.with("match_filter", cur_filter); + + item_panel_list_t items; + getItems(items); + + for (item_panel_list_t::iterator + iter = items.begin(), + iter_end = items.end(); + iter != iter_end; ++iter) + { + LLPanel* pItem = (*iter); + // 0 signifies that filter is matched, + // i.e. we don't hide items that don't support 'match_filter' action, separators etc. + if (0 == pItem->notify(action)) + { + pItem->setVisible(true); + } + else + { + // TODO: implement (re)storing of current selection. + selectItem(pItem, false); + pItem->setVisible(false); + } + } + + rearrangeItems(); + notifyParentItemsRectChanged(); +} + //EOF diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index 4f718ab0dc..6395805aab 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -264,9 +264,8 @@ public: /** Get number of selected items in the list */ U32 numSelected() const {return mSelectedItemPairs.size(); } - /** Get number of items in the list */ - U32 size() const { return mItemPairs.size(); } - + /** Get number of (visible) items in the list */ + U32 size(const bool only_visible_items = true) const; /** Removes all items from the list */ virtual void clear(); @@ -464,6 +463,17 @@ public: void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; } void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; } + /** + * Sets up new filter string and filters the list. + */ + void setFilterSubString(const std::string& filter_str); + + /** + * Filters the list, rearranges and notifies parent about shape changes. + * Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration. + */ + void filterItems(); + protected: LLFlatListViewEx(const Params& p); @@ -478,6 +488,7 @@ protected: private: std::string mNoFilteredItemsMsg; std::string mNoItemsMsg; + std::string mFilterSubString; }; #endif diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index a96ad7e796..f8fde0319e 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -2881,10 +2881,13 @@ void LLSplashScreenWin32::updateImpl(const std::string& mesg) if( output_str_len>1024 ) return; - WCHAR w_mesg[1024]; + WCHAR w_mesg[1025];//big enought to keep null terminatos MultiByteToWideChar (CP_UTF8, 0, mesg.c_str(), mesg.length(), w_mesg, output_str_len); + //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858 + w_mesg[output_str_len] = 0; + SendDlgItemMessage(mWindow, 666, // HACK: text id WM_SETTEXT, diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 98aa860b41..8c188461b2 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8086,17 +8086,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>ShowDebugAppearanceEditor</key> - <map> - <key>Comment</key> - <string>Show debugging appearance editor</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>ShowEmptyFoldersWhenSearching</key> <map> <key>Comment</key> diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp index b8222ebb18..1925b818f2 100644 --- a/indra/newview/llcofwearables.cpp +++ b/indra/newview/llcofwearables.cpp @@ -34,10 +34,13 @@ #include "llcofwearables.h" +#include "llagentdata.h" #include "llappearancemgr.h" #include "llinventory.h" -#include "llinventoryitemslist.h" #include "llinventoryfunctions.h" +#include "llwearableitemslist.h" + +static LLRegisterPanelClassWrapper<LLCOFAccordionListAdaptor> t_cof_accodion_list_adaptor("accordion_list_adaptor"); static LLRegisterPanelClassWrapper<LLCOFWearables> t_cof_wearables("cof_wearables"); @@ -89,9 +92,18 @@ void LLCOFWearables::onSelectionChange(LLFlatListView* selected_list) onCommit(); } -#include "llwearableitemslist.h" void LLCOFWearables::refresh() { + typedef std::vector<LLSD> values_vector_t; + typedef std::map<LLFlatListView*, values_vector_t> selection_map_t; + + selection_map_t preserve_selection; + + // Save current selection + mAttachments->getSelectedValues(preserve_selection[mAttachments]); + mClothing->getSelectedValues(preserve_selection[mClothing]); + mBodyParts->getSelectedValues(preserve_selection[mBodyParts]); + clear(); LLInventoryModel::cat_array_t cats; @@ -106,6 +118,23 @@ void LLCOFWearables::refresh() LLAppearanceMgr::getInstance()->divvyWearablesByType(cof_items, clothing_by_type); populateClothingList(clothing_by_type); + + // Restore previous selection + for (selection_map_t::iterator + iter = preserve_selection.begin(), + iter_end = preserve_selection.end(); + iter != iter_end; ++iter) + { + LLFlatListView* list = iter->first; + const values_vector_t& values = iter->second; + for (values_vector_t::const_iterator + value_it = values.begin(), + value_it_end = values.end(); + value_it != value_it_end; ++value_it) + { + list->selectItemByValue(*value_it); + } + } } @@ -126,9 +155,10 @@ void LLCOFWearables::populateAttachmentsAndBodypartsLists(const LLInventoryModel } else if (item_type == LLAssetType::AT_BODYPART) { - item_panel = LLPanelBodyPartsListItem::create(item); + item_panel = buildBodypartListItem(item); + if (!item_panel) continue; + mBodyParts->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false); - addWearableTypeSeparator(mBodyParts); } } @@ -143,17 +173,69 @@ void LLCOFWearables::populateAttachmentsAndBodypartsLists(const LLInventoryModel mBodyParts->sort(); //*TODO by name } - addListButtonBar(mBodyParts, "panel_bodyparts_list_button_bar.xml"); mBodyParts->notify(REARRANGE); } +//create a clothing list item, update verbs and show/hide line separator +LLPanelClothingListItem* LLCOFWearables::buildClothingListItem(LLViewerInventoryItem* item, bool first, bool last) +{ + llassert(item); + + LLPanelClothingListItem* item_panel = LLPanelClothingListItem::create(item); + if (!item_panel) return NULL; + + //updating verbs + //we don't need to use permissions of a link but of an actual/linked item + if (item->getLinkedItem()) item = item->getLinkedItem(); + + bool allow_modify = item->getPermissions().allowModifyBy(gAgentID); + + item_panel->setShowLockButton(!allow_modify); + item_panel->setShowEditButton(allow_modify); + + item_panel->setShowMoveUpButton(!first); + item_panel->setShowMoveDownButton(!last); + + //setting callbacks + //*TODO move that item panel's inner structure disclosing stuff into the panels + item_panel->childSetAction("btn_delete", mCOFCallbacks.mDeleteWearable); + item_panel->childSetAction("btn_move_up", mCOFCallbacks.mMoveWearableCloser); + item_panel->childSetAction("btn_move_down", mCOFCallbacks.mMoveWearableFurther); + item_panel->childSetAction("btn_edit", mCOFCallbacks.mEditWearable); + + //turning on gray separator line for the last item in the items group of the same wearable type + item_panel->childSetVisible("wearable_type_separator_panel", last); + + return item_panel; +} + +LLPanelBodyPartsListItem* LLCOFWearables::buildBodypartListItem(LLViewerInventoryItem* item) +{ + llassert(item); + + LLPanelBodyPartsListItem* item_panel = LLPanelBodyPartsListItem::create(item); + if (!item_panel) return NULL; + + //updating verbs + //we don't need to use permissions of a link but of an actual/linked item + if (item->getLinkedItem()) item = item->getLinkedItem(); + + bool allow_modify = item->getPermissions().allowModifyBy(gAgentID); + item_panel->setShowLockButton(!allow_modify); + item_panel->setShowEditButton(allow_modify); + + //setting callbacks + //*TODO move that item panel's inner structure disclosing stuff into the panels + item_panel->childSetAction("btn_delete", mCOFCallbacks.mDeleteWearable); + item_panel->childSetAction("btn_edit", mCOFCallbacks.mEditWearable); + + return item_panel; +} void LLCOFWearables::populateClothingList(LLAppearanceMgr::wearables_by_type_t& clothing_by_type) { llassert(clothing_by_type.size() == WT_COUNT); - addListButtonBar(mClothing, "panel_clothing_list_button_bar.xml"); - for (U32 type = WT_SHIRT; type < WT_COUNT; ++type) { U32 size = clothing_by_type[type].size(); @@ -165,13 +247,11 @@ void LLCOFWearables::populateClothingList(LLAppearanceMgr::wearables_by_type_t& { LLViewerInventoryItem* item = clothing_by_type[type][i]; - LLPanelInventoryListItemBase* item_panel = LLPanelClothingListItem::create(item); + LLPanelClothingListItem* item_panel = buildClothingListItem(item, i == 0, i == size - 1); if (!item_panel) continue; mClothing->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false); } - - addWearableTypeSeparator(mClothing); } addClothingTypesDummies(clothing_by_type); @@ -179,21 +259,6 @@ void LLCOFWearables::populateClothingList(LLAppearanceMgr::wearables_by_type_t& mClothing->notify(REARRANGE); } -void LLCOFWearables::addListButtonBar(LLFlatListView* list, std::string xml_filename) -{ - llassert(list); - llassert(xml_filename.length()); - - LLPanel::Params params; - LLPanel* button_bar = LLUICtrlFactory::create<LLPanel>(params); - LLUICtrlFactory::instance().buildPanel(button_bar, xml_filename); - - LLRect rc = button_bar->getRect(); - button_bar->reshape(list->getItemsRect().getWidth(), rc.getHeight()); - - list->addItem(button_bar, LLUUID::null, ADD_TOP, false); -} - //adding dummy items for missing wearable types void LLCOFWearables::addClothingTypesDummies(const LLAppearanceMgr::wearables_by_type_t& clothing_by_type) { @@ -208,26 +273,9 @@ void LLCOFWearables::addClothingTypesDummies(const LLAppearanceMgr::wearables_by LLPanelInventoryListItemBase* item_panel = LLPanelDummyClothingListItem::create(w_type); if(!item_panel) continue; mClothing->addItem(item_panel, LLUUID::null, ADD_BOTTOM, false); - addWearableTypeSeparator(mClothing); } } -void LLCOFWearables::addWearableTypeSeparator(LLFlatListView* list) -{ - llassert(list); - - static LLXMLNodePtr separator_xml_node = getXMLNode("panel_wearable_type_separator.xml"); - if (separator_xml_node->isNull()) return; - - LLPanel* separator = LLUICtrlFactory::defaultBuilder<LLPanel>(separator_xml_node, NULL, NULL); - - LLRect rc = separator->getRect(); - rc.setOriginAndSize(0, 0, list->getItemsRect().getWidth(), rc.getHeight()); - separator->setRect(rc); - - list->addItem(separator, LLUUID::null, ADD_BOTTOM, false); -} - LLUUID LLCOFWearables::getSelectedUUID() { if (!mLastSelectedList) return LLUUID::null; @@ -242,17 +290,4 @@ void LLCOFWearables::clear() mBodyParts->clear(); } -LLXMLNodePtr LLCOFWearables::getXMLNode(std::string xml_filename) -{ - LLXMLNodePtr xmlNode = NULL; - bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, xmlNode); - if (!success) - { - llwarning("Failed to read xml", 0); - return NULL; - } - - return xmlNode; -} - //EOF diff --git a/indra/newview/llcofwearables.h b/indra/newview/llcofwearables.h index fec6d34db2..2d26bf781f 100644 --- a/indra/newview/llcofwearables.h +++ b/indra/newview/llcofwearables.h @@ -36,12 +36,80 @@ #include "llpanel.h" #include "llinventorymodel.h" #include "llappearancemgr.h" +#include "llwearableitemslist.h" class LLFlatListView; +/** + * Adaptor between LLAccordionCtrlTab and LLFlatListView to facilitate communication between them + * (notify, notifyParent) regarding size changes of a list and selection changes across accordion tabs. + * Besides that it acts as a container for the LLFlatListView and a button bar on top of it. + */ +class LLCOFAccordionListAdaptor : public LLPanel +{ +public: + LLCOFAccordionListAdaptor() : LLPanel() {}; + ~LLCOFAccordionListAdaptor() {}; + + S32 notifyParent(const LLSD& info) + { + LLView* parent = getParent(); + if (!parent) return -1; + + if (!(info.has("action") && "size_changes" == info["action"].asString())) + { + return parent->notifyParent(info); + } + + LLRect rc; + childGetRect("button_bar", rc); + + LLSD params; + params["action"] = "size_changes"; + params["width"] = info["width"]; + params["height"] = info["height"].asInteger() + rc.getHeight(); + + return parent->notifyParent(params); + } + + + S32 notify(const LLSD& info) + { + for (child_list_const_iter_t iter = beginChild(); iter != endChild(); iter++) + { + if (dynamic_cast<LLFlatListView*>(*iter)) + { + return (*iter)->notify(info); + } + } + return LLPanel::notify(info); + }; +}; + + class LLCOFWearables : public LLPanel { public: + + /** + * Represents a collection of callbacks assigned to inventory panel item's buttons + */ + class LLCOFCallbacks + { + public: + LLCOFCallbacks() {}; + virtual ~LLCOFCallbacks() {}; + + typedef boost::function<void (void*)> cof_callback_t; + + cof_callback_t mMoveWearableCloser; + cof_callback_t mMoveWearableFurther; + cof_callback_t mEditWearable; + cof_callback_t mDeleteWearable; + }; + + + LLCOFWearables(); virtual ~LLCOFWearables() {}; @@ -52,17 +120,18 @@ public: void refresh(); void clear(); + LLCOFCallbacks& getCOFCallbacks() { return mCOFCallbacks; } + protected: void populateAttachmentsAndBodypartsLists(const LLInventoryModel::item_array_t& cof_items); void populateClothingList(LLAppearanceMgr::wearables_by_type_t& clothing_by_type); - void addListButtonBar(LLFlatListView* list, std::string xml_filename); void addClothingTypesDummies(const LLAppearanceMgr::wearables_by_type_t& clothing_by_type); - void addWearableTypeSeparator(LLFlatListView* list); void onSelectionChange(LLFlatListView* selected_list); - LLXMLNodePtr getXMLNode(std::string xml_filename); + LLPanelClothingListItem* buildClothingListItem(LLViewerInventoryItem* item, bool first, bool last); + LLPanelBodyPartsListItem* buildBodypartListItem(LLViewerInventoryItem* item); LLFlatListView* mAttachments; LLFlatListView* mClothing; @@ -70,6 +139,8 @@ protected: LLFlatListView* mLastSelectedList; + LLCOFCallbacks mCOFCallbacks; + }; diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 4c1e3461a5..6b7a257a4b 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1165,6 +1165,17 @@ void LLFavoritesBarCtrl::pastFromClipboard() const void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) { + // EXT-6997 (Fav bar: Pop-up menu for LM in overflow dropdown is kept after LM was dragged away) + // mInventoryItemsPopupMenuHandle.get() - is a pop-up menu (of items) in already opened dropdown menu. + // We have to check and set visibility of pop-up menu in such a way instead of using + // LLMenuHolderGL::hideMenus() because it will close both menus(dropdown and pop-up), but + // we need to close only pop-up menu while dropdown one should be still opened. + LLMenuGL* menu = (LLMenuGL*)mInventoryItemsPopupMenuHandle.get(); + if(menu && menu->getVisible()) + { + menu->setVisible(FALSE); + } + mDragItemId = id; mStartDrag = TRUE; diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp index 8dfdb0788a..9719de4650 100644 --- a/indra/newview/llinventoryitemslist.cpp +++ b/indra/newview/llinventoryitemslist.cpp @@ -45,6 +45,7 @@ #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "lltextutil.h" +#include "lltrans.h" //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -63,6 +64,16 @@ LLPanelInventoryListItemBase* LLPanelInventoryListItemBase::create(LLViewerInven return list_item; } +void LLPanelInventoryListItemBase::draw() +{ + if (getNeedsRefresh()) + { + updateItem(); + setNeedsRefresh(false); + } + LLPanel::draw(); +} + void LLPanelInventoryListItemBase::updateItem() { setIconImage(mIconImage); @@ -121,7 +132,7 @@ BOOL LLPanelInventoryListItemBase::postBuild() mIconImage = get_item_icon(mItem->getType(), mItem->getInventoryType(), mItem->getFlags(), FALSE); - updateItem(); + setNeedsRefresh(true); setWidgetsVisible(false); reshapeWidgets(); @@ -148,6 +159,34 @@ void LLPanelInventoryListItemBase::onMouseLeave(S32 x, S32 y, MASK mask) LLPanel::onMouseLeave(x, y, mask); } +S32 LLPanelInventoryListItemBase::notify(const LLSD& info) +{ + S32 rv = 0; + if(info.has("match_filter")) + { + mHighlightedText = info["match_filter"].asString(); + + std::string test(mItem->getName()); + LLStringUtil::toUpper(test); + + if(mHighlightedText.empty() || std::string::npos != test.find(mHighlightedText)) + { + rv = 0; // substring is found + } + else + { + rv = -1; + } + + setNeedsRefresh(true); + } + else + { + rv = LLPanel::notify(info); + } + return rv; +} + LLPanelInventoryListItemBase::LLPanelInventoryListItemBase(LLViewerInventoryItem* item) : LLPanel() , mItem(item) @@ -156,6 +195,7 @@ LLPanelInventoryListItemBase::LLPanelInventoryListItemBase(LLViewerInventoryItem , mWidgetSpacing(WIDGET_SPACING) , mLeftWidgetsWidth(0) , mRightWidgetsWidth(0) +, mNeedsRefresh(false) { } @@ -278,13 +318,15 @@ LLInventoryItemsList::Params::Params() {} LLInventoryItemsList::LLInventoryItemsList(const LLInventoryItemsList::Params& p) -: LLFlatListView(p) +: LLFlatListViewEx(p) , mNeedsRefresh(false) { // TODO: mCommitOnSelectionChange is set to "false" in LLFlatListView // but reset to true in all derived classes. This settings might need to // be added to LLFlatListView::Params() and/or set to "true" by default. setCommitOnSelectionChange(true); + + setNoFilteredItemsMsg(LLTrans::getString("InventoryNoMatchingItems")); } // virtual @@ -304,7 +346,7 @@ void LLInventoryItemsList::refreshList(const LLInventoryModel::item_array_t item void LLInventoryItemsList::draw() { - LLFlatListView::draw(); + LLFlatListViewEx::draw(); if(mNeedsRefresh) { refresh(); @@ -332,7 +374,8 @@ void LLInventoryItemsList::refresh() break; } LLViewerInventoryItem* item = gInventory.getItem(*it); - addNewItem(item); + // Do not rearrange items on each adding, let's do that on filter call + addNewItem(item, false); ++nadded; } @@ -342,6 +385,9 @@ void LLInventoryItemsList::refresh() removeItemByUUID(*it); } + // Filter, rearrange and notify parent about shape changes + filterItems(); + bool needs_refresh = add_limit_exceeded; setNeedsRefresh(needs_refresh); } @@ -363,7 +409,7 @@ void LLInventoryItemsList::computeDifference( LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved); } -void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item) +void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item, bool rearrange /*= true*/) { if (!item) { @@ -375,7 +421,7 @@ void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item) if (!list_item) return; - bool is_item_added = addItem(list_item, item->getUUID()); + bool is_item_added = addItem(list_item, item->getUUID(), ADD_BOTTOM, rearrange); if (!is_item_added) { llwarns << "Couldn't add flat list item." << llendl; diff --git a/indra/newview/llinventoryitemslist.h b/indra/newview/llinventoryitemslist.h index 152aafbd7e..bc04eb6f5b 100644 --- a/indra/newview/llinventoryitemslist.h +++ b/indra/newview/llinventoryitemslist.h @@ -64,13 +64,16 @@ class LLViewerInventoryItem; class LLPanelInventoryListItemBase : public LLPanel { public: - static LLPanelInventoryListItemBase* create(LLViewerInventoryItem* item); + virtual void draw(); + /** - * Called after inventory item was updated, update panel widgets to reflect inventory changes. + * Let item know it need to be refreshed in next draw() */ - virtual void updateItem(); + void setNeedsRefresh(bool needs_refresh){ mNeedsRefresh = needs_refresh; } + + bool getNeedsRefresh(){ return mNeedsRefresh; } /** * Add widget to left side @@ -107,6 +110,11 @@ public: */ /*virtual*/ void setValue(const LLSD& value); + /** + * Handles filter request + */ + /*virtual*/ S32 notify(const LLSD& info); + /* Highlights item */ /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask); /* Removes item highlight */ @@ -125,6 +133,11 @@ protected: */ virtual void init(); + /** + * Called after inventory item was updated, update panel widgets to reflect inventory changes. + */ + virtual void updateItem(); + /** setter for mIconCtrl */ void setIconCtrl(LLIconCtrl* icon) { mIconCtrl = icon; } /** setter for MTitleCtrl */ @@ -178,14 +191,15 @@ private: S32 mLeftWidgetsWidth; S32 mRightWidgetsWidth; + bool mNeedsRefresh; }; ////////////////////////////////////////////////////////////////////////// -class LLInventoryItemsList : public LLFlatListView +class LLInventoryItemsList : public LLFlatListViewEx { public: - struct Params : public LLInitParam::Block<Params, LLFlatListView::Params> + struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params> { Params(); }; @@ -225,7 +239,7 @@ protected: /** * Add an item to the list */ - virtual void addNewItem(LLViewerInventoryItem* item); + virtual void addNewItem(LLViewerInventoryItem* item, bool rearrange = true); private: uuid_vec_t mIDs; // IDs of items that were added in refreshList(). diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 86147d65e6..c24d2ee0ea 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -689,7 +689,10 @@ void LLInventoryCategoriesObserver::changed(U32 mask) // Unrecoverable, so just skip this category. llassert(cats != NULL && items != NULL); + + continue; } + const S32 current_num_known_descendents = cats->count() + items->count(); LLCategoryData cat_data = (*iter).second; @@ -708,11 +711,15 @@ void LLInventoryCategoriesObserver::changed(U32 mask) bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb) { - S32 version; - S32 current_num_known_descendents; + S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN; + S32 current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN; bool can_be_added = true; LLViewerInventoryCategory* category = gInventory.getCategory(cat_id); + // If category could not be retrieved it might mean that + // inventory is unusable at the moment so the category is + // stored with VERSION_UNKNOWN and DESCENDENT_COUNT_UNKNOWN, + // it may be updated later. if (category) { // Inventory category version is used to find out if some changes @@ -732,16 +739,10 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t llassert(cats != NULL && items != NULL); } - current_num_known_descendents = cats->count() + items->count(); - } - else - { - // If category could not be retrieved it might mean that - // inventory is unusable at the moment so the category is - // stored with VERSION_UNKNOWN and DESCENDENT_COUNT_UNKNOWN, - // it may be updated later. - version = LLViewerInventoryCategory::VERSION_UNKNOWN; - current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN; + else + { + current_num_known_descendents = cats->count() + items->count(); + } } if (can_be_added) diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index 95094f6b52..7cb192e026 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -145,6 +145,9 @@ std::string LLMute::getDisplayType() const case GROUP: return LLTrans::getString("MuteGroup"); break; + case EXTERNAL: + return LLTrans::getString("MuteExternal"); + break; } } @@ -303,6 +306,12 @@ BOOL LLMuteList::add(const LLMute& mute, U32 flags) void LLMuteList::updateAdd(const LLMute& mute) { + // External mutes (e.g. Avaline callers) are local only, don't send them to the server. + if (mute.mType == LLMute::EXTERNAL) + { + return; + } + // Update the database LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_UpdateMuteListEntry); @@ -390,6 +399,12 @@ BOOL LLMuteList::remove(const LLMute& mute, U32 flags) void LLMuteList::updateRemove(const LLMute& mute) { + // External mutes are not sent to the server anyway, no need to remove them. + if (mute.mType == LLMute::EXTERNAL) + { + return; + } + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_RemoveMuteListEntry); msg->nextBlockFast(_PREHASH_AgentData); @@ -573,9 +588,14 @@ BOOL LLMuteList::saveToFile(const std::string& filename) it != mMutes.end(); ++it) { - it->mID.toString(id_string); - const std::string& name = it->mName; - fprintf(fp, "%d %s %s|%u\n", (S32)it->mType, id_string.c_str(), name.c_str(), it->mFlags); + // Don't save external mutes as they are not sent to the server and probably won't + //be valid next time anyway. + if (it->mType != LLMute::EXTERNAL) + { + it->mID.toString(id_string); + const std::string& name = it->mName; + fprintf(fp, "%d %s %s|%u\n", (S32)it->mType, id_string.c_str(), name.c_str(), it->mFlags); + } } fclose(fp); return TRUE; diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h index 7cb11e6031..79b556bdbb 100644 --- a/indra/newview/llmutelist.h +++ b/indra/newview/llmutelist.h @@ -45,7 +45,8 @@ class LLMute { public: // Legacy mutes are BY_NAME and have null UUID. - enum EType { BY_NAME = 0, AGENT = 1, OBJECT = 2, GROUP = 3, COUNT = 4 }; + // EXTERNAL mutes are only processed through an external system (e.g. Voice) and not stored. + enum EType { BY_NAME = 0, AGENT = 1, OBJECT = 2, GROUP = 3, EXTERNAL = 4, COUNT = 5 }; // Bits in the mute flags. For backwards compatibility (since any mute list entries that were created before the flags existed // will have a flags field of 0), some of the flags are "inverted". diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index b103ec45d0..18bd610dd9 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -245,6 +245,34 @@ void LLOutfitsList::performAction(std::string action) void LLOutfitsList::setFilterSubString(const std::string& string) { mFilterSubString = string; + + for (outfits_map_t::iterator + iter = mOutfitsMap.begin(), + iter_end = mOutfitsMap.end(); + iter != iter_end; ++iter) + { + LLAccordionCtrlTab* tab = iter->second; + if (tab) + { + LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*> (tab->getAccordionView()); + if (list) + { + list->setFilterSubString(mFilterSubString); + } + + if(!mFilterSubString.empty()) + { + //store accordion tab state when filter is not empty + tab->notifyChildren(LLSD().with("action","store_state")); + tab->setDisplayChildren(true); + } + else + { + //restore accordion state after all those accodrion tab manipulations + tab->notifyChildren(LLSD().with("action","restore_state")); + } + } + } } ////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index dbccd243da..daa41e1467 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -128,8 +128,6 @@ LLPanelOutfitEdit::LLPanelOutfitEdit() mSearchFilter(NULL), mCOFWearables(NULL), mInventoryItemsPanel(NULL), - mAddToOutfitBtn(NULL), - mRemoveFromOutfitBtn(NULL), mLookObserver(NULL) { mSavedFolderState = new LLSaveFolderState(); @@ -174,13 +172,20 @@ BOOL LLPanelOutfitEdit::postBuild() mCurrentOutfitName = getChild<LLTextBox>("curr_outfit_name"); - childSetCommitCallback("add_btn", boost::bind(&LLPanelOutfitEdit::showAddWearablesPanel, this), NULL); childSetCommitCallback("filter_button", boost::bind(&LLPanelOutfitEdit::showWearablesFilter, this), NULL); childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showFilteredWearablesPanel, this), NULL); mCOFWearables = getChild<LLCOFWearables>("cof_wearables_list"); mCOFWearables->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onOutfitItemSelectionChange, this)); + mCOFWearables->getCOFCallbacks().mEditWearable = boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this); + mCOFWearables->getCOFCallbacks().mDeleteWearable = boost::bind(&LLPanelOutfitEdit::onRemoveFromOutfitClicked, this); + mCOFWearables->getCOFCallbacks().mMoveWearableCloser = boost::bind(&LLPanelOutfitEdit::moveWearable, this, true); + mCOFWearables->getCOFCallbacks().mMoveWearableFurther = boost::bind(&LLPanelOutfitEdit::moveWearable, this, false); + + mCOFWearables->childSetAction("add_btn", boost::bind(&LLPanelOutfitEdit::toggleAddWearablesPanel, this)); + + mInventoryItemsPanel = getChild<LLInventoryPanel>("inventory_items"); mInventoryItemsPanel->setFilterTypes(ALL_ITEMS_MASK); mInventoryItemsPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); @@ -209,13 +214,6 @@ BOOL LLPanelOutfitEdit::postBuild() mAddToLookBtn->setEnabled(FALSE); mAddToLookBtn->setVisible(FALSE); */ - childSetAction("add_to_outfit_btn", boost::bind(&LLPanelOutfitEdit::onAddToOutfitClicked, this)); - childSetEnabled("add_to_outfit_btn", false); - - mRemoveFromOutfitBtn = getChild<LLButton>("remove_from_outfit_btn"); - mRemoveFromOutfitBtn->setEnabled(FALSE); - mRemoveFromOutfitBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onRemoveFromOutfitClicked, this)); - mEditWearableBtn = getChild<LLButton>("edit_wearable_btn"); mEditWearableBtn->setEnabled(FALSE); mEditWearableBtn->setVisible(FALSE); @@ -233,9 +231,6 @@ BOOL LLPanelOutfitEdit::postBuild() mWearableListManager = new LLFilteredWearableListManager( getChild<LLInventoryItemsList>("filtered_wearables_list"), ALL_ITEMS_MASK); - - childSetAction("move_closer_btn", boost::bind(&LLPanelOutfitEdit::moveWearable, this, true)); - childSetAction("move_further_btn", boost::bind(&LLPanelOutfitEdit::moveWearable, this, false)); return TRUE; } @@ -252,9 +247,9 @@ void LLPanelOutfitEdit::moveWearable(bool closer_to_body) updateLookInfo(); } -void LLPanelOutfitEdit::showAddWearablesPanel() +void LLPanelOutfitEdit::toggleAddWearablesPanel() { - childSetVisible("add_wearables_panel", childGetValue("add_btn")); + childSetVisible("add_wearables_panel", !childIsVisible("add_wearables_panel")); } void LLPanelOutfitEdit::showWearablesFilter() @@ -379,8 +374,6 @@ void LLPanelOutfitEdit::onRemoveFromOutfitClicked(void) LLAppearanceMgr::getInstance()->removeItemFromAvatar(id_to_remove); updateLookInfo(); - - mRemoveFromOutfitBtn->setEnabled(FALSE); } @@ -434,10 +427,7 @@ void LLPanelOutfitEdit::onInventorySelectionChange(const std::deque<LLFolderView case LLAssetType::AT_CLOTHING: case LLAssetType::AT_BODYPART: case LLAssetType::AT_OBJECT: - childSetEnabled("add_to_outfit_btn", true); - break; default: - childSetEnabled("add_to_outfit_btn", false); break; } @@ -470,10 +460,7 @@ void LLPanelOutfitEdit::onOutfitItemSelectionChange(void) { case LLAssetType::AT_CLOTHING: case LLAssetType::AT_OBJECT: - mRemoveFromOutfitBtn->setEnabled(TRUE); - break; default: - mRemoveFromOutfitBtn->setEnabled(FALSE); break; } } diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index 21fa849289..0074cd517b 100644 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -90,7 +90,7 @@ public: void moveWearable(bool closer_to_body); - void showAddWearablesPanel(); + void toggleAddWearablesPanel(); void showWearablesFilter(); void showFilteredWearablesPanel(); void saveOutfit(bool as_new = false); @@ -122,8 +122,6 @@ private: LLFilterEditor* mSearchFilter; LLSaveFolderState* mSavedFolderState; std::string mSearchString; - LLButton* mAddToOutfitBtn; - LLButton* mRemoveFromOutfitBtn; LLButton* mEditWearableBtn; LLToggleableMenu* mSaveMenu; diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index 80964938f5..59c1fb4f3c 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -68,7 +68,6 @@ static const std::string OUTFITS_TAB_NAME = "outfitslist_tab"; static const std::string COF_TAB_NAME = "cof_tab"; static LLRegisterPanelClassWrapper<LLPanelOutfitsInventory> t_inventory("panel_outfits_inventory"); -bool LLPanelOutfitsInventory::sShowDebugEditor = false; LLPanelOutfitsInventory::LLPanelOutfitsInventory() : @@ -88,7 +87,6 @@ LLPanelOutfitsInventory::~LLPanelOutfitsInventory() // virtual BOOL LLPanelOutfitsInventory::postBuild() { - sShowDebugEditor = gSavedSettings.getBOOL("ShowDebugAppearanceEditor"); initTabPanels(); initListCommandsHandlers(); @@ -133,7 +131,6 @@ void LLPanelOutfitsInventory::updateVerbs() if (mListCommands) { - mListCommands->childSetVisible("edit_current_outfit_btn",sShowDebugEditor); updateListCommands(); } } @@ -307,14 +304,6 @@ void LLPanelOutfitsInventory::onSelectionChange(const std::deque<LLFolderViewIte } } -void LLPanelOutfitsInventory::showEditOutfitPanel() -{ - LLSD key; - key["type"] = "edit_outfit"; - - LLSideTray::getInstance()->showPanel("sidepanel_appearance", key); -} - LLFolderViewEventListener *LLPanelOutfitsInventory::getCorrectListenerForAction() { // TODO: add handling "My Outfits" tab. @@ -369,8 +358,6 @@ void LLPanelOutfitsInventory::initListCommandsHandlers() mListCommands->childSetAction("make_outfit_btn", boost::bind(&LLPanelOutfitsInventory::onAddButtonClick, this)); mListCommands->childSetAction("wear_btn", boost::bind(&LLPanelOutfitsInventory::onWearButtonClick, this)); - mListCommands->childSetAction("edit_current_outfit_btn", boost::bind(&LLPanelOutfitsInventory::showEditOutfitPanel, this)); - LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>("trash_btn"); trash_btn->setDragAndDropHandler(boost::bind(&LLPanelOutfitsInventory::handleDragAndDropToTrash, this , _4 // BOOL drop diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index 4234cc45c5..975d99f834 100644 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -65,7 +65,6 @@ public: bool onSaveCommit(const LLSD& notification, const LLSD& response); void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action); - void showEditOutfitPanel(); // If a compatible listener type is selected, then return a pointer to that. // Otherwise, return NULL. @@ -131,8 +130,6 @@ private: // List Commands // //////////////////////////////////////////////////////////////////////////////// /// -public: - static bool sShowDebugEditor; }; #endif //LL_LLPANELOUTFITSINVENTORY_H diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index c3748ca81d..a058548459 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -722,7 +722,21 @@ void LLParticipantList::LLParticipantListMenu::toggleMute(const LLSD& userdata, name = speakerp->mDisplayName; - LLMute mute(speaker_id, name, speakerp->mType == LLSpeaker::SPEAKER_AGENT ? LLMute::AGENT : LLMute::OBJECT); + LLMute::EType mute_type; + switch (speakerp->mType) + { + case LLSpeaker::SPEAKER_AGENT: + mute_type = LLMute::AGENT; + break; + case LLSpeaker::SPEAKER_OBJECT: + mute_type = LLMute::OBJECT; + break; + case LLSpeaker::SPEAKER_EXTERNAL: + default: + mute_type = LLMute::EXTERNAL; + break; + } + LLMute mute(speaker_id, name, mute_type); if (!is_muted) { diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index f38df19de0..08098e2adb 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -44,6 +44,7 @@ #include "llfoldervieweventlistener.h" #include "llpaneleditwearable.h" #include "llpaneloutfitsinventory.h" +#include "llsidetray.h" #include "lltextbox.h" #include "lluictrlfactory.h" #include "llviewerregion.h" @@ -115,6 +116,8 @@ BOOL LLSidepanelAppearance::postBuild() mEditAppearanceBtn = getChild<LLButton>("editappearance_btn"); mEditAppearanceBtn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onEditAppearanceButtonClicked, this)); + childSetAction("edit_outfit_btn", boost::bind(&LLSidepanelAppearance::onEditOutfitButtonClicked, this)); + mEditBtn = getChild<LLButton>("edit_btn"); mEditBtn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onEditButtonClicked, this)); @@ -154,7 +157,7 @@ BOOL LLSidepanelAppearance::postBuild() mCurrentLookName = getChild<LLTextBox>("currentlook_name"); - mOutfitDirtyTag = getChild<LLTextBox>("currentlook_title"); + mOutfitStatus = getChild<LLTextBox>("currentlook_status"); mCurrOutfitPanel = getChild<LLPanel>("panel_currentlook"); @@ -238,6 +241,13 @@ void LLSidepanelAppearance::onEditAppearanceButtonClicked() } } +void LLSidepanelAppearance::onEditOutfitButtonClicked() +{ + LLSD key; + key["type"] = "edit_outfit"; + LLSideTray::getInstance()->showPanel("sidepanel_appearance", key); +} + void LLSidepanelAppearance::onEditButtonClicked() { toggleOutfitEditPanel(FALSE); @@ -339,7 +349,11 @@ void LLSidepanelAppearance::updateVerbs() void LLSidepanelAppearance::refreshCurrentOutfitName(const std::string& name) { - mOutfitDirtyTag->setVisible(LLAppearanceMgr::getInstance()->isOutfitDirty()); + // Set current outfit status (wearing/unsaved). + bool dirty = LLAppearanceMgr::getInstance()->isOutfitDirty(); + std::string cof_status_str = getString(dirty ? "Unsaved Changes" : "Now Wearing"); + mOutfitStatus->setText(cof_status_str); + if (name == "") { std::string outfit_name; diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h index 0a609797fb..0a2d882a0b 100644 --- a/indra/newview/llsidepanelappearance.h +++ b/indra/newview/llsidepanelappearance.h @@ -71,6 +71,7 @@ private: void onOpenOutfitButtonClicked(); void onEditAppearanceButtonClicked(); + void onEditOutfitButtonClicked(); void onEditButtonClicked(); void onEditWearBackClicked(); @@ -90,7 +91,7 @@ private: LLPanel* mCurrOutfitPanel; LLTextBox* mCurrentLookName; - LLTextBox* mOutfitDirtyTag; + LLTextBox* mOutfitStatus; // Used to make sure the user's inventory is in memory. LLCurrentlyWornFetchObserver* mFetchWorn; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 33fb3d0f0f..a8004f26ed 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -487,12 +487,6 @@ bool toggle_show_favorites_panel(const LLSD& newvalue) return true; } -bool toggle_show_appearance_editor(const LLSD& newvalue) -{ - LLPanelOutfitsInventory::sShowDebugEditor = newvalue.asBoolean(); - return true; -} - bool toggle_show_object_render_cost(const LLSD& newvalue) { LLFloaterTools::sShowObjectCost = newvalue.asBoolean(); @@ -644,7 +638,6 @@ void settings_setup_listeners() gSavedSettings.getControl("ShowSnapshotButton")->getSignal()->connect(boost::bind(&toggle_show_snapshot_button, _2)); gSavedSettings.getControl("ShowNavbarNavigationPanel")->getSignal()->connect(boost::bind(&toggle_show_navigation_panel, _2)); gSavedSettings.getControl("ShowNavbarFavoritesPanel")->getSignal()->connect(boost::bind(&toggle_show_favorites_panel, _2)); - gSavedSettings.getControl("ShowDebugAppearanceEditor")->getSignal()->connect(boost::bind(&toggle_show_appearance_editor, _2)); gSavedSettings.getControl("ShowObjectRenderingCost")->getSignal()->connect(boost::bind(&toggle_show_object_render_cost, _2)); gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2)); } diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 298ce3fcec..542ec16547 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -5143,9 +5143,6 @@ LLVoiceClient::participantState *LLVoiceClient::sessionState::addParticipant(con { result->mAvatarIDValid = true; result->mAvatarID = id; - - if(result->updateMuteState()) - mMuteDirty = true; } else { @@ -5154,7 +5151,12 @@ LLVoiceClient::participantState *LLVoiceClient::sessionState::addParticipant(con setUUIDFromStringHash(result->mAvatarID, uri); } } - + + if(result->updateMuteState()) + { + mMuteDirty = true; + } + mParticipantsByUUID.insert(participantUUIDMap::value_type(&(result->mAvatarID), result)); if (LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID, result->mVolume)) @@ -5173,15 +5175,12 @@ bool LLVoiceClient::participantState::updateMuteState() { bool result = false; - if(mAvatarIDValid) + bool isMuted = LLMuteList::getInstance()->isMuted(mAvatarID, LLMute::flagVoiceChat); + if(mOnMuteList != isMuted) { - bool isMuted = LLMuteList::getInstance()->isMuted(mAvatarID, LLMute::flagVoiceChat); - if(mOnMuteList != isMuted) - { - mOnMuteList = isMuted; - mVolumeDirty = true; - result = true; - } + mOnMuteList = isMuted; + mVolumeDirty = true; + result = true; } return result; } diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 56b2791993..bd5d8d9357 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -136,31 +136,6 @@ BOOL LLPanelClothingListItem::postBuild() return TRUE; } -void LLPanelClothingListItem::setShowDeleteButton(bool show) -{ - setShowWidget("btn_delete", show); -} - -void LLPanelClothingListItem::setShowMoveUpButton(bool show) -{ - setShowWidget("btn_move_up", show); -} - -void LLPanelClothingListItem::setShowMoveDownButton(bool show) -{ - setShowWidget("btn_move_down", show); -} - -void LLPanelClothingListItem::setShowLockButton(bool show) -{ - setShowWidget("btn_lock", show); -} - -void LLPanelClothingListItem::setShowEditButton(bool show) -{ - setShowWidget("btn_edit", show); -} - ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// @@ -201,16 +176,6 @@ BOOL LLPanelBodyPartsListItem::postBuild() return TRUE; } -void LLPanelBodyPartsListItem::setShowLockButton(bool show) -{ - setShowWidget("btn_lock", show); -} - -void LLPanelBodyPartsListItem::setShowEditButton(bool show) -{ - setShowWidget("btn_edit", show); -} - ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index c4a415dfbf..29532a15c1 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -86,11 +86,13 @@ public: /** * Make button visible during mouse over event. */ - inline void setShowDeleteButton(bool show); - inline void setShowMoveUpButton(bool show); - inline void setShowMoveDownButton(bool show); - inline void setShowLockButton(bool show); - inline void setShowEditButton(bool show); + inline void setShowDeleteButton(bool show) { setShowWidget("btn_delete", show); } + inline void setShowMoveUpButton(bool show) { setShowWidget("btn_move_up", show); } + + inline void setShowMoveDownButton(bool show) { setShowWidget("btn_move_down", show); } + inline void setShowLockButton(bool show) { setShowWidget("btn_lock", show); } + inline void setShowEditButton(bool show) { setShowWidget("btn_edit", show); } + protected: @@ -113,8 +115,8 @@ public: /** * Make button visible during mouse over event. */ - inline void setShowLockButton(bool show); - inline void setShowEditButton(bool show); + inline void setShowLockButton(bool show) { setShowWidget("btn_lock", show); } + inline void setShowEditButton(bool show) { setShowWidget("btn_edit", show); } protected: LLPanelBodyPartsListItem(LLViewerInventoryItem* item); diff --git a/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml index 28a6995186..e70abc0975 100644 --- a/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml +++ b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml @@ -37,7 +37,7 @@ layout="topleft" name="speakers_list" opaque="false" - show_info_btn="false" + show_info_btn="true" show_profile_btn="false" show_speaking_indicator="false" width="147" /> diff --git a/indra/newview/skins/default/xui/en/panel_body_parts_list_item.xml b/indra/newview/skins/default/xui/en/panel_body_parts_list_item.xml index 4313d450fb..115964e5f2 100644 --- a/indra/newview/skins/default/xui/en/panel_body_parts_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_body_parts_list_item.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel follows="top|right|left" - height="20" + height="22" layout="topleft" left="0" name="wearable_item" @@ -69,4 +69,14 @@ height="20" width="20" tab_stop="false" /> + <panel + background_visible="true" + bg_alpha_color="0.4 0.4 0.4 1.0" + bottom="0" + follows="left|right|top" + height="1" + layout="bottomleft" + left="0" + name="wearable_type_separator_panel" + width="380"/> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_clothing_list_item.xml b/indra/newview/skins/default/xui/en/panel_clothing_list_item.xml index 8dc67de06f..7cc9c46c08 100644 --- a/indra/newview/skins/default/xui/en/panel_clothing_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_clothing_list_item.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel follows="top|right|left" - height="20" + height="23" layout="topleft" left="0" name="wearable_item" @@ -101,4 +101,15 @@ height="20" width="20" tab_stop="false" /> + <panel + background_visible="true" + bg_alpha_color="0.4 0.4 0.4 1.0" + bottom="0" + follows="left|right|top" + height="1" + layout="bottomleft" + left="0" + name="wearable_type_separator_panel" + visible="false" + width="380"/> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml index d8a8dbbea4..86b9ea6e14 100644 --- a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml +++ b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml @@ -3,23 +3,22 @@ background_visible="true" bg_alpha_color="DkGray" border="false" - bottom="0" follows="all" height="200" left="0" name="cof_wearables" - width="313"> + width="311"> <accordion follows="all" - height="373" + height="200" layout="topleft" - left="3" + left="0" single_expansion="true" top="0" name="cof_wearables_accordion" background_visible="true" bg_alpha_color="DkGray2" - width="307"> + width="311"> <accordion_tab layout="topleft" name="tab_attachments" @@ -27,40 +26,82 @@ <flat_list_view allow_select="true" follows="all" - height="150" + height="10" layout="topleft" left="0" name="list_attachments" top="0" - width="307" /> + width="311" /> </accordion_tab> <accordion_tab layout="topleft" name="tab_clothing" title="Clothing"> - <flat_list_view - allow_select="true" + + <!-- *NOTE there should be no any gaps between the button bar and the list - + accordiong-list adaptor won't employ them while calculating new height when the size of the list changes --> + <panel + background_visible="false" + class="accordion_list_adaptor" follows="all" - height="150" + height="45" layout="topleft" left="0" - name="list_clothing" + name="button_bar_adaptor" top="0" - width="307" /> + width="311"> + <panel + bevel="none" + filename="panel_clothing_list_button_bar.xml" + height="35" + name="button_bar" + top="0" + width="311" /> + <flat_list_view + allow_select="true" + follows="all" + height="10" + layout="topleft" + left="0" + name="list_clothing" + top_pad="0" + width="311" /> + </panel> </accordion_tab> <accordion_tab layout="topleft" name="tab_body_parts" title="Body Parts"> - <flat_list_view - allow_select="true" + + <!-- *NOTE there should be no any gaps between the button bar and the list - + accordiong-list adaptor won't employ them while calculating new height when the size of the list changes --> + <panel + background_visible="false" + class="accordion_list_adaptor" follows="all" - height="150" + height="45" layout="topleft" left="0" - name="list_body_parts" + name="button_bar_adaptor" top="0" - width="307" /> + width="311"> + <panel + bevel="none" + filename="panel_bodyparts_list_button_bar.xml" + height="35" + name="button_bar" + top="0" + width="311"/> + <flat_list_view + allow_select="true" + follows="all" + height="10" + layout="topleft" + left="0" + name="list_body_parts" + top_pad="0" + width="311" /> + </panel> </accordion_tab> </accordion> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_dummy_clothing_list_item.xml b/indra/newview/skins/default/xui/en/panel_dummy_clothing_list_item.xml index dbbfa8f2e2..c5a60ced88 100644 --- a/indra/newview/skins/default/xui/en/panel_dummy_clothing_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_dummy_clothing_list_item.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel follows="top|right|left" - height="20" + height="22" layout="topleft" left="0" name="dummy_clothing_item" @@ -59,4 +59,14 @@ height="20" width="20" tab_stop="false" /> + <panel + background_visible="true" + bg_alpha_color="0.4 0.4 0.4 1.0" + bottom="0" + follows="left|right|top" + height="1" + layout="bottomleft" + left="0" + name="wearable_type_separator_panel" + width="380"/> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_group_control_panel.xml b/indra/newview/skins/default/xui/en/panel_group_control_panel.xml index aa7d621e4c..c1dc2aaaf7 100644 --- a/indra/newview/skins/default/xui/en/panel_group_control_panel.xml +++ b/indra/newview/skins/default/xui/en/panel_group_control_panel.xml @@ -36,7 +36,7 @@ layout="topleft" name="speakers_list" opaque="false" - show_info_btn="false" + show_info_btn="true" show_profile_btn="false" show_speaking_indicator="false" width="145" /> diff --git a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml index a9f588698a..6a212306d6 100644 --- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml +++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml @@ -69,19 +69,21 @@ <!-- "HEADER WITH ICON, STATUS TEXT AND OUTFIT NAME" --> <panel + background_visible="true" + bg_alpha_color="DkGray2" bevel_style="none" follows="top|left|right" - height="45" + height="40" label="bottom_panel" layout="topleft" - left="5" + left="6" name="header_panel" top_pad="5" - width="300"> + width="311"> <icon follows="left|top" height="40" - image_name="t-shirt-image" + image_name="TabIcon_Appearance_Off" left="2" mouse_opaque="false" name="outfit_icon" @@ -92,35 +94,35 @@ <panel bevel_style="none" follows="top|right" - height="40" + height="38" label="bottom_panel" layout="topleft" - left_pad="10" + left_pad="5" name="outfit_name_and_status" top="2" - width="200"> + width="270"> <text follows="top|left|right" - font="SansSerif" + font="SansSerifSmallBold" height="13" layout="topleft" name="status" - text_color="Green" - top="0" - value="Editing..." + text_color="EmphasisColor" + top="2" + value="Now editing..." use_ellipses="true" - width="275" /> + width="270" /> <text follows="bottom|left|right" - font="SansSerifHugeBold" + font="SansSerifLargeBold" height="26" layout="topleft" name="curr_outfit_name" text_color="LtGray" - top_pad="0" + top_pad="2" value="[Current Outfit]" use_ellipses="true" - width="275" /> + width="270" /> </panel> </panel> @@ -130,22 +132,21 @@ animate="false" default_tab_group="2" follows="all" - height="470" - width="300" + height="495" + width="313" layout="topleft" orientation="vertical" name="im_panels" tab_group="1" - top_pad="10" + top_pad="5" left="5"> <layout_panel layout="topleft" - follows="left|top|right" height="220" label="IM Control Panel" min_height="100" name="outfit_wearables_panel" - width="300" + width="313" auto_resize="true" user_resize="true"> @@ -157,11 +158,12 @@ follows="left|top|right|bottom" height="193" layout="topleft" - left="0" + left="1" name="cof_wearables_list" top="0" - width="300" /> + width="311" /> + <!-- Button bar --> <panel background_visible="true" bevel_style="none" @@ -171,8 +173,8 @@ layout="topleft" left="0" name="edit_panel" - top_pad="0" - width="300"> + top="193" + width="313"> <button follows="bottom|left" height="25" @@ -185,75 +187,14 @@ name="gear_menu_btn" top="1" width="31" /> - <button - is_toggle="true" - follows="bottom|left" - height="25" - image_hover_unselected="Toolbar_Middle_Over" - image_overlay="AddItem_Off" - image_selected="Toolbar_Middle_Selected" - image_unselected="Toolbar_Middle_Off" - layout="topleft" - left_pad="1" - name="add_btn" - top="1" - width="31" /> - <button - follows="bottom|left" - height="25" - image_hover_unselected="Toolbar_Middle_Over" - image_overlay="" - image_selected="Toolbar_Middle_Selected" - image_unselected="Toolbar_Middle_Off" - layout="topleft" - left_pad="1" - name="new_btn" - top="1" - width="31" /> - <button - follows="bottom|left" - height="25" - image_hover_unselected="Toolbar_Middle_Over" - image_overlay="Movement_Forward_On" - image_selected="Toolbar_Middle_Selected" - image_unselected="Toolbar_Middle_Off" - layout="topleft" - left_pad="1" - name="move_closer_btn" - top="1" - width="31" /> - <button - follows="bottom|left" - height="25" - image_hover_unselected="Toolbar_Middle_Over" - image_overlay="Movement_Backward_On" - image_selected="Toolbar_Middle_Selected" - image_unselected="Toolbar_Middle_Off" - layout="topleft" - left_pad="1" - name="move_further_btn" - top="1" - width="31" /> <icon - follows="bottom|left" + follows="bottom|left|right" height="25" - image_name="Toolbar_Middle_Off" + image_name="Toolbar_Right_Off" layout="topleft" left_pad="1" - name="dummy_icon" - width="105" /> - <button - follows="bottom|right" - height="25" - image_hover_unselected="Toolbar_Middle_Over" - image_overlay="TrashItem_Off" - image_selected="Toolbar_Middle_Selected" - image_unselected="Toolbar_Middle_Off" - layout="topleft" - name="remove_from_outfit_btn" - right="-1" - top="1" - width="31" /> + name="dummy_right_icon" + width="281" /> </panel> </layout_panel> @@ -264,7 +205,7 @@ height="210" min_height="210" name="add_wearables_panel" - width="300" + width="313" tab_group="2" user_resize="true" visible="false"> @@ -448,22 +389,6 @@ name="add_to_outfit_btn" top="1" width="31" /> - <icon - follows="bottom|left" - height="25" - image_name="Toolbar_Middle_Off" - layout="topleft" - left_pad="1" - name="dummy_middle_icon" - width="140" /> - <icon - follows="bottom|left" - height="25" - image_name="Toolbar_Right_Off" - layout="topleft" - left_pad="1" - name="dummy_right_icon" - width="31" /> </panel> </layout_panel> </layout_stack> @@ -472,25 +397,28 @@ follows="left|right|bottom" height="30" layout="topleft" - left="5" - top_pad="10" + left="4" + top_pad="2" name="save_revert_button_bar" width="300"> <button - follows="bottom|left|right" + follows="bottom|left" height="23" label="Save" left="0" layout="topleft" name="save_btn" - width="145" /> + top="0" + width="155" /> <button - follows="bottom|right" + follows="bottom|left" height="23" name="save_flyout_btn" label="" + layout="topleft" left_pad="-20" tab_stop="false" + top="0" image_selected="SegmentedBtn_Right_Selected_Press" image_unselected="SegmentedBtn_Right_Off" image_pressed="SegmentedBtn_Right_Press" @@ -500,10 +428,11 @@ <button follows="bottom|left|right" height="23" - left_pad="15" + left_pad="12" label="Revert" layout="topleft" name="revert_btn" - width="145" /> + top="0" + width="147" /> </panel> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml index b8ad278da7..9e59651bd1 100644 --- a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml @@ -5,7 +5,7 @@ background_opaque="true" background_visible="true" follows="all" - height="570" + height="575" label="Things" layout="topleft" min_height="350" @@ -14,7 +14,7 @@ border="false"> <tab_container follows="all" - height="501" + height="509" layout="topleft" left="7" name="appearance_tabs" @@ -22,6 +22,7 @@ tab_height="30" tab_position="top" halign="center" + top="8" width="312"> <panel class="outfits_list" @@ -50,8 +51,8 @@ </tab_container> <panel background_visible="true" - follows="bottom|left" - height="73" + follows="bottom|left|right" + height="57" layout="topleft" left="9" top_pad="-1" @@ -72,7 +73,7 @@ top="1" width="31" /> <icon - follows="bottom|left" + follows="bottom|left|right" height="25" image_name="Toolbar_Middle_Off" layout="topleft" @@ -82,7 +83,7 @@ /> <dnd_button - follows="bottom|left" + follows="bottom|right" height="25" image_hover_unselected="Toolbar_Right_Over" image_overlay="TrashItem_Off" @@ -104,7 +105,7 @@ left="0" width="153" /> <button - follows="bottom|right" + follows="bottom|left|right" height="23" label="Wear" layout="topleft" @@ -112,16 +113,6 @@ left_pad="3" tool_tip="Wear selected outfit" width="152" /> - <button - follows="bottom|left" - height="23" - label="Edit Outfit" - layout="topleft" - right="-140" - name="edit_current_outfit_btn" - top="26" - visible="false" - width="50" /> </panel> </panel>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml index 73650a19dc..e74c70789f 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml @@ -15,63 +15,85 @@ width="333"> <string name="No Outfit" value="No Outfit" /> + <string + name="Unsaved Changes" + value="Unsaved changes" /> + <string + name="Now Wearing" + value="Now wearing..." /> <panel - left="0" - top="0" - follows="all" + background_opaque="true" + background_visible="true" + bg_opaque_color="DkGray2" + left="10" + top="5" + follows="left|top|right" layout="topleft" - width="330" + width="303" height="33" name="panel_currentlook" > <button follows="left|top" - top="0" width="1" height="1" + left="205" top="7" width="20" height="20" + label="E" layout="topleft" - left="0" - name="editappearance_btn" /> + name="editappearance_btn" + visible="false" /> <button follows="left|top" - top="0" width="1" height="1" + left="235" top="7" width="20" height="20" + label="O" layout="topleft" - left="0" - name="openoutfit_btn" /> + name="openoutfit_btn" + visible="false" /> <icon follows="top|left" - height="24" + height="32" image_name="TabIcon_Appearance_Off" name="outfit_icon" mouse_opaque="false" visible="true" - left="9" + left="0" top="0" - width="24" /> + width="32" /> <text - font="SansSerifHugeBold" + font="SansSerifSmallBold" + text_color="EmphasisColor" + width="300" + height="10" + follows="top|left" + layout="topleft" + left="35" + top="3" + mouse_opaque="false" + name="currentlook_status" > + (Status) + </text> + <text + font="SansSerifLargeBold" height="20" - left_pad="5" - text_color="LtGray" - top="0" + left="35" + text_color="White" + top="15" use_ellipses="true" - width="305" + width="230" follows="top|left" - word_wrap="true" + word_wrap="false" mouse_opaque="false" name="currentlook_name"> MyOutfit With a really Long Name like MOOSE </text> - <text - font="SansSerifSmall" - text_color="White_50" - width="300" - height="1" - follows="top|left" + <button + follows="left|top" + height="20" + image_overlay="windows/Icon_Gear_Over.png" + label="" layout="topleft" - top_pad="5" - mouse_opaque="false" - name="currentlook_title" > - (unsaved) - </text> + left="265" + name="edit_outfit_btn" + top="7" + width="30" /> </panel> <filter_editor height="23" @@ -87,7 +109,7 @@ width="333"> class="panel_outfits_inventory" filename="panel_outfits_inventory.xml" name="panel_outfits_inventory" - height="505" + height="493" min_height="410" width="320" left="0" @@ -106,7 +128,7 @@ width="333"> <panel class="panel_outfit_edit" filename="panel_outfit_edit.xml" - height="550" + height="565" follows="all" layout="topleft" left="5" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 73df41b776..996b04760a 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -2164,10 +2164,11 @@ Clears (deletes) the media and all params from the given face. <string name="BusyModeResponseDefault">The Resident you messaged is in 'busy mode' which means they have requested not to be disturbed. Your message will still be shown in their IM panel for later viewing.</string> <!-- Mute --> - <string name="MuteByName">(by name)</string> + <string name="MuteByName">(By name)</string> <string name="MuteAgent">(Resident)</string> - <string name="MuteObject">(object)</string> - <string name="MuteGroup">(group)</string> + <string name="MuteObject">(Object)</string> + <string name="MuteGroup">(Group)</string> + <string name="MuteExternal">(External)</string> <!-- Region/Estate Covenant --> <string name="RegionNoCovenant">There is no Covenant provided for this Estate.</string> |