diff options
Diffstat (limited to 'indra')
69 files changed, 1975 insertions, 307 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 4481d334b2..3c689930b8 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -35,6 +35,7 @@ set(llcommon_SOURCE_FILES llbase32.cpp llbase64.cpp llcommon.cpp + llcommonutils.cpp llcoros.cpp llcrc.cpp llcriticaldamp.cpp @@ -124,6 +125,7 @@ set(llcommon_HEADER_FILES llchat.h llclickaction.h llcommon.h + llcommonutils.h llcoros.h llcrc.h llcriticaldamp.h diff --git a/indra/llcommon/llcommonutils.cpp b/indra/llcommon/llcommonutils.cpp new file mode 100644 index 0000000000..0022dc6915 --- /dev/null +++ b/indra/llcommon/llcommonutils.cpp @@ -0,0 +1,61 @@ +/** + * @file llcommonutils.h + * @brief Commin utils + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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 "llcommonutils.h" + +void LLCommonUtils::computeDifference( + const uuid_vec_t& vnew, + const uuid_vec_t& vcur, + uuid_vec_t& vadded, + uuid_vec_t& vremoved) +{ + uuid_vec_t vnew_copy(vnew); + uuid_vec_t vcur_copy(vcur); + + std::sort(vnew_copy.begin(), vnew_copy.end()); + std::sort(vcur_copy.begin(), vcur_copy.end()); + + size_t maxsize = llmax(vnew_copy.size(), vcur_copy.size()); + vadded.resize(maxsize); + vremoved.resize(maxsize); + + uuid_vec_t::iterator it; + // what was removed + it = set_difference(vcur_copy.begin(), vcur_copy.end(), vnew_copy.begin(), vnew_copy.end(), vremoved.begin()); + vremoved.erase(it, vremoved.end()); + + // what was added + it = set_difference(vnew_copy.begin(), vnew_copy.end(), vcur_copy.begin(), vcur_copy.end(), vadded.begin()); + vadded.erase(it, vadded.end()); +} + +// EOF diff --git a/indra/llcommon/llcommonutils.h b/indra/llcommon/llcommonutils.h new file mode 100644 index 0000000000..f769ab87d3 --- /dev/null +++ b/indra/llcommon/llcommonutils.h @@ -0,0 +1,51 @@ +/** + * @file llcommonutils.h + * @brief Common utils + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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_LLCOMMONUTILS_H +#define LL_LLCOMMONUTILS_H + +namespace LLCommonUtils +{ + /** + * Computes difference between 'vnew' and 'vcur' vectors. + * Items present in 'vnew' and missing in 'vcur' are treated as added and are copied into 'vadded' + * Items missing in 'vnew' and present in 'vcur' are treated as removed and are copied into 'vremoved' + */ + LL_COMMON_API void computeDifference( + const uuid_vec_t& vnew, + const uuid_vec_t& vcur, + uuid_vec_t& vadded, + uuid_vec_t& vremoved); +}; + +#endif //LL_LLCOMMONUTILS_H + +// EOF diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index cdcf780d2e..136fd2a9ac 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -332,11 +332,31 @@ void LLAccordionCtrl::addCollapsibleCtrl(LLView* view) 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::removeCollapsibleCtrl(LLView* view) +{ + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view); + if(!accordion_tab) + return; + + if(std::find(getChildList()->begin(),getChildList()->end(),accordion_tab) != getChildList()->end()) + removeChild(accordion_tab); + + for (std::vector<LLAccordionCtrlTab*>::iterator iter = mAccordionTabs.begin(); + iter != mAccordionTabs.end(); ++iter) + { + if (accordion_tab == (*iter)) + { + mAccordionTabs.erase(iter); + break; + } + } +} + void LLAccordionCtrl::arrangeSinge() { S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h index 7c29e545b7..ab7d6548ca 100644 --- a/indra/llui/llaccordionctrl.h +++ b/indra/llui/llaccordionctrl.h @@ -92,6 +92,7 @@ public: virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); void addCollapsibleCtrl(LLView* view); + void removeCollapsibleCtrl(LLView* view); void arrange(); diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index dfb427f293..d389236642 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -425,6 +425,9 @@ bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group) setDisplayChildren(getDisplayChildren()); } + if (!mContainerPanel) + mContainerPanel = findContainerView(); + return res; } diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 33c6a8b6ac..0255061b12 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -1003,6 +1003,11 @@ void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image) mFadeWhenDisabled = TRUE; } +void LLButton::setImagePressed(LLPointer<LLUIImage> image) +{ + mImagePressed = image; +} + void LLButton::setImageHoverSelected(LLPointer<LLUIImage> image) { mImageHoverSelected = image; diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 6a1e3a9425..a4d81ed6c3 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -246,6 +246,7 @@ public: void setImageHoverUnselected(LLPointer<LLUIImage> image); void setImageDisabled(LLPointer<LLUIImage> image); void setImageDisabledSelected(LLPointer<LLUIImage> image); + void setImagePressed(LLPointer<LLUIImage> image); void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; } BOOL getCommitOnReturn() const { return mCommitOnReturn; } diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h index 66368f979b..7e37600409 100644 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -73,6 +73,7 @@ public: std::string getImageName() const; void setColor(const LLColor4& color) { mColor = color; } + void setImage(LLPointer<LLUIImage> image) { mImagep = image; } private: void setIconImageDrawSize() ; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index e08026eaf4..390ec234d3 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1507,6 +1507,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url)); registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url)); registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url)); + registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url)); registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url)); registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url)); registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url)); diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index 679db5e39b..2f13a56b42 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -146,3 +146,20 @@ void LLUrlAction::copyLabelToClipboard(std::string url) LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(match.getLabel())); } } + +void LLUrlAction::showProfile(std::string url) +{ + // Get id from 'secondlife:///app/{cmd}/{id}/{action}' + // and show its profile + LLURI uri(url); + LLSD path_array = uri.pathArray(); + if (path_array.size() == 4) + { + std::string id_str = path_array.get(2).asString(); + if (LLUUID::validate(id_str)) + { + std::string cmd_str = path_array.get(1).asString(); + executeSLURL("secondlife:///app/" + cmd_str + "/" + id_str + "/about"); + } + } +} diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index 4830cf27ef..b96faf1b3f 100644 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -79,6 +79,9 @@ public: /// copy a Url to the clipboard static void copyURLToClipboard(std::string url); + /// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile + static void showProfile(std::string url); + /// specify the callbacks to enable this class's functionality static void setOpenURLCallback(void (*cb) (const std::string& url)); static void setOpenURLInternalCallback(void (*cb) (const std::string& url)); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index efb16d1e42..bfb5798909 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -142,6 +142,7 @@ set(viewer_SOURCE_FILES llfavoritesbar.cpp llfeaturemanager.cpp llfilepicker.cpp + llfilteredwearablelist.cpp llfirstuse.cpp llflexibleobject.cpp llfloaterabout.cpp @@ -252,6 +253,7 @@ set(viewer_SOURCE_FILES llinventoryclipboard.cpp llinventoryfilter.cpp llinventoryfunctions.cpp + llinventoryitemslist.cpp llinventorymodel.cpp llinventorymodelbackgroundfetch.cpp llinventoryobserver.cpp @@ -295,6 +297,7 @@ set(viewer_SOURCE_FILES llnotificationofferhandler.cpp llnotificationscripthandler.cpp llnotificationtiphandler.cpp + lloutfitslist.cpp lloutputmonitorctrl.cpp llpanelavatar.cpp llpanelavatartag.cpp @@ -327,6 +330,7 @@ set(viewer_SOURCE_FILES llpanelnearbymedia.cpp llpanelobject.cpp llpanelobjectinventory.cpp + llpanelonlinestatus.cpp llpaneloutfitedit.cpp llpaneloutfitsinventory.cpp llpanelpeople.cpp @@ -528,6 +532,7 @@ set(viewer_SOURCE_FILES llwaterparamset.cpp llwearable.cpp llwearabledictionary.cpp + llwearableitemslist.cpp llwearablelist.cpp llweb.cpp llwind.cpp @@ -647,6 +652,7 @@ set(viewer_HEADER_FILES llfavoritesbar.h llfeaturemanager.h llfilepicker.h + llfilteredwearablelist.h llfirstuse.h llflexibleobject.h llfloaterabout.h @@ -756,6 +762,7 @@ set(viewer_HEADER_FILES llinventoryclipboard.h llinventoryfilter.h llinventoryfunctions.h + llinventoryitemslist.h llinventorymodel.h llinventorymodelbackgroundfetch.h llinventoryobserver.h @@ -795,6 +802,7 @@ set(viewer_HEADER_FILES llnetmap.h llnotificationhandler.h llnotificationmanager.h + lloutfitslist.h lloutputmonitorctrl.h llpanelavatar.h llpanelavatartag.h @@ -827,6 +835,7 @@ set(viewer_HEADER_FILES llpanelnearbymedia.h llpanelobject.h llpanelobjectinventory.h + llpanelonlinestatus.h llpaneloutfitedit.h llpaneloutfitsinventory.h llpanelpeople.h @@ -1030,6 +1039,7 @@ set(viewer_HEADER_FILES llwaterparamset.h llwearable.h llwearabledictionary.h + llwearableitemslist.h llwearablelist.h llweb.h llwind.h diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 7f248eee30..466f2d499d 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -1338,7 +1338,8 @@ public: LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key); LLPanelOutfitsInventory *outfit_panel = dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory")); - if (outfit_panel) + // TODO: add handling "My Outfits" tab. + if (outfit_panel && outfit_panel->isCOFPanelActive()) { outfit_panel->getRootFolder()->clearSelection(); outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE); @@ -1361,24 +1362,6 @@ private: LLUUID mFolderID; }; -LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name) -{ - if (!isAgentAvatarValid()) return LLUUID::null; - - // 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, - new_folder_name); - - LLPointer<LLInventoryCallback> cb = new LLShowCreatedOutfit(folder_id); - LLAppearanceMgr::instance().shallowCopyCategoryContents(LLAppearanceMgr::instance().getCOF(),folder_id, cb); - LLAppearanceMgr::instance().createBaseOutfitLink(folder_id, cb); - - return folder_id; -} - void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) { LLUUID first_item_id = getWearableItemID((EWearableType)type, index); diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index b76367324c..585fd3f8b3 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -169,8 +169,7 @@ public: const LLDynamicArray<S32>& wearables_to_include, const LLDynamicArray<S32>& attachments_to_include, BOOL rename_clothing); - - LLUUID makeNewOutfitLinks(const std::string& new_folder_name); + // Should only be called if we *know* we've never done so before, since users may // not want the Library outfits to stay in their quick outfit selector and can delete them. diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp index 08d8ccfd23..03d09a3798 100644 --- a/indra/newview/llagentwearablesfetch.cpp +++ b/indra/newview/llagentwearablesfetch.cpp @@ -119,6 +119,7 @@ public: item->getLinkedUUID(), LLAppearanceMgr::instance().getCOF(), item->getName(), + item->getDescription(), LLAssetType::AT_LINK, link_waiter); } @@ -507,6 +508,7 @@ void LLLibraryOutfitsFetch::contentsDone() item->getLinkedUUID(), new_outfit_folder_id, item->getName(), + item->getDescription(), LLAssetType::AT_LINK, NULL); } diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 4d18ff57fe..9e02886e4f 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -32,6 +32,7 @@ #include "llviewerprecompiledheaders.h" +#include "llaccordionctrltab.h" #include "llagent.h" #include "llagentwearables.h" #include "llappearancemgr.h" @@ -42,6 +43,7 @@ #include "llinventoryfunctions.h" #include "llinventoryobserver.h" #include "llnotificationsutil.h" +#include "llpaneloutfitsinventory.h" #include "llselectmgr.h" #include "llsidepanelappearance.h" #include "llsidetray.h" @@ -51,6 +53,8 @@ #include "llviewerregion.h" #include "llwearablelist.h" +char ORDER_NUMBER_SEPARATOR('@'); + LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name) { LLInventoryModel::cat_array_t cat_array; @@ -400,6 +404,7 @@ public: item_id, LLAppearanceMgr::instance().getCOF(), itemp->getName(), + itemp->getDescription(), LLAssetType::AT_LINK, cb); } @@ -691,10 +696,13 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL { case LLAssetType::AT_LINK: { + //LLInventoryItem::getDescription() is used for a new description + //to propagate ordering information saved in descriptions of links link_inventory_item(gAgent.getID(), item->getLinkedUUID(), dst_id, item->getName(), + item->LLInventoryItem::getDescription(), LLAssetType::AT_LINK, cb); break; } @@ -708,6 +716,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL item->getLinkedUUID(), dst_id, item->getName(), + item->getDescription(), LLAssetType::AT_LINK_FOLDER, cb); } break; @@ -811,20 +820,7 @@ void LLAppearanceMgr::filterWearableItems( { // Divvy items into arrays by wearable type. std::vector<LLInventoryModel::item_array_t> items_by_type(WT_COUNT); - for (S32 i=0; i<items.count(); i++) - { - LLViewerInventoryItem *item = items.get(i); - // Ignore non-wearables. - if (!item->isWearableType()) - continue; - EWearableType type = item->getWearableType(); - if(type < 0 || type >= WT_COUNT) - { - LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL; - continue; - } - items_by_type[type].push_back(item); - } + divvyWearablesByType(items, items_by_type); // rebuild items list, retaining the last max_per_type of each array items.clear(); @@ -853,6 +849,7 @@ void LLAppearanceMgr::linkAll(const LLUUID& category, item->getLinkedUUID(), category, item->getName(), + item->LLInventoryItem::getDescription(), LLAssetType::AT_LINK, cb); } @@ -956,7 +953,7 @@ void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLI if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) { - link_inventory_item(gAgent.getID(), category, cof, catp->getName(), + link_inventory_item(gAgent.getID(), category, cof, catp->getName(), "", LLAssetType::AT_LINK_FOLDER, link_waiter); new_outfit_name = catp->getName(); } @@ -1016,6 +1013,18 @@ static void remove_non_link_items(LLInventoryModel::item_array_t &items) items = pruned_items; } +//a predicate for sorting inventory items by actual descriptions +bool sort_by_description(const LLInventoryItem* item1, const LLInventoryItem* item2) +{ + if (!item1 || !item2) + { + llwarning("either item1 or item2 is NULL", 0); + return true; + } + + return item1->LLInventoryItem::getDescription() < item2->LLInventoryItem::getDescription(); +} + void LLAppearanceMgr::updateAppearanceFromCOF() { // update dirty flag to see if the state of the COF matches @@ -1026,6 +1035,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF() dumpCat(getCOF(),"COF, start"); + updateClothingOrderingInfo(); + bool follow_folder_links = true; LLUUID current_outfit_id = getCOF(); @@ -1046,6 +1057,9 @@ void LLAppearanceMgr::updateAppearanceFromCOF() return; } + //preparing the list of wearables in the correct order for LLAgentWearables + std::sort(wear_items.begin(), wear_items.end(), sort_by_description); + LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; holder->mObjItems = obj_items; @@ -1079,8 +1093,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF() } #endif - - holder->mFoundList.push_front(found); + //pushing back, not front, to preserve order of wearables for LLAgentWearables + holder->mFoundList.push_back(found); } else { @@ -1407,7 +1421,7 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update // Are these links to different items of the same wearable // type? If so, new item will replace old. // MULTI-WEARABLES: revisit if more than one per type is allowed. - else if (areMatchingWearables(vitem,inv_item)) + else if (FALSE/*areMatchingWearables(vitem,inv_item)*/) { if (inv_item->getIsLinkType()) { @@ -1430,6 +1444,7 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update vitem->getLinkedUUID(), getCOF(), vitem->getName(), + vitem->getDescription(), LLAssetType::AT_LINK, cb); } @@ -1446,6 +1461,7 @@ void LLAppearanceMgr::addEnsembleLink( LLInventoryCategory* cat, bool do_update cat->getLinkedUUID(), getCOF(), cat->getName(), + cat->getDescription(), LLAssetType::AT_LINK_FOLDER, cb); #endif @@ -1572,6 +1588,8 @@ bool LLAppearanceMgr::updateBaseOutfit() const LLUUID base_outfit_id = getBaseOutfitUUID(); if (base_outfit_id.isNull()) return false; + updateClothingOrderingInfo(); + // in a Base Outfit we do not remove items, only links purgeCategory(base_outfit_id, false); @@ -1581,6 +1599,168 @@ bool LLAppearanceMgr::updateBaseOutfit() return true; } +void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type) +{ + items_by_type.reserve(WT_COUNT); + if (items.empty()) return; + + for (S32 i=0; i<items.count(); i++) + { + LLViewerInventoryItem *item = items.get(i); + // Ignore non-wearables. + if (!item->isWearableType()) + continue; + EWearableType type = item->getWearableType(); + if(type < 0 || type >= WT_COUNT) + { + LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL; + continue; + } + items_by_type[type].push_back(item); + } +} + +std::string build_order_string(EWearableType type, U32 i) +{ + std::ostringstream order_num; + order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i; + return order_num.str(); +} + +struct WearablesOrderComparator +{ + WearablesOrderComparator(const EWearableType type) + { + mControlSize = build_order_string(type, 0).size(); + }; + + bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2) + { + if (!item1 || !item2) + { + llwarning("either item1 or item2 is NULL", 0); + return true; + } + + const std::string& desc1 = item1->LLInventoryItem::getDescription(); + const std::string& desc2 = item2->LLInventoryItem::getDescription(); + + bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]); + bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]); + + if (item1_valid && item2_valid) + return desc1 < desc2; + + //we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions, + //items with ordering information but not for the associated wearables type + if (!item1_valid && item2_valid) + return false; + + return true; + } + + U32 mControlSize; +}; + +void LLAppearanceMgr::updateClothingOrderingInfo() +{ + LLInventoryModel::item_array_t wear_items; + getDescendentsOfAssetType(getCOF(), wear_items, LLAssetType::AT_CLOTHING, false); + + wearables_by_type_t items_by_type(WT_COUNT); + divvyWearablesByType(wear_items, items_by_type); + + bool inventory_changed = false; + for (U32 type = WT_SHIRT; type < WT_COUNT; type++) + { + + U32 size = items_by_type[type].size(); + if (!size) continue; + + //sinking down invalid items which need reordering + std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((EWearableType) type)); + + //requesting updates only for those links which don't have "valid" descriptions + for (U32 i = 0; i < size; i++) + { + LLViewerInventoryItem* item = items_by_type[type][i]; + if (!item) continue; + + std::string new_order_str = build_order_string((EWearableType)type, i); + if (new_order_str == item->LLInventoryItem::getDescription()) continue; + + item->setDescription(new_order_str); + item->setComplete(TRUE); + item->updateServer(FALSE); + gInventory.updateItem(item); + inventory_changed = true; + } + } + + //*TODO do we really need to notify observers? + if (inventory_changed) gInventory.notifyObservers(); +} + + + + +class LLShowCreatedOutfit: public LLInventoryCallback +{ +public: + LLShowCreatedOutfit(LLUUID& folder_id): mFolderID(folder_id) + {} + + virtual ~LLShowCreatedOutfit() + { + LLSD key; + LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key); + LLPanelOutfitsInventory *outfit_panel = + dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory")); + if (outfit_panel) + { + outfit_panel->getRootFolder()->clearSelection(); + outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE); + } + + LLAccordionCtrlTab* tab_outfits = outfit_panel ? outfit_panel->findChild<LLAccordionCtrlTab>("tab_outfits") : 0; + if (tab_outfits && !tab_outfits->getDisplayChildren()) + { + tab_outfits->changeOpenClose(tab_outfits->getDisplayChildren()); + } + + LLAppearanceMgr::getInstance()->updateIsDirty(); + LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); + } + + virtual void fire(const LLUUID&) + {} + +private: + LLUUID mFolderID; +}; + +LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name) +{ + if (!isAgentAvatarValid()) return LLUUID::null; + + // 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, + new_folder_name); + + updateClothingOrderingInfo(); + + LLPointer<LLInventoryCallback> cb = new LLShowCreatedOutfit(folder_id); + shallowCopyCategoryContents(getCOF(),folder_id, cb); + createBaseOutfitLink(folder_id, cb); + + dumpCat(folder_id,"COF, new outfit"); + + return folder_id; +} + void LLAppearanceMgr::wearBaseOutfit() { const LLUUID& base_outfit_id = getBaseOutfitUUID(); diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 7e35919892..efb5274c5b 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -138,12 +138,23 @@ public: //Remove clothing or detach an object from the agent (a bodypart cannot be removed) void removeItemFromAvatar(const LLUUID& item_id); + + LLUUID makeNewOutfitLinks(const std::string& new_folder_name); + protected: LLAppearanceMgr(); ~LLAppearanceMgr(); private: + typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t; + + //Divvy items into arrays by wearable type + static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type); + + //Check ordering information on wearables stored in links' descriptions and update if it is invalid + void updateClothingOrderingInfo(); + void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type); void getDescendentsOfAssetType(const LLUUID& category, diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index aef36b677c..6ee14e8ba9 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -44,6 +44,8 @@ #include "llviewercontrol.h" #include "llagentdata.h" +#include "llslurl.h" + static const S32 msg_left_offset = 10; static const S32 msg_right_offset = 10; static const S32 msg_height_pad = 5; @@ -190,6 +192,8 @@ void LLNearbyChatToastPanel::init(LLSD& notification) style_params_name.font.name(font_name); style_params_name.font.size(font_style_size); + style_params_name.link_href = LLSLURL::buildCommand("agent",mFromID,"about"); + msg_text->appendText(str_sender, FALSE, style_params_name); } diff --git a/indra/newview/llfilteredwearablelist.cpp b/indra/newview/llfilteredwearablelist.cpp new file mode 100644 index 0000000000..01d3c3f22e --- /dev/null +++ b/indra/newview/llfilteredwearablelist.cpp @@ -0,0 +1,113 @@ +/** + * @file llfilteredwearablelist.cpp + * @brief Functionality for showing filtered wearable flat list + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llfilteredwearablelist.h" + +// newview +#include "llinventoryfunctions.h" +#include "llinventoryitemslist.h" +#include "llinventorymodel.h" + +class LLFindItemsByMask : public LLInventoryCollectFunctor +{ +public: + LLFindItemsByMask(U64 mask) + : mFilterMask(mask) + {} + + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if(item) + { + if( mFilterMask & (1LL << item->getInventoryType()) ) + { + return TRUE; + } + } + return FALSE; + } + +private: + U64 mFilterMask; +}; + +////////////////////////////////////////////////////////////////////////// + +LLFilteredWearableListManager::LLFilteredWearableListManager(LLInventoryItemsList* list, U64 filter_mask) +: mWearableList(list) +, mFilterMask(filter_mask) +{ + llassert(mWearableList); + gInventory.addObserver(this); + gInventory.fetchDescendentsOf(gInventory.getRootFolderID()); +} + +LLFilteredWearableListManager::~LLFilteredWearableListManager() +{ + gInventory.removeObserver(this); +} + +void LLFilteredWearableListManager::changed(U32 mask) +{ + if(!gInventory.isInventoryUsable()) + { + return; + } + + populateList(); +} + +void LLFilteredWearableListManager::setFilterMask(U64 mask) +{ + mFilterMask = mask; + populateList(); +} + +void LLFilteredWearableListManager::populateList() +{ + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLFindItemsByMask collector(mFilterMask); + + gInventory.collectDescendentsIf( + gInventory.getRootFolderID(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + collector); + + // Probably will also need to get items from Library (waiting for reply in EXT-6724). + + mWearableList->refreshList(item_array); +} + +// EOF diff --git a/indra/newview/llfilteredwearablelist.h b/indra/newview/llfilteredwearablelist.h new file mode 100644 index 0000000000..3f42833bb4 --- /dev/null +++ b/indra/newview/llfilteredwearablelist.h @@ -0,0 +1,70 @@ +/** + * @file llfilteredwearablelist.h + * @brief Functionality for showing filtered wearable flat list + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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_LLFILTEREDWEARABLELIST_H +#define LL_LLFILTEREDWEARABLELIST_H + +#include "llinventoryobserver.h" + +class LLInventoryItemsList; + +// Class that fills LLInventoryItemsList with filtered data. +class LLFilteredWearableListManager : public LLInventoryObserver +{ + LOG_CLASS(LLFilteredWearableListManager); +public: + + LLFilteredWearableListManager(LLInventoryItemsList* list, U64 filter_mask); + ~LLFilteredWearableListManager(); + + /** LLInventoryObserver implementation + * + */ + /*virtual*/ void changed(U32 mask); + + /** + * Sets new filter and applies it immediately + */ + void setFilterMask(U64 mask); + + /** + * Populates wearable list with filtered data. + */ + void populateList(); + +private: + LLInventoryItemsList* mWearableList; + U64 mFilterMask; +}; + +#endif //LL_LLFILTEREDWEARABLELIST_H + +// EOF diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index b85bf0d518..b4a1bf2758 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2520,6 +2520,7 @@ void LLFolderBridge::pasteLinkFromClipboard() item->getLinkedUUID(), parent_id, item->getName(), + item->getDescription(), LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL)); } @@ -3166,6 +3167,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, inv_item->getLinkedUUID(), mUUID, inv_item->getName(), + inv_item->getDescription(), LLAssetType::AT_LINK, cb); } diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp new file mode 100644 index 0000000000..9f54b86607 --- /dev/null +++ b/indra/newview/llinventoryitemslist.cpp @@ -0,0 +1,211 @@ +/** + * @file llinventoryitemslist.cpp + * @brief A list of inventory items represented by LLFlatListView. + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llinventoryitemslist.h" + +// llcommon +#include "llcommonutils.h" + +#include "lliconctrl.h" + +#include "llinventoryfunctions.h" +#include "lltextutil.h" + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +LLPanelInventoryItem::LLPanelInventoryItem(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 wearable_type, + const std::string &item_name, + const std::string &hl) +: LLPanel() + ,mItemName(item_name) + ,mHighlightedText(hl) + ,mIcon(NULL) + ,mTitle(NULL) +{ + mItemIcon = get_item_icon(asset_type, inventory_type, wearable_type, FALSE); + + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_inventory_item.xml"); +} + +LLPanelInventoryItem::~LLPanelInventoryItem() +{} + +//virtual +BOOL LLPanelInventoryItem::postBuild() +{ + mIcon = getChild<LLIconCtrl>("item_icon"); + mTitle = getChild<LLTextBox>("item_name"); + + updateItem(); + + return TRUE; +} + +//virtual +void LLPanelInventoryItem::setValue(const LLSD& value) +{ + if (!value.isMap()) return; + if (!value.has("selected")) return; + childSetVisible("selected_icon", value["selected"]); +} + +void LLPanelInventoryItem::updateItem() +{ + if (mItemIcon.notNull()) + mIcon->setImage(mItemIcon); + + LLTextUtil::textboxSetHighlightedVal( + mTitle, + LLStyle::Params(), + mItemName, + mHighlightedText); +} + +void LLPanelInventoryItem::onMouseEnter(S32 x, S32 y, MASK mask) +{ + childSetVisible("hovered_icon", true); + + LLPanel::onMouseEnter(x, y, mask); +} + +void LLPanelInventoryItem::onMouseLeave(S32 x, S32 y, MASK mask) +{ + childSetVisible("hovered_icon", false); + + LLPanel::onMouseLeave(x, y, mask); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +LLInventoryItemsList::LLInventoryItemsList(const LLFlatListView::Params& p) +: LLFlatListView(p) +, mNeedsRefresh(false) +{} + +// virtual +LLInventoryItemsList::~LLInventoryItemsList() +{} + +void LLInventoryItemsList::refreshList(const LLInventoryModel::item_array_t item_array) +{ + getIDs().clear(); + LLInventoryModel::item_array_t::const_iterator it = item_array.begin(); + for( ; item_array.end() != it; ++it) + { + getIDs().push_back((*it)->getUUID()); + } + mNeedsRefresh = true; +} + +void LLInventoryItemsList::draw() +{ + LLFlatListView::draw(); + if(mNeedsRefresh) + { + refresh(); + } +} + +void LLInventoryItemsList::refresh() +{ + static const unsigned ADD_LIMIT = 50; + + uuid_vec_t added_items; + uuid_vec_t removed_items; + + computeDifference(getIDs(), added_items, removed_items); + + bool add_limit_exceeded = false; + unsigned nadded = 0; + + uuid_vec_t::const_iterator it = added_items.begin(); + for( ; added_items.end() != it; ++it) + { + if(nadded >= ADD_LIMIT) + { + add_limit_exceeded = true; + break; + } + LLViewerInventoryItem* item = gInventory.getItem(*it); + addNewItem(item); + ++nadded; + } + + it = removed_items.begin(); + for( ; removed_items.end() != it; ++it) + { + removeItemByUUID(*it); + } + + bool needs_refresh = add_limit_exceeded; + setNeedsRefresh(needs_refresh); +} + +void LLInventoryItemsList::computeDifference( + const uuid_vec_t& vnew, + uuid_vec_t& vadded, + uuid_vec_t& vremoved) +{ + uuid_vec_t vcur; + { + std::vector<LLSD> vcur_values; + getValues(vcur_values); + + for (size_t i=0; i<vcur_values.size(); i++) + vcur.push_back(vcur_values[i].asUUID()); + } + + LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved); +} + +void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item) +{ + llassert(item); + + LLPanelInventoryItem *list_item = new LLPanelInventoryItem(item->getType(), + item->getInventoryType(), item->getFlags(), item->getName(), LLStringUtil::null); + + if (!addItem(list_item, item->getUUID())) + { + llwarns << "Couldn't add flat list item." << llendl; + llassert(!"Couldn't add flat list item."); + } +} + +// EOF diff --git a/indra/newview/llinventoryitemslist.h b/indra/newview/llinventoryitemslist.h new file mode 100644 index 0000000000..0ca4146867 --- /dev/null +++ b/indra/newview/llinventoryitemslist.h @@ -0,0 +1,122 @@ +/** + * @file llinventoryitemslist.h + * @brief A list of inventory items represented by LLFlatListView. + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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_LLINVENTORYITEMSLIST_H +#define LL_LLINVENTORYITEMSLIST_H + +#include "llpanel.h" + +#include "llassettype.h" + +#include "llinventorytype.h" + +// newview +#include "llflatlistview.h" +#include "llinventorymodel.h" + +class LLIconCtrl; +class LLTextBox; + +class LLPanelInventoryItem : public LLPanel +{ +public: + LLPanelInventoryItem(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 wearable_type, + const std::string &item_name, + const std::string &hl); + virtual ~LLPanelInventoryItem(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void setValue(const LLSD& value); + + void updateItem(); + + void onMouseEnter(S32 x, S32 y, MASK mask); + void onMouseLeave(S32 x, S32 y, MASK mask); + +private: + LLIconCtrl* mIcon; + LLTextBox* mTitle; + + LLUIImagePtr mItemIcon; + std::string mItemName; + std::string mHighlightedText; +}; + + +class LLInventoryItemsList : public LLFlatListView +{ +public: + virtual ~LLInventoryItemsList(); + + void refreshList(const LLInventoryModel::item_array_t item_array); + + /** + * Let list know items need to be refreshed in next draw() + */ + void setNeedsRefresh(bool needs_refresh){ mNeedsRefresh = needs_refresh; } + + bool getNeedsRefresh(){ return mNeedsRefresh; } + + /*virtual*/ void draw(); + +protected: + friend class LLUICtrlFactory; + LLInventoryItemsList(const LLFlatListView::Params& p); + + uuid_vec_t& getIDs() { return mIDs; } + + /** + * Refreshes list items, adds new items and removes deleted items. + * Called from draw() until all new items are added, , + * maximum 50 items can be added during single call. + */ + void refresh(); + + /** + * Compute difference between new items and current items, fills 'vadded' with added items, + * 'vremoved' with removed items. See LLCommonUtils::computeDifference + */ + void computeDifference(const uuid_vec_t& vnew, uuid_vec_t& vadded, uuid_vec_t& vremoved); + + /** + * Add an item to the list + */ + void addNewItem(LLViewerInventoryItem* item); + +private: + uuid_vec_t mIDs; // IDs of items that were added in refreshList(). + // Will be used in refresh() to determine added and removed ids + bool mNeedsRefresh; +}; + +#endif //LL_LLINVENTORYITEMSLIST_H diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 29d99d328a..03006243f9 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -650,3 +650,35 @@ void LLInventoryTransactionObserver::changed(U32 mask) } } } + +void LLInventoryCategoriesObserver::changed(U32 mask) +{ + if (!mCategoryMap.size()) + return; + + for (category_map_t::iterator iter = mCategoryMap.begin(); + iter != mCategoryMap.end(); + iter++) + { + // Inventory category version is used to find out if some changes + // to a category have been made. + S32 version = gInventory.getCategory((*iter).first)->getVersion(); + if (version != (*iter).second.mVersion) + { + // Update category version in map. + (*iter).second.mVersion = version; + (*iter).second.mCallback(); + } + } +} + +void LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb) +{ + S32 version = gInventory.getCategory(cat_id)->getVersion(); + mCategoryMap.insert(category_map_value_t(cat_id, LLCategoryData(cb, version))); +} + +void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id) +{ + mCategoryMap.erase(mCategoryMap.find(cat_id)); +} diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index 8d60df7e8d..e63b67d2ad 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -261,5 +261,40 @@ protected: uuid_vec_t mIncomplete; }; -#endif // LL_LLINVENTORYOBSERVERS_H +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryCategoriesObserver +// +// This class is used for monitoring a list of inventory categories +// and firing a callback when there are changes in any of them. +// Categories are identified by their UUIDs. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryCategoriesObserver : public LLInventoryObserver +{ +public: + typedef boost::function<void()> callback_t; + + LLInventoryCategoriesObserver() {}; + virtual void changed(U32 mask); + + void addCategory(const LLUUID& cat_id, callback_t cb); + void removeCategory(const LLUUID& cat_id); +protected: + struct LLCategoryData + { + LLCategoryData(callback_t cb, S32 version) + : mCallback(cb) + , mVersion(version) + {} + + callback_t mCallback; + S32 mVersion; + }; + + typedef std::map<LLUUID, LLCategoryData> category_map_t; + typedef category_map_t::value_type category_map_value_t; + + category_map_t mCategoryMap; +}; + +#endif // LL_LLINVENTORYOBSERVERS_H diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 4e0be81f62..7abb4f4f16 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -38,6 +38,7 @@ // common includes #include "llbutton.h" #include "llfocusmgr.h" +#include "llhelp.h" #include "llmenugl.h" #include "llparcel.h" #include "llstring.h" @@ -177,6 +178,7 @@ static LLDefaultChildRegistry::Register<LLLocationInputCtrl> r("location_input") LLLocationInputCtrl::Params::Params() : icon_maturity_general("icon_maturity_general"), icon_maturity_adult("icon_maturity_adult"), + icon_maturity_moderate("icon_maturity_moderate"), add_landmark_image_enabled("add_landmark_image_enabled"), add_landmark_image_disabled("add_landmark_image_disabled"), add_landmark_image_hover("add_landmark_image_hover"), @@ -186,14 +188,15 @@ LLLocationInputCtrl::Params::Params() add_landmark_button("add_landmark_button"), for_sale_button("for_sale_button"), info_button("info_button"), - maturity_icon("maturity_icon"), + maturity_button("maturity_button"), voice_icon("voice_icon"), fly_icon("fly_icon"), push_icon("push_icon"), build_icon("build_icon"), scripts_icon("scripts_icon"), damage_icon("damage_icon"), - damage_text("damage_text") + damage_text("damage_text"), + maturity_help_topic("maturity_help_topic") { } @@ -208,7 +211,9 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) mLandmarkImageOn(NULL), mLandmarkImageOff(NULL), mIconMaturityGeneral(NULL), - mIconMaturityAdult(NULL) + mIconMaturityAdult(NULL), + mIconMaturityModerate(NULL), + mMaturityHelpTopic(p.maturity_help_topic) { // Lets replace default LLLineEditor with LLLocationLineEditor // to make needed escaping while copying and cutting url @@ -276,10 +281,15 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) { mIconMaturityAdult = p.icon_maturity_adult; } + if(p.icon_maturity_moderate()) + { + mIconMaturityModerate = p.icon_maturity_moderate; + } - LLIconCtrl::Params maturity_icon = p.maturity_icon; - mMaturityIcon = LLUICtrlFactory::create<LLIconCtrl>(maturity_icon); - addChild(mMaturityIcon); + LLButton::Params maturity_button = p.maturity_button; + mMaturityButton = LLUICtrlFactory::create<LLButton>(maturity_button); + addChild(mMaturityButton); + mMaturityButton->setClickedCallback(boost::bind(&LLLocationInputCtrl::onMaturityButtonClicked, this)); LLButton::Params for_sale_button = p.for_sale_button; for_sale_button.tool_tip = LLTrans::getString("LocationCtrlForSaleTooltip"); @@ -576,7 +586,7 @@ void LLLocationInputCtrl::reshape(S32 width, S32 height, BOOL called_from_parent if (isHumanReadableLocationVisible) { - refreshMaturityIcon(); + refreshMaturityButton(); } } @@ -613,6 +623,11 @@ void LLLocationInputCtrl::onAgentParcelChange() refresh(); } +void LLLocationInputCtrl::onMaturityButtonClicked() +{ + LLUI::sHelpImpl->showTopic(mMaturityHelpTopic); +} + void LLLocationInputCtrl::onLandmarkLoaded(LLLandmark* lm) { (void) lm; @@ -736,7 +751,7 @@ void LLLocationInputCtrl::refreshLocation() setText(location_name); isHumanReadableLocationVisible = true; - refreshMaturityIcon(); + refreshMaturityButton(); } // returns new right edge @@ -852,37 +867,54 @@ void LLLocationInputCtrl::refreshHealth() } } -void LLLocationInputCtrl::refreshMaturityIcon() +void LLLocationInputCtrl::refreshMaturityButton() { // Updating maturity rating icon. LLViewerRegion* region = gAgent.getRegion(); if (!region) return; + bool button_visible = true; + LLPointer<LLUIImage> rating_image = NULL; + std::string rating_tooltip; + U8 sim_access = region->getSimAccess(); switch(sim_access) { case SIM_ACCESS_PG: - mMaturityIcon->setValue(mIconMaturityGeneral->getName()); - mMaturityIcon->setVisible(TRUE); + rating_image = mIconMaturityGeneral; + rating_tooltip = LLTrans::getString("LocationCtrlGeneralIconTooltip"); break; case SIM_ACCESS_ADULT: - mMaturityIcon->setValue(mIconMaturityAdult->getName()); - mMaturityIcon->setVisible(TRUE); + rating_image = mIconMaturityAdult; + rating_tooltip = LLTrans::getString("LocationCtrlAdultIconTooltip"); + break; + + case SIM_ACCESS_MATURE: + rating_image = mIconMaturityModerate; + rating_tooltip = LLTrans::getString("LocationCtrlModerateIconTooltip"); break; default: - mMaturityIcon->setVisible(FALSE); + button_visible = false; + break; } - if (mMaturityIcon->getVisible()) + mMaturityButton->setVisible(button_visible); + mMaturityButton->setToolTip(rating_tooltip); + if(rating_image) + { + mMaturityButton->setImageUnselected(rating_image); + mMaturityButton->setImagePressed(rating_image); + } + if (mMaturityButton->getVisible()) { - positionMaturityIcon(); + positionMaturityButton(); } } -void LLLocationInputCtrl::positionMaturityIcon() +void LLLocationInputCtrl::positionMaturityButton() { const LLFontGL* font = mTextEntry->getFont(); if (!font) @@ -894,11 +926,11 @@ void LLLocationInputCtrl::positionMaturityIcon() // Calculate the right edge of rendered text + a whitespace. left_pad = left_pad + font->getWidth(mTextEntry->getText()) + font->getWidth(" "); - LLRect rect = mMaturityIcon->getRect(); - mMaturityIcon->setRect(rect.setOriginAndSize(left_pad, rect.mBottom, rect.getWidth(), rect.getHeight())); + LLRect rect = mMaturityButton->getRect(); + mMaturityButton->setRect(rect.setOriginAndSize(left_pad, rect.mBottom, rect.getWidth(), rect.getHeight())); // Hide icon if it text area is not width enough to display it, show otherwise. - mMaturityIcon->setVisible(rect.mRight < mTextEntry->getRect().getWidth() - right_pad); + mMaturityButton->setVisible(rect.mRight < mTextEntry->getRect().getWidth() - right_pad); } void LLLocationInputCtrl::rebuildLocationHistory(const std::string& filter) @@ -1014,7 +1046,7 @@ void LLLocationInputCtrl::changeLocationPresentation() mTextEntry->setText(LLAgentUI::buildSLURL(false)); mTextEntry->selectAll(); - mMaturityIcon->setVisible(FALSE); + mMaturityButton->setVisible(FALSE); isHumanReadableLocationVisible = false; } diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h index f790140f07..fc7adf60b0 100644 --- a/indra/newview/lllocationinputctrl.h +++ b/indra/newview/lllocationinputctrl.h @@ -66,17 +66,19 @@ public: { Optional<LLUIImage*> icon_maturity_general, icon_maturity_adult, + icon_maturity_moderate, add_landmark_image_enabled, add_landmark_image_disabled, add_landmark_image_hover, add_landmark_image_selected; + Optional<std::string> maturity_help_topic; Optional<S32> icon_hpad, add_landmark_hpad; - Optional<LLButton::Params> add_landmark_button, + Optional<LLButton::Params> maturity_button, + add_landmark_button, for_sale_button, info_button; - Optional<LLIconCtrl::Params> maturity_icon, - voice_icon, + Optional<LLIconCtrl::Params> voice_icon, fly_icon, push_icon, build_icon, @@ -136,8 +138,8 @@ private: void refreshParcelIcons(); // Refresh the value in the health percentage text field void refreshHealth(); - void refreshMaturityIcon(); - void positionMaturityIcon(); + void refreshMaturityButton(); + void positionMaturityButton(); void rebuildLocationHistory(const std::string& filter = LLStringUtil::null); bool findTeleportItemsByTitle(const LLTeleportHistoryItem& item, const std::string& filter); @@ -156,6 +158,7 @@ private: void onForSaleButtonClicked(); void onAddLandmarkButtonClicked(); void onAgentParcelChange(); + void onMaturityButtonClicked(); // callbacks bool onLocationContextMenuItemEnabled(const LLSD& userdata); void onLocationContextMenuItemClicked(const LLSD& userdata); @@ -168,7 +171,7 @@ private: S32 mIconHPad; // pad between all icons S32 mAddLandmarkHPad; // pad to left of landmark star - LLIconCtrl* mMaturityIcon; + LLButton* mMaturityButton; LLIconCtrl* mParcelIcon[ICON_COUNT]; LLTextBox* mDamageText; @@ -182,14 +185,16 @@ private: boost::signals2::connection mLocationHistoryConnection; LLUIImage* mLandmarkImageOn; LLUIImage* mLandmarkImageOff; - LLUIImage* mIconMaturityGeneral; - LLUIImage* mIconMaturityAdult; + LLPointer<LLUIImage> mIconMaturityGeneral; + LLPointer<LLUIImage> mIconMaturityAdult; + LLPointer<LLUIImage> mIconMaturityModerate; std::string mAddLandmarkTooltip; std::string mEditLandmarkTooltip; // this field holds a human-readable form of the location string, it is needed to be able to compare copy-pated value and real location std::string mHumanReadableLocation; bool isHumanReadableLocationVisible; + std::string mMaturityHelpTopic; }; #endif diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index 9611c286eb..d605d4430e 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -81,7 +81,7 @@ void LLNameListCtrl::addNameItem(const LLUUID& agent_id, EAddPosition pos, item.enabled = enabled; item.target = INDIVIDUAL; - addNameItemRow(item, pos); + addNameItemRow(item, pos, suffix); } // virtual, public diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp index e528f871af..df6f04b6ea 100644 --- a/indra/newview/llnotificationtiphandler.cpp +++ b/indra/newview/llnotificationtiphandler.cpp @@ -45,38 +45,6 @@ using namespace LLNotificationsUI; -class LLOnlineStatusToast : public LLPanelTipToast -{ -public: - - struct Params - { - LLNotificationPtr notification; - LLUUID avatar_id; - std::string message; - - Params() {} - }; - - LLOnlineStatusToast(Params& p) : LLPanelTipToast(p.notification) - { - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_online_status_toast.xml"); - - childSetValue("avatar_icon", p.avatar_id); - childSetValue("message", p.message); - - if (p.notification->getPayload().has("respond_on_mousedown") - && p.notification->getPayload()["respond_on_mousedown"] ) - { - setMouseDownCallback(boost::bind(&LLNotification::respond, p.notification, - p.notification->getResponseTemplate())); - } - - // set line max count to 3 in case of a very long name - snapToMessageHeight(getChild<LLTextBox>("message"), 3); - } -}; - //-------------------------------------------------------------------------- LLTipHandler::LLTipHandler(e_notification_type type, const LLSD& id) { @@ -157,28 +125,7 @@ bool LLTipHandler::processNotification(const LLSD& notify) return true; } - LLToastPanel* notify_box = NULL; - // TODO: this should be implemented in LLToastPanel::buidPanelFromNotification - if("FriendOffline" == notification->getName() || "FriendOnline" == notification->getName()) - { - LLOnlineStatusToast::Params p; - p.notification = notification; - p.message = notification->getMessage(); - p.avatar_id = notification->getPayload()["FROM_ID"]; - notify_box = new LLOnlineStatusToast(p); - } - else - { - notify_box = LLToastPanel::buidPanelFromNotification(notification); - } - - // TODO: this if statement should be removed after modification of - // LLToastPanel::buidPanelFromNotification() to allow create generic tip panel - // for all tip notifications except FriendOnline and FriendOffline - if (notify_box == NULL) - { - notify_box = new LLToastNotifyPanel(notification); - } + LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification); LLToast::Params p; p.notif_id = notification->getID(); diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp new file mode 100644 index 0000000000..ad42d80467 --- /dev/null +++ b/indra/newview/lloutfitslist.cpp @@ -0,0 +1,265 @@ +/** + * @file lloutfitslist.cpp + * @brief List of agent's outfits for My Appearance side panel. + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lloutfitslist.h" + +#include "llaccordionctrl.h" +#include "llaccordionctrltab.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "llwearableitemslist.h" + +static LLRegisterPanelClassWrapper<LLOutfitsList> t_outfits_list("outfits_list"); + +LLOutfitsList::LLOutfitsList() + : LLPanel() + , mAccordion(NULL) + , mListCommands(NULL) +{} + +LLOutfitsList::~LLOutfitsList() +{ + if (gInventory.containsObserver(mCategoriesObserver)) + { + gInventory.removeObserver(mCategoriesObserver); + delete mCategoriesObserver; + } + + if (gInventory.containsObserver(this)) + { + gInventory.removeObserver(this); + } +} + +BOOL LLOutfitsList::postBuild() +{ + mAccordion = getChild<LLAccordionCtrl>("outfits_accordion"); + + mCategoriesObserver = new LLInventoryCategoriesObserver(); + gInventory.addObserver(mCategoriesObserver); + + gInventory.addObserver(this); + + return TRUE; +} + +//virtual +void LLOutfitsList::changed(U32 mask) +{ + if (!gInventory.isInventoryUsable()) + return; + + // Start observing changes in "My Outfits" category. + const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + mCategoriesObserver->addCategory(outfits, + boost::bind(&LLOutfitsList::refreshList, this, outfits)); + + LLViewerInventoryCategory* category = gInventory.getCategory(outfits); + if (!category) + return; + + // Fetch "My Outfits" contents and refresh the list to display + // initially fetched items. If not all items are fetched now + // the observer will refresh the list as soon as the new items + // arrive. + category->fetch(); + refreshList(outfits); + + // This observer is used to start the initial outfits fetch + // when inventory becomes usable. It is no longer needed because + // "My Outfits" category is now observed by + // LLInventoryCategoriesObserver. + gInventory.removeObserver(this); +} + +void LLOutfitsList::refreshList(const LLUUID& category_id) +{ + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + // Collect all sub-categories of a given category. + LLIsType is_category(LLAssetType::AT_CATEGORY); + gInventory.collectDescendentsIf( + category_id, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_category); + + uuid_vec_t vnew; + + // Creating a vector of newly collected sub-categories UUIDs. + for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); + iter != cat_array.end(); + iter++) + { + vnew.push_back((*iter)->getUUID()); + } + + uuid_vec_t vcur; + + // Creating a vector of currently displayed sub-categories UUIDs. + for (outfits_map_t::const_iterator iter = mOutfitsMap.begin(); + iter != mOutfitsMap.end(); + iter++) + { + vcur.push_back((*iter).first); + } + + // Sorting both vectors to compare. + std::sort(vcur.begin(), vcur.end()); + std::sort(vnew.begin(), vnew.end()); + + uuid_vec_t vadded; + uuid_vec_t vremoved; + + uuid_vec_t::iterator it; + size_t maxsize = llmax(vcur.size(), vnew.size()); + vadded.resize(maxsize); + vremoved.resize(maxsize); + + // what to remove + it = set_difference(vcur.begin(), vcur.end(), vnew.begin(), vnew.end(), vremoved.begin()); + vremoved.erase(it, vremoved.end()); + + // what to add + it = set_difference(vnew.begin(), vnew.end(), vcur.begin(), vcur.end(), vadded.begin()); + vadded.erase(it, vadded.end()); + + // Handle added tabs. + for (uuid_vec_t::const_iterator iter = vadded.begin(); + iter != vadded.end(); + iter++) + { + const LLUUID cat_id = (*iter); + LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); + if (!cat) + continue; + + std::string name = cat->getName(); + + // *TODO: create accordion tabs and lists from XML. + LLAccordionCtrlTab::Params params; + params.name(name); + params.title(name); + params.rect(LLRect(0, 0, 315, 20)); + params.display_children(false); + LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(params); + + mAccordion->addCollapsibleCtrl(tab); + + LLFlatListView::Params list_params; + LLWearableItemsList* list = LLUICtrlFactory::create<LLWearableItemsList>(list_params); + + tab->addChild(list, 0); + tab->setDisplayChildren(false); + + // Map the new tab with outfit category UUID. + mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab)); + + // Start observing the new outfit category. + mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id)); + + // Fetch the new outfit contents. + cat->fetch(); + + // Refresh the list of outfit items after fetch(). + // Further list updates will be triggered by the category observer. + list->updateList(cat_id); + } + + // Handle removed tabs. + for (uuid_vec_t::const_iterator iter=vremoved.begin(); iter != vremoved.end(); iter++) + { + outfits_map_t::iterator outfits_iter = mOutfitsMap.find((*iter)); + if (outfits_iter != mOutfitsMap.end()) + { + // An outfit is removed from the list. Do the following: + // 1. Remove outfit accordion tab from accordion. + mAccordion->removeCollapsibleCtrl(outfits_iter->second); + + // 2. Remove outfit category from observer to stop monitoring its changes. + mCategoriesObserver->removeCategory(outfits_iter->first); + + // 3. Remove category UUID to accordion tab mapping. + mOutfitsMap.erase(outfits_iter); + } + } + + // Get changed items from inventory model and update outfit tabs + // which might have been renamed. + const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs(); + for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin(); + items_iter != changed_items.end(); + ++items_iter) + { + updateOutfitTab(*items_iter); + } + + mAccordion->arrange(); +} + +void LLOutfitsList::updateOutfitTab(const LLUUID& category_id) +{ + outfits_map_t::iterator outfits_iter = mOutfitsMap.find(category_id); + if (outfits_iter != mOutfitsMap.end()) + { + LLViewerInventoryCategory *cat = gInventory.getCategory(category_id); + if (!cat) + return; + + std::string name = cat->getName(); + + // Update tab name with the new category name. + LLAccordionCtrlTab* tab = outfits_iter->second; + if (tab) + { + tab->setName(name); + } + + // Update tab title with the new category name using textbox + // in accordion tab header. + LLTextBox* tab_title = tab->findChild<LLTextBox>("dd_textbox"); + if (tab_title) + { + tab_title->setText(name); + } + } +} + +void LLOutfitsList::setFilterSubString(const std::string& string) +{ + mFilterSubString = string; +} + +// EOF diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h new file mode 100644 index 0000000000..892e0a862a --- /dev/null +++ b/indra/newview/lloutfitslist.h @@ -0,0 +1,74 @@ +/** + * @file lloutfitslist.h + * @brief List of agent's outfits for My Appearance side panel. + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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_LLOUTFITSLIST_H +#define LL_LLOUTFITSLIST_H + +#include "llpanel.h" + +// newview +#include "llinventoryobserver.h" + +class LLAccordionCtrl; +class LLAccordionCtrlTab; +class LLWearableItemsList; + +class LLOutfitsList : public LLPanel, public LLInventoryObserver +{ +public: + LLOutfitsList(); + virtual ~LLOutfitsList(); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void changed(U32 mask); + + void refreshList(const LLUUID& category_id); + + // Update tab displaying outfit identified by category_id. + void updateOutfitTab(const LLUUID& category_id); + + void setFilterSubString(const std::string& string); + +private: + LLInventoryCategoriesObserver* mCategoriesObserver; + + LLAccordionCtrl* mAccordion; + LLPanel* mListCommands; + + std::string mFilterSubString; + + typedef std::map<LLUUID, LLAccordionCtrlTab*> outfits_map_t; + typedef outfits_map_t::value_type outfits_map_value_t; + outfits_map_t mOutfitsMap; +}; + +#endif //LL_LLOUTFITSLIST_H diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index ee4dcc44fe..529a368dc3 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -1007,7 +1007,7 @@ void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data) { if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE) { - LLNotificationsUtil::add("CapsKeyOn"); +// *TODO: use another way to notify user about enabled caps lock, see EXT-6858 sCapslockDidNotification = TRUE; } } diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp index 35acf8edcc..3f620869e0 100644 --- a/indra/newview/llpanelme.cpp +++ b/indra/newview/llpanelme.cpp @@ -63,7 +63,6 @@ BOOL LLPanelMe::postBuild() LLPanelProfile::postBuild(); getTabContainer()[PANEL_PROFILE]->childSetAction("edit_profile_btn", boost::bind(&LLPanelMe::onEditProfileClicked, this), this); - getTabContainer()[PANEL_PROFILE]->childSetAction("edit_appearance_btn", boost::bind(&LLPanelMe::onEditAppearanceClicked, this), this); return TRUE; } @@ -141,14 +140,6 @@ void LLPanelMe::onEditProfileClicked() togglePanel(mEditPanel, getAvatarId()); // open } -void LLPanelMe::onEditAppearanceClicked() -{ - if (gAgentWearables.areWearablesLoaded()) - { - gAgentCamera.changeCameraToCustomizeAvatar(); - } -} - void LLPanelMe::onSaveChangesClicked() { LLAvatarData data = LLAvatarData(); diff --git a/indra/newview/llpanelme.h b/indra/newview/llpanelme.h index 1325192bbf..f2b38de3d6 100644 --- a/indra/newview/llpanelme.h +++ b/indra/newview/llpanelme.h @@ -63,7 +63,6 @@ private: void buildEditPanel(); void onEditProfileClicked(); - void onEditAppearanceClicked(); void onSaveChangesClicked(); void onCancelClicked(); diff --git a/indra/newview/llpanelonlinestatus.cpp b/indra/newview/llpanelonlinestatus.cpp new file mode 100644 index 0000000000..6ba015b11c --- /dev/null +++ b/indra/newview/llpanelonlinestatus.cpp @@ -0,0 +1,60 @@ +/** + * @file llpanelonlinestatus.cpp + * @brief Represents a class of online status tip toast panels. + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llnotifications.h" +#include "llpanelonlinestatus.h" + +LLPanelOnlineStatus::LLPanelOnlineStatus( + const LLNotificationPtr& notification) : + LLPanelTipToast(notification) +{ + + LLUICtrlFactory::getInstance()->buildPanel(this, + "panel_online_status_toast.xml"); + + + childSetValue("avatar_icon", notification->getPayload()["FROM_ID"]); + childSetValue("message", notification->getMessage()); + + if (notification->getPayload().has("respond_on_mousedown") + && notification->getPayload()["respond_on_mousedown"]) + { + setMouseDownCallback(boost::bind(&LLNotification::respond, + notification, notification->getResponseTemplate())); + } + + // set line max count to 3 in case of a very long name + snapToMessageHeight(getChild<LLTextBox> ("message"), 3); + +} diff --git a/indra/newview/llpanelonlinestatus.h b/indra/newview/llpanelonlinestatus.h new file mode 100644 index 0000000000..b47050c3a2 --- /dev/null +++ b/indra/newview/llpanelonlinestatus.h @@ -0,0 +1,53 @@ +/** + * @file llpanelonlinestatus.h + * @brief Represents a class of online status tip toast panels. + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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 "llpaneltiptoast.h" + +#ifndef LL_PANELONLINESTATUS_H +#define LL_PANELONLINESTATUS_H + +/** + * Represents online tip toast panel. + */ +class LLPanelOnlineStatus : public LLPanelTipToast +{ + // disallow instantiation of this class +private: + // grant privileges to instantiate this class to LLToastPanel + friend class LLToastPanel; + + LLPanelOnlineStatus(const LLNotificationPtr& notification); + virtual ~LLPanelOnlineStatus() {} +}; + +#endif /* LL_PANELONLINESTATUS_H */ diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index ce17e1d624..e139cb31d6 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -38,7 +38,9 @@ #include "llagent.h" #include "llagentwearables.h" #include "llappearancemgr.h" +#include "llfilteredwearablelist.h" #include "llinventory.h" +#include "llinventoryitemslist.h" #include "llviewercontrol.h" #include "llui.h" #include "llfloater.h" @@ -164,6 +166,7 @@ BOOL LLPanelOutfitEdit::postBuild() 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); mLookContents = getChild<LLScrollListCtrl>("look_items_list"); mLookContents->sortByColumn("look_item_sort", TRUE); @@ -229,6 +232,9 @@ BOOL LLPanelOutfitEdit::postBuild() save_registar.add("Outfit.SaveAsNew.Action", boost::bind(&LLPanelOutfitEdit::saveOutfit, this, true)); mSaveMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_save_outfit.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mWearableListManager = new LLFilteredWearableListManager( + getChild<LLInventoryItemsList>("filtered_wearables_list"), ALL_ITEMS_MASK); + return TRUE; } @@ -242,6 +248,11 @@ void LLPanelOutfitEdit::showWearablesFilter() childSetVisible("filter_combobox_panel", childGetValue("filter_button")); } +void LLPanelOutfitEdit::showFilteredWearablesPanel() +{ + childSetVisible("filtered_wearables_panel", !childIsVisible("filtered_wearables_panel")); +} + void LLPanelOutfitEdit::saveOutfit(bool as_new) { if (!as_new && LLAppearanceMgr::getInstance()->updateBaseOutfit()) @@ -275,6 +286,7 @@ void LLPanelOutfitEdit::onTypeFilterChanged(LLUICtrl* ctrl) { U32 curr_filter_type = type_filter->getCurrentIndex(); mInventoryItemsPanel->setFilterTypes(mLookItemTypes[curr_filter_type].inventoryMask); + mWearableListManager->setFilterMask(mLookItemTypes[curr_filter_type].inventoryMask); } mSavedFolderState->setApply(TRUE); @@ -577,4 +589,4 @@ void LLPanelOutfitEdit::displayCurrentOutfit() updateLookInfo(); } - +// EOF diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index 69e8016534..308ee23115 100644 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -55,6 +55,7 @@ class LLScrollListCtrl; class LLToggleableMenu; class LLLookFetchObserver; class LLFilterEditor; +class LLFilteredWearableListManager; class LLPanelOutfitEdit : public LLPanel { @@ -88,6 +89,7 @@ public: void showAddWearablesPanel(); void showWearablesFilter(); + void showFilteredWearablesPanel(); void saveOutfit(bool as_new = false); void showSaveMenu(); @@ -122,7 +124,9 @@ private: LLButton* mUpBtn; LLButton* mEditWearableBtn; LLToggleableMenu* mSaveMenu; - + + LLFilteredWearableListManager* mWearableListManager; + LLLookFetchObserver* mFetchLook; LLInventoryLookObserver* mLookObserver; std::vector<LLLookItemType> mLookItemTypes; diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index b78268da7b..789e85b46f 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -49,6 +49,7 @@ #include "lllineeditor.h" #include "llmodaldialog.h" #include "llnotificationsutil.h" +#include "lloutfitslist.h" #include "llsidepanelappearance.h" #include "llsidetray.h" #include "lltabcontainer.h" @@ -71,7 +72,8 @@ bool LLPanelOutfitsInventory::sShowDebugEditor = false; LLPanelOutfitsInventory::LLPanelOutfitsInventory() : - mActivePanel(NULL), + mMyOutfitsPanel(NULL), + mCurrentOutfitPanel(NULL), mParent(NULL) { mSavedFolderState = new LLSaveFolderState(); @@ -145,9 +147,17 @@ void LLPanelOutfitsInventory::setParent(LLSidepanelAppearance* parent) void LLPanelOutfitsInventory::onSearchEdit(const std::string& string) { mFilterSubString = string; + + // TODO: add handling "My Outfits" tab. + if (!isCOFPanelActive()) + { + mMyOutfitsPanel->setFilterSubString(string); + return; + } + if (string == "") { - mActivePanel->setFilterSubString(LLStringUtil::null); + getActivePanel()->setFilterSubString(LLStringUtil::null); // re-open folders that were initially open mSavedFolderState->setApply(TRUE); @@ -159,7 +169,7 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string) LLInventoryModelBackgroundFetch::instance().start(); - if (mActivePanel->getFilterSubString().empty() && string.empty()) + if (getActivePanel()->getFilterSubString().empty() && string.empty()) { // current filter and new filter empty, do nothing return; @@ -173,7 +183,7 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string) } // set new filter string - mActivePanel->setFilterSubString(string); + getActivePanel()->setFilterSubString(string); } void LLPanelOutfitsInventory::onWearButtonClick() @@ -216,7 +226,7 @@ bool LLPanelOutfitsInventory::onSaveCommit(const LLSD& notification, const LLSD& LLStringUtil::trim(outfit_name); if( !outfit_name.empty() ) { - LLUUID outfit_folder = gAgentWearables.makeNewOutfitLinks(outfit_name); + LLUUID outfit_folder = LLAppearanceMgr::getInstance()->makeNewOutfitLinks(outfit_name); LLSidepanelAppearance* panel_appearance = dynamic_cast<LLSidepanelAppearance *>(LLSideTray::getInstance()->getPanel("sidepanel_appearance")); @@ -267,6 +277,11 @@ void LLPanelOutfitsInventory::onSave() void LLPanelOutfitsInventory::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action) { updateVerbs(); + + // TODO: add handling "My Outfits" tab. + if (!isCOFPanelActive()) + return; + if (getRootFolder()->needsAutoRename() && items.size()) { getRootFolder()->startRenamingSelectedItem(); @@ -284,6 +299,10 @@ void LLPanelOutfitsInventory::showEditOutfitPanel() LLFolderViewEventListener *LLPanelOutfitsInventory::getCorrectListenerForAction() { + // TODO: add handling "My Outfits" tab. + if (!isCOFPanelActive()) + return NULL; + LLFolderViewItem* current_item = getRootFolder()->getCurSelectedItem(); if (!current_item) return NULL; @@ -311,7 +330,7 @@ bool LLPanelOutfitsInventory::getIsCorrectType(const LLFolderViewEventListener * LLFolderView *LLPanelOutfitsInventory::getRootFolder() { - return mActivePanel->getRootFolder(); + return getActivePanel()->getRootFolder(); } //static @@ -393,7 +412,11 @@ void LLPanelOutfitsInventory::onTrashButtonClick() void LLPanelOutfitsInventory::onClipboardAction(const LLSD& userdata) { std::string command_name = userdata.asString(); - getActivePanel()->getRootFolder()->doToSelected(getActivePanel()->getModel(),command_name); + // TODO: add handling "My Outfits" tab. + if (isCOFPanelActive()) + { + getActivePanel()->getRootFolder()->doToSelected(getActivePanel()->getModel(),command_name); + } updateListCommands(); updateVerbs(); } @@ -447,21 +470,26 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata) if (command_name == "delete" || command_name == "remove") { BOOL can_delete = FALSE; - LLFolderView* root = getActivePanel()->getRootFolder(); - if (root) + + // TODO: add handling "My Outfits" tab. + if (isCOFPanelActive()) { - std::set<LLUUID> selection_set; - root->getSelectionList(selection_set); - can_delete = (selection_set.size() > 0); - for (std::set<LLUUID>::iterator iter = selection_set.begin(); - iter != selection_set.end(); - ++iter) + LLFolderView* root = getActivePanel()->getRootFolder(); + if (root) { - const LLUUID &item_id = (*iter); - LLFolderViewItem *item = root->getItemByID(item_id); - can_delete &= item->getListener()->isItemRemovable(); + std::set<LLUUID> selection_set; + root->getSelectionList(selection_set); + can_delete = (selection_set.size() > 0); + for (std::set<LLUUID>::iterator iter = selection_set.begin(); + iter != selection_set.end(); + ++iter) + { + const LLUUID &item_id = (*iter); + LLFolderViewItem *item = root->getItemByID(item_id); + can_delete &= item->getListener()->isItemRemovable(); + } + return can_delete; } - return can_delete; } return FALSE; } @@ -517,12 +545,17 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata) bool LLPanelOutfitsInventory::hasItemsSelected() { bool has_items_selected = false; - LLFolderView* root = getActivePanel()->getRootFolder(); - if (root) + + // TODO: add handling "My Outfits" tab. + if (isCOFPanelActive()) { - std::set<LLUUID> selection_set; - root->getSelectionList(selection_set); - has_items_selected = (selection_set.size() > 0); + LLFolderView* root = getActivePanel()->getRootFolder(); + if (root) + { + std::set<LLUUID> selection_set; + root->getSelectionList(selection_set); + has_items_selected = (selection_set.size() > 0); + } } return has_items_selected; } @@ -549,74 +582,58 @@ bool LLPanelOutfitsInventory::handleDragAndDropToTrash(BOOL drop, EDragAndDropTy void LLPanelOutfitsInventory::initTabPanels() { - LLInventoryPanel *cof_panel = getChild<LLInventoryPanel>(COF_TAB_NAME); - cof_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - mTabPanels.push_back(cof_panel); + mCurrentOutfitPanel = getChild<LLInventoryPanel>(COF_TAB_NAME); + mCurrentOutfitPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + mCurrentOutfitPanel->setSelectCallback(boost::bind(&LLPanelOutfitsInventory::onTabSelectionChange, this, mCurrentOutfitPanel, _1, _2)); - LLInventoryPanel *myoutfits_panel = getChild<LLInventoryPanel>(OUTFITS_TAB_NAME); - myoutfits_panel->setFilterTypes(1LL << LLFolderType::FT_OUTFIT, LLInventoryFilter::FILTERTYPE_CATEGORY); - myoutfits_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - mTabPanels.push_back(myoutfits_panel); - - for (tabpanels_vec_t::iterator iter = mTabPanels.begin(); - iter != mTabPanels.end(); - ++iter) - { - LLInventoryPanel *panel = (*iter); - panel->setSelectCallback(boost::bind(&LLPanelOutfitsInventory::onTabSelectionChange, this, panel, _1, _2)); - } + mMyOutfitsPanel = getChild<LLOutfitsList>(OUTFITS_TAB_NAME); mAppearanceTabs = getChild<LLTabContainer>("appearance_tabs"); mAppearanceTabs->setCommitCallback(boost::bind(&LLPanelOutfitsInventory::onTabChange, this)); - mActivePanel = (LLInventoryPanel*)mAppearanceTabs->getCurrentPanel(); } void LLPanelOutfitsInventory::onTabSelectionChange(LLInventoryPanel* tab_panel, const std::deque<LLFolderViewItem*> &items, BOOL user_action) { if (user_action && items.size() > 0) { - for (tabpanels_vec_t::iterator iter = mTabPanels.begin(); - iter != mTabPanels.end(); - ++iter) + // TODO: add handling "My Outfits" tab. + if (isCOFPanelActive()) { - LLInventoryPanel *panel = (*iter); - if (panel == tab_panel) - { - mActivePanel = panel; - } - else - { - panel->getRootFolder()->clearSelection(); - } + onSelectionChange(items, user_action); + } + else + { + mCurrentOutfitPanel->getRootFolder()->clearSelection(); } } - onSelectionChange(items, user_action); } void LLPanelOutfitsInventory::onTabChange() { - mActivePanel = (LLInventoryPanel*)childGetVisibleTab("appearance_tabs"); - if (!mActivePanel) + // TODO: add handling "My Outfits" tab. + if (isCOFPanelActive()) { - return; + mCurrentOutfitPanel->setFilterSubString(mFilterSubString); + } + else + { + mMyOutfitsPanel->setFilterSubString(mFilterSubString); } - mActivePanel->setFilterSubString(mFilterSubString); + updateVerbs(); } BOOL LLPanelOutfitsInventory::isTabPanel(LLInventoryPanel *panel) const { - for(tabpanels_vec_t::const_iterator it = mTabPanels.begin(); - it != mTabPanels.end(); - ++it) + // TODO: add handling "My Outfits" tab. + if (mCurrentOutfitPanel == panel) { - if (*it == panel) - return TRUE; + return TRUE; } return FALSE; } BOOL LLPanelOutfitsInventory::isCOFPanelActive() const { - return (getActivePanel()->getName() == COF_TAB_NAME); + return (childGetVisibleTab("appearance_tabs")->getName() == COF_TAB_NAME); } diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index 5d0d27ee4f..4234cc45c5 100644 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -40,6 +40,7 @@ class LLFolderView; class LLFolderViewItem; class LLFolderViewEventListener; class LLInventoryPanel; +class LLOutfitsList; class LLSaveFolderState; class LLButton; class LLMenuGL; @@ -88,20 +89,21 @@ private: public: ////////////////////////////////////////////////////////////////////////////////// // tab panels - LLInventoryPanel* getActivePanel() { return mActivePanel; } - const LLInventoryPanel* getActivePanel() const { return mActivePanel; } + // TODO: change getActivePanel() to return the active tab instead of returning + // a pointer to "Wearing" inventory panel. + LLInventoryPanel* getActivePanel() { return mCurrentOutfitPanel; } + BOOL isTabPanel(LLInventoryPanel *panel) const; - + BOOL isCOFPanelActive() const; + protected: void initTabPanels(); void onTabSelectionChange(LLInventoryPanel* tab_panel, const std::deque<LLFolderViewItem*> &items, BOOL user_action); void onTabChange(); - BOOL isCOFPanelActive() const; private: - LLInventoryPanel* mActivePanel; - typedef std::vector<LLInventoryPanel *> tabpanels_vec_t; - tabpanels_vec_t mTabPanels; + LLOutfitsList* mMyOutfitsPanel; + LLInventoryPanel* mCurrentOutfitPanel; // tab panels // //////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index daa2a04f65..f60951ca66 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -645,6 +645,23 @@ void LLPanelPeople::onChange(EStatusType status, const std::string &channelURI, updateButtons(); } +void LLPanelPeople::updateFriendListHelpText() +{ + // show special help text for just created account to help finding friends. EXT-4836 + static LLTextBox* no_friends_text = getChild<LLTextBox>("no_friends_help_text"); + + // Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...) + // So, lets check all lists to avoid overlapping the text with online list. See EXT-6448. + bool any_friend_exists = mAllFriendList->filterHasMatches() || mOnlineFriendList->filterHasMatches(); + no_friends_text->setVisible(!any_friend_exists); + if (no_friends_text->getVisible()) + { + //update help text for empty lists + std::string message_name = mFilterSubString.empty() ? "no_friends_msg" : "no_filtered_friends_msg"; + no_friends_text->setText(getString(message_name)); + } +} + void LLPanelPeople::updateFriendList() { if (!mOnlineFriendList || !mAllFriendList) @@ -684,14 +701,6 @@ void LLPanelPeople::updateFriendList() online_friendsp.push_back(buddy_id); } - // show special help text for just created account to help found friends. EXT-4836 - static LLTextBox* no_friends_text = getChild<LLTextBox>("no_friends_msg"); - - // Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...) - // So, lets check all lists to avoid overlapping the text with online list. See EXT-6448. - bool any_friend_exists = (all_friendsp.size() > 0) || (online_friendsp.size() > 0); - no_friends_text->setVisible(!any_friend_exists); - /* * Avatarlists will be hidden by showFriendsAccordionsIfNeeded(), if they do not have items. * But avatarlist can be updated only if it is visible @see LLAvatarList::draw(); @@ -1436,6 +1445,9 @@ void LLPanelPeople::showFriendsAccordionsIfNeeded() // Rearrange accordions LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion"); accordion->arrange(); + + // keep help text in a synchronization with accordions visibility. + updateFriendListHelpText(); } } diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index 891381e2de..1bd3ea471c 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -73,6 +73,7 @@ private: } ESortOrder; // methods indirectly called by the updaters + void updateFriendListHelpText(); void updateFriendList(); void updateNearbyList(); void updateRecentList(); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 17784c31e3..89293d0e50 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -1071,8 +1071,7 @@ void LLPanelPlaces::updateVerbs() mSaveBtn->setVisible(isLandmarkEditModeOn); mCancelBtn->setVisible(isLandmarkEditModeOn); mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn); - mPlaceInfoBtn->setVisible(mPlaceInfoType != LANDMARK_INFO_TYPE && mPlaceInfoType != TELEPORT_HISTORY_INFO_TYPE - && !is_create_landmark_visible && !isLandmarkEditModeOn); + mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn); mShowOnMapBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos); mPlaceInfoBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos); diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index abef47d4be..87494daaa9 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -329,8 +329,8 @@ void LLSidepanelAppearance::updateVerbs() if (mPanelOutfitsInventory && !is_look_info_visible) { - const bool is_correct_type = (mPanelOutfitsInventory->getCorrectListenerForAction() != NULL); - mEditBtn->setEnabled(is_correct_type); +// const bool is_correct_type = (mPanelOutfitsInventory->getCorrectListenerForAction() != NULL); +// mEditBtn->setEnabled(is_correct_type); } else { diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index 22b12ee132..568cd4cb19 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -67,6 +67,7 @@ LLToast::Params::Params() LLToast::LLToast(const LLToast::Params& p) : LLModalDialog(LLSD(), p.is_modal), mPanel(p.panel), + mToastLifetime(p.lifetime_secs), mToastFadingTime(p.fading_time_secs), mNotificationID(p.notif_id), mSessionID(p.session_id), @@ -241,6 +242,13 @@ void LLToast::draw() drawChild(mHideBtn); } } + + // if timer started and remaining time <= fading time + if (mTimer->getStarted() && (mToastLifetime + - mTimer->getEventTimer().getElapsedTimeF32()) <= mToastFadingTime) + { + setBackgroundOpaque(FALSE); + } } //-------------------------------------------------------------------------- diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 4a213580da..4211f21ef1 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -209,6 +209,7 @@ private: // timer counts a lifetime of a toast std::auto_ptr<LLToastLifeTimer> mTimer; + F32 mToastLifetime; // in seconds F32 mToastFadingTime; // in seconds LLPanel* mPanel; diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp index d142a0665b..71598b3169 100644 --- a/indra/newview/lltoastpanel.cpp +++ b/indra/newview/lltoastpanel.cpp @@ -33,6 +33,7 @@ #include "llviewerprecompiledheaders.h" #include "llpanelgenerictip.h" +#include "llpanelonlinestatus.h" #include "llnotifications.h" #include "lltoastpanel.h" @@ -97,9 +98,19 @@ LLToastPanel* LLToastPanel::buidPanelFromNotification( { LLToastPanel* res = NULL; - if (notification->getName() == "SystemMessageTip") + //process tip toast panels + if ("notifytip" == notification->getType()) { - res = new LLPanelGenericTip(notification); + // if it is online/offline notification + if ("FriendOffline" == notification->getName() || "FriendOnline" == notification->getName()) + { + res = new LLPanelOnlineStatus(notification); + } + // in all other case we use generic tip panel + else + { + res = new LLPanelGenericTip(notification); + } } /* else if(...) diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 8a891b1462..f434d15843 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -923,6 +923,7 @@ void link_inventory_item( const LLUUID& item_id, const LLUUID& parent_id, const std::string& new_name, + const std::string& new_description, const LLAssetType::EType asset_type, LLPointer<LLInventoryCallback> cb) { @@ -948,7 +949,6 @@ void link_inventory_item( } LLUUID transaction_id; - std::string desc = "Broken link"; // This should only show if the object can't find its baseobj. LLInventoryType::EType inv_type = LLInventoryType::IT_NONE; if (dynamic_cast<const LLInventoryCategory *>(baseobj)) { @@ -979,7 +979,7 @@ void link_inventory_item( msg->addS8Fast(_PREHASH_Type, (S8)asset_type); msg->addS8Fast(_PREHASH_InvType, (S8)inv_type); msg->addStringFast(_PREHASH_Name, new_name); - msg->addStringFast(_PREHASH_Description, desc); + msg->addStringFast(_PREHASH_Description, new_description); } gAgent.sendReliableMessage(); } diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 9d449399e8..f296ce35ff 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -339,6 +339,7 @@ void link_inventory_item( const LLUUID& item_id, const LLUUID& parent_id, const std::string& new_name, + const std::string& new_description, const LLAssetType::EType asset_type, LLPointer<LLInventoryCallback> cb); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 0d02aa56b8..d75e55f259 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1800,10 +1800,8 @@ void inventory_offer_handler(LLOfferInfo* info) // Inform user that there is a script floater via toast system { payload["give_inventory_notification"] = TRUE; - LLNotification::Params params(p.name); - params.substitutions = p.substitutions; - params.payload = payload; - LLPostponedNotification::add<LLPostponedOfferNotification>( params, info->mFromID, false); + p.payload = payload; + LLPostponedNotification::add<LLPostponedOfferNotification>(p, info->mFromID, false); } } } @@ -2484,7 +2482,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // Note: lie to Nearby Chat, pretending that this is NOT an IM, because // IMs from obejcts don't open IM sessions. LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); - if(nearby_chat) + if(SYSTEM_FROM != name && nearby_chat) { LLSD args; args["owner_id"] = from_id; diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp new file mode 100644 index 0000000000..ff309cbbc3 --- /dev/null +++ b/indra/newview/llwearableitemslist.cpp @@ -0,0 +1,88 @@ +/** + * @file llwearableitemslist.cpp + * @brief A flat list of wearable items. + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llwearableitemslist.h" + +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" + +class LLFindOutfitItems : public LLInventoryCollectFunctor +{ +public: + LLFindOutfitItems() {} + virtual ~LLFindOutfitItems() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +}; + +bool LLFindOutfitItems::operator()(LLInventoryCategory* cat, + LLInventoryItem* item) +{ + if(item) + { + if((item->getType() == LLAssetType::AT_CLOTHING) + || (item->getType() == LLAssetType::AT_BODYPART) + || (item->getType() == LLAssetType::AT_OBJECT)) + { + return TRUE; + } + } + return FALSE; +} + +static const LLDefaultChildRegistry::Register<LLWearableItemsList> r("wearable_items_list"); + +LLWearableItemsList::LLWearableItemsList(const LLFlatListView::Params& p) +: LLInventoryItemsList(p) +{} + +// virtual +LLWearableItemsList::~LLWearableItemsList() +{} + +void LLWearableItemsList::updateList(const LLUUID& category_id) +{ + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + LLFindOutfitItems collector = LLFindOutfitItems(); + // collectDescendentsIf takes non-const reference: + gInventory.collectDescendentsIf( + category_id, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + collector); + + refreshList(item_array); +} diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h new file mode 100644 index 0000000000..e3b011912b --- /dev/null +++ b/indra/newview/llwearableitemslist.h @@ -0,0 +1,56 @@ +/** + * @file llwearableitemslist.h + * @brief A flat list of wearable items. + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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_LLWEARABLEITEMSLIST_H +#define LL_LLWEARABLEITEMSLIST_H + +#include "llpanel.h" + +#include "llassettype.h" + +#include "llinventorytype.h" + +// newview +#include "llinventoryitemslist.h" + +class LLWearableItemsList : public LLInventoryItemsList +{ +public: + virtual ~LLWearableItemsList(); + + void updateList(const LLUUID& category_id); + +protected: + friend class LLUICtrlFactory; + LLWearableItemsList(const LLFlatListView::Params& p); +}; + +#endif //LL_LLWEARABLEITEMSLIST_H diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 151180aae7..081a3721b1 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -1072,18 +1072,10 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask ) // zoomed out, so don't display anything about the count. JC if (agent_count > 0) { - // Merov: i18n horror!!! Even using gettext(), concatenating strings is not localizable. - // The singular/plural switch form here under might make no sense in some languages. Don't do that. - message += llformat("\n%d ", agent_count); - - if (agent_count == 1) - { - message += "person"; - } - else - { - message += "people"; - } + LLStringUtil::format_map_t string_args; + string_args["[NUMBER]"] = llformat("%d", agent_count); + message += '\n'; + message += getString((agent_count == 1 ? "world_map_person" : "world_map_people") , string_args); } } tooltip_msg.assign( message ); diff --git a/indra/newview/skins/default/xui/en/floater_im_container.xml b/indra/newview/skins/default/xui/en/floater_im_container.xml index 65a05f3ec5..ced8c29199 100644 --- a/indra/newview/skins/default/xui/en/floater_im_container.xml +++ b/indra/newview/skins/default/xui/en/floater_im_container.xml @@ -11,7 +11,7 @@ save_visibility="true" single_instance="true" title="CONVERSATIONS" - width="392"> + width="396"> <tab_container follows="left|right|top|bottom" height="390" @@ -27,7 +27,7 @@ halign="left" use_ellipses="true" top="0" - width="390" /> + width="394" /> <icon color="DefaultShadowLight" enabled="false" @@ -38,5 +38,5 @@ left="1" name="im_box_tab_container_icon" bottom="10" - width="390" /> + width="394" /> </multi_floater> diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml index 422e50f035..f537c81860 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -13,7 +13,7 @@ can_minimize="true" can_close="true" visible="false" - width="385" + width="394" can_resize="true" min_width="250" min_height="190"> @@ -22,7 +22,7 @@ default_tab_group="2" follows="all" height="320" - width="385" + width="394" layout="topleft" orientation="horizontal" name="im_panels" @@ -43,7 +43,7 @@ tab_group="2" top="0" height="200" - width="245" + width="254" user_resize="true"> <button height="20" @@ -70,7 +70,7 @@ parse_highlights="true" allow_html="true" left="1" - width="240"> + width="249"> </chat_history> <line_editor bottom="0" @@ -81,7 +81,7 @@ layout="bottomleft" name="chat_editor" tab_group="3" - width="240"> + width="249"> </line_editor> </layout_panel> </layout_stack> diff --git a/indra/newview/skins/default/xui/en/menu_url_agent.xml b/indra/newview/skins/default/xui/en/menu_url_agent.xml index fa05dac148..73f0fa7979 100644 --- a/indra/newview/skins/default/xui/en/menu_url_agent.xml +++ b/indra/newview/skins/default/xui/en/menu_url_agent.xml @@ -7,7 +7,7 @@ layout="topleft" name="show_agent"> <menu_item_call.on_click - function="Url.Execute" /> + function="Url.ShowProfile" /> </menu_item_call> <menu_item_separator layout="topleft" /> diff --git a/indra/newview/skins/default/xui/en/menu_url_group.xml b/indra/newview/skins/default/xui/en/menu_url_group.xml index c5eaf94d22..2cb125ce09 100644 --- a/indra/newview/skins/default/xui/en/menu_url_group.xml +++ b/indra/newview/skins/default/xui/en/menu_url_group.xml @@ -7,7 +7,7 @@ layout="topleft" name="show_group"> <menu_item_call.on_click - function="Url.Execute" /> + function="Url.ShowProfile" /> </menu_item_call> <menu_item_separator layout="topleft" /> diff --git a/indra/newview/skins/default/xui/en/panel_im_control_panel.xml b/indra/newview/skins/default/xui/en/panel_im_control_panel.xml index 29c6a17c31..33a5e01e4c 100644 --- a/indra/newview/skins/default/xui/en/panel_im_control_panel.xml +++ b/indra/newview/skins/default/xui/en/panel_im_control_panel.xml @@ -3,14 +3,14 @@ border="false" height="300" name="panel_im_control_panel" - width="110"> + width="119"> <avatar_icon follows="left|top" height="105" left_delta="5" name="avatar_icon" top="-5" - width="105"/> + width="114"/> <layout_stack mouse_opaque="false" border_size="0" @@ -22,7 +22,7 @@ name="button_stack" orientation="vertical" top_pad="5" - width="105"> + width="114"> <layout_panel mouse_opaque="false" auto_resize="true" @@ -31,7 +31,7 @@ layout="topleft" left="2" min_height="0" - width="100" + width="109" top="0" name="spacer" user_resize="false" /> @@ -41,7 +41,7 @@ height="20" layout="topleft" min_height="20" - width="100" + width="109" name="view_profile_btn_panel" user_resize="false"> <button @@ -50,7 +50,7 @@ label="Profile" name="view_profile_btn" top="0" - width="100" /> + width="109" /> </layout_panel> <layout_panel auto_resize="false" @@ -58,7 +58,7 @@ height="25" layout="topleft" min_height="25" - width="100" + width="109" name="add_friend_btn_panel" user_resize="false"> <button @@ -67,7 +67,7 @@ label="Add Friend" name="add_friend_btn" top="5" - width="100" /> + width="109" /> </layout_panel> <layout_panel auto_resize="false" @@ -75,7 +75,7 @@ height="25" layout="topleft" min_height="25" - width="100" + width="109" name="teleport_btn_panel" user_resize="false"> <button @@ -85,7 +85,7 @@ label="Teleport" name="teleport_btn" tool_tip = "Offer to teleport this person" - width="100" /> + width="109" /> </layout_panel> <layout_panel auto_resize="false" @@ -93,7 +93,7 @@ height="25" layout="topleft" min_height="25" - width="100" + width="109" name="share_btn_panel" user_resize="false"> <button @@ -102,7 +102,7 @@ height="23" label="Share" name="share_btn" - width="100" /> + width="109" /> </layout_panel> <layout_panel auto_resize="false" @@ -110,7 +110,7 @@ height="25" layout="topleft" min_height="25" - width="100" + width="109" name="pay_btn_panel" user_resize="false"> <button @@ -119,7 +119,7 @@ height="23" label="Pay" name="pay_btn" - width="100" /> + width="109" /> </layout_panel> <layout_panel auto_resize="false" @@ -127,7 +127,7 @@ height="25" layout="topleft" min_height="25" - width="100" + width="109" name="call_btn_panel" user_resize="false"> <button @@ -135,7 +135,7 @@ height="23" label="Call" name="call_btn" - width="100" /> + width="109" /> </layout_panel> <layout_panel auto_resize="false" @@ -143,7 +143,7 @@ height="25" layout="topleft" min_height="25" - width="100" + width="109" name="end_call_btn_panel" user_resize="false" visible="false"> @@ -152,7 +152,7 @@ height="23" label="End Call" name="end_call_btn" - width="100" /> + width="109" /> </layout_panel> <layout_panel auto_resize="false" @@ -160,7 +160,7 @@ height="25" layout="topleft" min_height="25" - width="100" + width="109" name="voice_ctrls_btn_panel" user_resize="false" visible="false"> @@ -169,7 +169,7 @@ height="23" label="Voice Controls" name="voice_ctrls_btn" - width="100" /> + width="109" /> </layout_panel> </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_inventory_item.xml b/indra/newview/skins/default/xui/en/panel_inventory_item.xml new file mode 100644 index 0000000000..f1b7b92ece --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_inventory_item.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + follows="top|right|left" + height="20" + layout="topleft" + left="0" + name="inventory_item" + top="0" + width="380"> + <icon + follows="top|right|left" + height="20" + image_name="ListItem_Over" + layout="topleft" + left="0" + name="hovered_icon" + top="0" + visible="false" + width="380" /> + <icon + height="20" + follows="top|right|left" + image_name="ListItem_Select" + layout="topleft" + left="0" + name="selected_icon" + top="0" + visible="false" + width="380" /> + <icon + height="16" + follows="top|left" + image_name="Inv_Object" + layout="topleft" + left="0" + name="item_icon" + top="0" + width="16" /> + <text + follows="left|right" + height="20" + layout="topleft" + left_pad="5" + allow_html="false" + use_ellipses="true" + name="item_name" + text_color="white" + top="4" + value="..." + width="359" /> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_my_profile.xml b/indra/newview/skins/default/xui/en/panel_my_profile.xml index 5e41d65720..841a4f5713 100644 --- a/indra/newview/skins/default/xui/en/panel_my_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_my_profile.xml @@ -401,14 +401,6 @@ name="edit_profile_btn" tool_tip="Edit your personal information" width="152" /> - <button - follows="bottom|right" - height="23" - label="Edit Appearance" - left_pad="3" - name="edit_appearance_btn" - tool_tip="Create/edit your appearance: physical data, clothes and etc." - width="153" /> </layout_panel> </layout_stack> </panel> 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 c77e4e8d5e..b1f0ff15cb 100644 --- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml +++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml @@ -342,6 +342,30 @@ width="300"/> <panel + name="filtered_wearables_panel" + background_opaque="true" + background_visible="true" + layout="topleft" + follows="left|top|right|bottom" + border="false" + height="155" + left="0" + mouse_opaque="false" + width="300" + top_delta="0" + visible="false"> + <wearable_items_list + name="filtered_wearables_list" + allow_select="true" + layout="topleft" + follows="all" + width="300" + height="155" + left="0" + top="0" /> + </panel> + + <panel background_visible="true" bevel_style="none" follows="left|right|bottom" 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 66ed43efec..b8ad278da7 100644 --- a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml @@ -23,20 +23,16 @@ tab_position="top" halign="center" width="312"> - <inventory_panel + <panel + class="outfits_list" + filename="panel_outfits_list.xml" + height="490" + name="outfitslist_tab" background_visible="true" - background_opaque="true" - label="MY OUTFITS" - help_topic="my_outfits_tab" - allow_multi_select="true" follows="all" - border="false" - left="0" - top="0" - width="315" - mouse_opaque="true" - name="outfitslist_tab" - start_folder="My Outfits" /> + label="MY OUTFITS" + layout="topleft" + width="315" /> <inventory_panel follows="all" background_visible="true" diff --git a/indra/newview/skins/default/xui/en/panel_outfits_list.xml b/indra/newview/skins/default/xui/en/panel_outfits_list.xml new file mode 100644 index 0000000000..5cf94c25d7 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_outfits_list.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + background_visible="true" + bg_alpha_color="DkGray" + border="false" + follows="all" + height="400" + name="Outfits" + layout="topleft" + left="0" + top="0" + width="313"> + <accordion + background_visible="true" + bg_alpha_color="DkGray2" + bg_opaque_color="DkGray2" + follows="all" + height="400" + layout="topleft" + left="3" + name="outfits_accordion" + top="0" + width="307"> + </accordion> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index 61784fede4..fa4213667b 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -30,6 +30,15 @@ name="no_friends" value="No friends" /> <string + name="no_friends_msg"> + Find friends using [secondlife:///app/search/people Search] or right-click on a Resident to add them as a friend. +Looking for people to hang out with? Try the [secondlife:///app/worldmap World Map]. + </string> + <string + name="no_filtered_friends_msg"> + Didn't find what you're looking for? Try [secondlife:///app/search/people Search]. + </string> + <string name="people_filter_label" value="Filter People" /> <string @@ -265,14 +274,11 @@ <text follows="all" height="450" - left="10" - name="no_friends_msg" + left="13" + name="no_friends_help_text" top="10" width="293" - wrap="true"> - Find friends using [secondlife:///app/search/people Search] or right-click on a Resident to add them as a friend. -Looking for people to hang out with? Try the [secondlife:///app/worldmap World Map]. - </text> + wrap="true" /> </panel> <panel background_opaque="true" @@ -293,6 +299,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M Values are set from appropriate strings at the top of file via LLPeoplePanel::postBuild() --> <group_list + allow_select="true" background_visible="true" bg_alpha_color="DkGray2" bg_opaque_color="DkGray2" diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml index a666608103..d7a601d7a3 100644 --- a/indra/newview/skins/default/xui/en/panel_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_profile.xml @@ -389,14 +389,6 @@ name="edit_profile_btn" tool_tip="Edit your personal information" width="130" /> - <button - follows="bottom|right" - height="23" - label="Edit Appearance" - left_pad="10" - name="edit_appearance_btn" - tool_tip="Create/edit your appearance: physical data, clothes and etc." - width="130" /> </layout_panel> </layout_stack> diff --git a/indra/newview/skins/default/xui/en/panel_world_map.xml b/indra/newview/skins/default/xui/en/panel_world_map.xml index 9f08d3a817..16860a6117 100644 --- a/indra/newview/skins/default/xui/en/panel_world_map.xml +++ b/indra/newview/skins/default/xui/en/panel_world_map.xml @@ -45,6 +45,14 @@ name="world_map_northwest"> NW </panel.string> + <panel.string + name="world_map_person"> + 1 person + </panel.string> + <panel.string + name="world_map_people"> + [NUMBER] people + </panel.string> <text type="string" length="1" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 80fddcba43..023aba8d7b 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -1842,7 +1842,7 @@ Clears (deletes) the media and all params from the given face. <string name="LeaveMouselook">Press ESC to return to World View</string> <!-- inventory --> - <string name="InventoryNoMatchingItems">No matching items found in inventory. Try [secondlife:///app/search/groups "Search"].</string> + <string name="InventoryNoMatchingItems">Didn't find what you're looking for? Try [secondlife:///app/search/all Search].</string> <string name="FavoritesNoMatchingItems">Drag a landmark here to add it to your favorites.</string> <string name="InventoryNoTexture">You do not have a copy of this texture in your inventory</string> <!-- use value="" because they have preceding spaces --> @@ -2897,6 +2897,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="LocationCtrlBuildTooltip">Building/dropping objects not allowed</string> <string name="LocationCtrlScriptsTooltip">Scripts not allowed</string> <string name="LocationCtrlDamageTooltip">Health</string> + <string name="LocationCtrlAdultIconTooltip">Adult Region</string> + <string name="LocationCtrlModerateIconTooltip">Moderate Region</string> + <string name="LocationCtrlGeneralIconTooltip">General Region</string> <!-- Strings used by the (currently Linux) auto-updater app --> <string name="UpdaterWindowTitle"> diff --git a/indra/newview/skins/default/xui/en/widgets/location_input.xml b/indra/newview/skins/default/xui/en/widgets/location_input.xml index 1d61447e31..02ea661da3 100644 --- a/indra/newview/skins/default/xui/en/widgets/location_input.xml +++ b/indra/newview/skins/default/xui/en/widgets/location_input.xml @@ -6,6 +6,8 @@ <location_input font="SansSerifSmall" icon_maturity_general="Parcel_PG_Light" icon_maturity_adult="Parcel_R_Light" + icon_maturity_moderate="Parcel_M_Light" + maturity_help_topic="TODO" add_landmark_image_enabled="Favorite_Star_Active" add_landmark_image_disabled="Favorite_Star_Off" add_landmark_image_hover="Favorite_Star_Over" @@ -43,7 +45,7 @@ scale_image="false" top="19" left="-3" /> - <maturity_icon + <maturity_button name="maturity_icon" width="18" height="16" |